From b890e81ab87dd7e4c6d0e7dc4396a3d85d6ad2c8 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 15:47:03 +0200 Subject: [PATCH 01/22] extraneous word --- src/hir-typeck/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hir-typeck/summary.md b/src/hir-typeck/summary.md index 23df97a9cf..b519e8374d 100644 --- a/src/hir-typeck/summary.md +++ b/src/hir-typeck/summary.md @@ -3,7 +3,7 @@ The [`hir_analysis`] crate contains the source for "type collection" as well as a bunch of related functionality. Checking the bodies of functions is implemented in the [`hir_typeck`] crate. -These crates draw heavily on the [type inference] and [trait solving]. +These crates draw heavily on [type inference] and [trait solving]. [`hir_analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/index.html [`hir_typeck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/index.html From 95ded4ac9c29ad5a4ed8545fe7df93e2055b480a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 15:50:10 +0200 Subject: [PATCH 02/22] deserves own sentence --- src/hir-typeck/summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hir-typeck/summary.md b/src/hir-typeck/summary.md index b519e8374d..ae84c1e676 100644 --- a/src/hir-typeck/summary.md +++ b/src/hir-typeck/summary.md @@ -14,8 +14,8 @@ These crates draw heavily on [type inference] and [trait solving]. Type "collection" is the process of converting the types found in the HIR (`hir::Ty`), which represent the syntactic things that the user wrote, into the -**internal representation** used by the compiler (`Ty<'tcx>`) – we also do -similar conversions for where-clauses and other bits of the function signature. +**internal representation** used by the compiler (`Ty<'tcx>`). +Note that we also do similar conversions for where-clauses and other bits of the function signature. To try and get a sense of the difference, consider this function: From b5da32ab5ed674131bf87530460eebe0f247d19e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:47:13 +0200 Subject: [PATCH 03/22] update thir output --- src/thir.md | 191 ++++++++++++++++++++-------------------------------- 1 file changed, 73 insertions(+), 118 deletions(-) diff --git a/src/thir.md b/src/thir.md index 802df22860..1ba30d86a6 100644 --- a/src/thir.md +++ b/src/thir.md @@ -48,7 +48,7 @@ which is useful to keep peak memory in check. Having a THIR representation of all bodies of a crate in memory at the same time would be very heavy. -You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag +You can get a debug representation of the THIR by passing the `-Zunpretty=thir-flat` flag to `rustc`. To demonstrate, let's use the following example: @@ -59,213 +59,168 @@ fn main() { } ``` -Here is how that gets represented in THIR (as of Aug 2022): +Here is how that gets represented in THIR (as of Jul 2026): ```rust,no_run +DefId(0:3 ~ main[26fd]::main): Thir { + body_type: Fn( + fn(), + ), + attributes: {}, // no match arms arms: [], + blocks: [ + Block { + targeted_by_break: false, + region_scope: Node(1), + span: main.rs:1:11: 3:2 (#0), + stmts: [ + s0, + ], + expr: None, + safety_mode: Safe, + }, + ], exprs: [ // expression 0, a literal with a value of 1 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:14 (#0), kind: Literal { lit: Spanned { node: Int( - 1, + Pu128( + 1, + ), Unsuffixed, ), - span: oneplustwo.rs:2:13: 2:14 (#0), + span: main.rs:2:13: 2:14 (#0), }, neg: false, }, + ty: i32, + temp_scope_id: 4, + span: main.rs:2:13: 2:14 (#0), }, // expression 1, scope surrounding literal 1 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:14 (#0), kind: Scope { + region_scope: Node(4), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).4), // reference to expression 0 above - region_scope: Node(3), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 3, - }, - ), value: e0, }, + ty: i32, + temp_scope_id: 4, + span: main.rs:2:13: 2:14 (#0), }, // expression 2, literal 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:17: 2:18 (#0), kind: Literal { lit: Spanned { node: Int( - 2, + Pu128( + 2, + ), Unsuffixed, ), - span: oneplustwo.rs:2:17: 2:18 (#0), + span: main.rs:2:17: 2:18 (#0), }, neg: false, }, + ty: i32, + temp_scope_id: 5, + span: main.rs:2:17: 2:18 (#0), }, // expression 3, scope surrounding literal 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:17: 2:18 (#0), kind: Scope { - region_scope: Node(4), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 4, - }, - ), - // reference to expression 2 above + region_scope: Node(5), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).5), + // reference to expression 0 above value: e2, }, + ty: i32, + temp_scope_id: 5, + span: main.rs:2:17: 2:18 (#0), }, // expression 4, represents 1 + 2 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:18 (#0), kind: Binary { op: Add, // references to scopes surrounding literals above lhs: e1, rhs: e3, }, + ty: i32, + temp_scope_id: 3, + span: main.rs:2:13: 2:18 (#0), }, // expression 5, scope surrounding expression 4 Expr { - ty: i32, - temp_lifetime: Some( - Node(1), - ), - span: oneplustwo.rs:2:13: 2:18 (#0), kind: Scope { - region_scope: Node(5), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 5, - }, - ), + region_scope: Node(3), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).3), value: e4, }, + ty: i32, + temp_scope_id: 3, + span: main.rs:2:13: 2:18 (#0), }, // expression 6, block around statement Expr { - ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), kind: Block { - body: Block { - targeted_by_break: false, - region_scope: Node(8), - opt_destruction_scope: None, - span: oneplustwo.rs:1:11: 3:2 (#0), - // reference to statement 0 below - stmts: [ - s0, - ], - expr: None, - safety_mode: Safe, - }, + block: b0, }, + ty: (), + temp_scope_id: 8, + span: main.rs:1:11: 3:2 (#0), }, // expression 7, scope around block in expression 6 Expr { - ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), kind: Scope { - region_scope: Node(9), - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 9, - }, - ), + region_scope: Node(8), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).8), value: e6, }, - }, - // destruction scope around expression 7 - Expr { ty: (), - temp_lifetime: Some( - Node(9), - ), - span: oneplustwo.rs:1:11: 3:2 (#0), - kind: Scope { - region_scope: Destruction(9), - lint_level: Inherited, - value: e7, - }, + temp_scope_id: 8, + span: main.rs:1:11: 3:2 (#0), }, ], stmts: [ - // let statement Stmt { kind: Let { - remainder_scope: Remainder { block: 8, first_statement_index: 0}, - init_scope: Node(1), + remainder_scope: Remainder { block: 1, first_statement_index: 0}, + init_scope: Node(2), pattern: Pat { ty: i32, - span: oneplustwo.rs:2:9: 2:10 (#0), + span: main.rs:2:9: 2:10 (#0), + extra: None, kind: Binding { - mutability: Not, name: "x", - mode: ByValue, + mode: BindingMode( + No, + Not, + ), var: LocalVarId( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 7, - }, + HirId(DefId(0:3 ~ main[26fd]::main).7), ), ty: i32, subpattern: None, is_primary: true, + is_shorthand: false, }, }, initializer: Some( e5, ), else_block: None, - lint_level: Explicit( - HirId { - owner: DefId(0:3 ~ oneplustwo[6932]::main), - local_id: 6, - }, - ), + hir_id: HirId(DefId(0:3 ~ main[26fd]::main).6), + span: main.rs:2:5: 2:18 (#0), }, - opt_destruction_scope: Some( - Destruction(1), - ), }, ], + params: [], } ``` From f1bda62ad949c658df2e953b362c078fd4641218 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:50:22 +0200 Subject: [PATCH 04/22] sembr src/hir-typeck/summary.md --- src/hir-typeck/summary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hir-typeck/summary.md b/src/hir-typeck/summary.md index ae84c1e676..a64f6c5ada 100644 --- a/src/hir-typeck/summary.md +++ b/src/hir-typeck/summary.md @@ -26,8 +26,9 @@ fn foo(x: Foo, y: self::Foo) { ... } ``` Those two parameters `x` and `y` each have the same type: but they will have -distinct `hir::Ty` nodes. Those nodes will have different spans, and of course -they encode the path somewhat differently. But once they are "collected" into +distinct `hir::Ty` nodes. +Those nodes will have different spans, and of course they encode the path somewhat differently. +But once they are "collected" into `Ty<'tcx>` nodes, they will be represented by the exact same internal type. Collection is defined as a bundle of [queries] for computing information about @@ -35,8 +36,7 @@ the various functions, traits, and other items in the crate being compiled. Note that each of these queries is concerned with *interprocedural* things – for example, for a function definition, collection will figure out the type and signature of the function, but it will not visit the *body* of the function in -any way, nor examine type annotations on local variables (that's the job of -type *checking*). +any way, nor examine type annotations on local variables (that's the job of type *checking*). For more details, see the [`collect`][collect] module. From a8986aaf209da0df70a2d60fba43ee4f92225146 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:51:43 +0200 Subject: [PATCH 05/22] unusual use of colon --- src/hir-typeck/summary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hir-typeck/summary.md b/src/hir-typeck/summary.md index a64f6c5ada..5fd1066369 100644 --- a/src/hir-typeck/summary.md +++ b/src/hir-typeck/summary.md @@ -25,8 +25,8 @@ fn foo(x: Foo, y: self::Foo) { ... } // ^^^ ^^^^^^^^^ ``` -Those two parameters `x` and `y` each have the same type: but they will have -distinct `hir::Ty` nodes. +Those two parameters `x` and `y` each have the same type, +but they will have distinct `hir::Ty` nodes. Those nodes will have different spans, and of course they encode the path somewhat differently. But once they are "collected" into `Ty<'tcx>` nodes, they will be represented by the exact same internal type. From 4cec68770da2e008d1d364549544b706964eb4bf Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 18:52:25 +0200 Subject: [PATCH 06/22] sembr src/debuginfo/intro.md --- src/debuginfo/intro.md | 76 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/debuginfo/intro.md b/src/debuginfo/intro.md index 4fcf4901be..693aa5863f 100644 --- a/src/debuginfo/intro.md +++ b/src/debuginfo/intro.md @@ -1,13 +1,14 @@ # Debug Info Debug info is a collection of information generated by the compiler that allows debuggers to -correctly interpret the state of a program while it is running. That includes things like mapping +correctly interpret the state of a program while it is running. +That includes things like mapping instruction addresses to lines of code in the source file, and type layout information so that bytes in memory can be read and displayed in a meaningful way. Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the -end-user seeing the output of their debugger onscreen. In brief, the stack from beginning to end is -as follows: +end-user seeing the output of their debugger onscreen. +In brief, the stack from beginning to end is as follows: 1. Rustc inspects the MIR and communicates the relevant source, symbol, and type information to LLVM 2. LLVM translates this information into a target-specific debug info format during compilation @@ -33,51 +34,62 @@ API layers (e.g. VSCode extension by way of the # DWARF -The is the primary debug info format for `*-gnu` targets. It is typically bundled in with the -binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). The -DWARF standard is available [here](https://dwarfstd.org/). +The is the primary debug info format for `*-gnu` targets. +It is typically bundled in with the +binary, but it [can be generated as a separate file](https://gcc.gnu.org/wiki/DebugFission). +The DWARF standard is available [here](https://dwarfstd.org/). > NOTE: To inspect DWARF debug info, [gimli](https://crates.io/crates/gimli) can be used > programatically. If you prefer a GUI, the author recommends [DWEX](https://github.com/sevaa/dwex) # PDB/CodeView -The primary debug info format for `*-msvc` targets. PDB is a proprietary container format created by -Microsoft that, unfortunately, +The primary debug info format for `*-msvc` targets. +PDB is a proprietary container format created by Microsoft that, unfortunately, [has multiple meanings](https://docs.rs/ms-pdb/0.1.10/ms_pdb/taster/enum.Flavor.html). -We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. PDB -files are separate from the compiled binary and use the `.pdb` extension. +We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Net applications. +PDB files are separate from the compiled binary and use the `.pdb` extension. -PDB files contain CodeView objects, equivalent to DWARF's tags. CodeView, the debugger that +PDB files contain CodeView objects, equivalent to DWARF's tags. +CodeView, the debugger that consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging, -and was later extended to support Visual C++. There are still minor alterations to the format to +and was later extended to support Visual C++. +There are still minor alterations to the format to support modern architectures and languages, but many of these changes are undocumented and/or sparsely used. -It is important to keep this context in mind when working with CodeView objects. Due to its origins, -the "feature-set" of these objects is very limited, and focused around the core features of C. It -does not have many of the convenience or features of modern DWARF standards. A fair number of +It is important to keep this context in mind when working with CodeView objects. +Due to its origins, +the "feature-set" of these objects is very limited, and focused around the core features of C. +It does not have many of the convenience or features of modern DWARF standards. +A fair number of workarounds exist within the debug info stack to compensate for CodeView's shortcomings. -Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. Many +Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. +Many of the sources were made at vastly different times and contain incomplete or somewhat contradictory -information. As such this page will aim to collect as many sources as possible. +information. +As such this page will aim to collect as many sources as possible. * [TIS PE specification](https://web.archive.org/web/20260315080740/http://x-ways.net/winhex/kb/ff/PE_EXE.pdf) which includes a lengthy section titled "Microsoft Symbol and Type Information", detailing much of -the CodeView format. The document was created in 1993, but the information is still detailed, +the CodeView format. +The document was created in 1993, but the information is still detailed, accurate, and has useful diagrams. * LLVM * [CodeView Overview](https://llvm.org/docs/SourceLevelDebugging.html#codeview-debug-info-format) * [PDB Overview and technical details](https://llvm.org/docs/PDB/index.html) * Microsoft * [microsoft-pdb](https://github.com/microsoft/microsoft-pdb) - A C/C++ implementation of a PDB - reader. The implementation does not contain the full PDB or CodeView specification, but does - contain enough information for other PDB consumers to be written. At time of writing (Nov 2025), + reader. + The implementation does not contain the full PDB or CodeView specification, but does + contain enough information for other PDB consumers to be written. + At time of writing (Nov 2025), this repo has been archived for several years. * [pdb-rs](https://github.com/microsoft/pdb-rs/) - A Rust-based PDB reader and writer based on - other publicly-available information. Does not guarantee stability or spec compliance. Also - contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`) + other publicly-available information. + Does not guarantee stability or spec compliance. + Also contains `pdbtool`, which can dump PDB files (`cargo install pdbtool`) * [Debug Interface Access SDK](https://learn.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk). While it does not document the PDB format directly, details can be gleaned from the interface itself. @@ -86,16 +98,20 @@ accurate, and has useful diagrams. # Debuggers -Rust supports 3 major debuggers: GDB, LLDB, and CDB. Each has its own set of requirements, -limitations, and quirks. This unfortunately creates a large surface area to account for. +Rust supports 3 major debuggers: GDB, LLDB, and CDB. +Each has its own set of requirements, +limitations, and quirks. +This unfortunately creates a large surface area to account for. > NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers >WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In >these docs, it will be referred to as CDB for consistency While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't -completely necessary. Rust currently outputs debug info very similar to that of C++, allowing -debuggers without Rust support to work with a slightly degraded experience. More detail will be +completely necessary. +Rust currently outputs debug info very similar to that of C++, allowing +debuggers without Rust support to work with a slightly degraded experience. +More detail will be included in later sections, but here is a quick reference for the capabilities of each debugger: | Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts | @@ -113,7 +129,9 @@ Below, are several unsupported debuggers that are of particular note due to thei in the future. * [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust, -specifically to debug Rust programs. While promising, it is still in early development. -* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has -a custom debug info format that PDB is translated into. The project also includes a linker that can +specifically to debug Rust programs. +While promising, it is still in early development. +* [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. + It has a custom debug info format that PDB is translated into. +The project also includes a linker that can generate their new debug info format during the linking phase. From ea9b85e32464ae2b62eecf24f6db71040ae008ad Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:05:48 +0200 Subject: [PATCH 07/22] reflow --- src/debuginfo/intro.md | 44 ++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/debuginfo/intro.md b/src/debuginfo/intro.md index 693aa5863f..1fa0f62002 100644 --- a/src/debuginfo/intro.md +++ b/src/debuginfo/intro.md @@ -2,9 +2,8 @@ Debug info is a collection of information generated by the compiler that allows debuggers to correctly interpret the state of a program while it is running. -That includes things like mapping -instruction addresses to lines of code in the source file, and type layout information so that -bytes in memory can be read and displayed in a meaningful way. +That includes things like mapping instruction addresses to lines of code in the source file, +and type layout information so that bytes in memory can be read and displayed in a meaningful way. Debug info can be a slightly overloaded term, covering all the layers between Rust MIR, and the end-user seeing the output of their debugger onscreen. @@ -51,25 +50,23 @@ We are concerned with ordinary PDB files, as Portable PDB is used mainly for .Ne PDB files are separate from the compiled binary and use the `.pdb` extension. PDB files contain CodeView objects, equivalent to DWARF's tags. -CodeView, the debugger that -consumed CodeView objects, was originally released in 1985. Its original intent was for C debugging, +CodeView, the debugger that consumed CodeView objects, was originally released in 1985. +Its original intent was for C debugging, and was later extended to support Visual C++. -There are still minor alterations to the format to -support modern architectures and languages, but many of these changes are undocumented and/or -sparsely used. +There are still minor alterations to the format to support modern architectures and languages, +but many of these changes are undocumented and/or sparsely used. It is important to keep this context in mind when working with CodeView objects. Due to its origins, the "feature-set" of these objects is very limited, and focused around the core features of C. It does not have many of the convenience or features of modern DWARF standards. -A fair number of -workarounds exist within the debug info stack to compensate for CodeView's shortcomings. +A fair number of workarounds exist within the debug info stack +to compensate for CodeView's shortcomings. Due to its proprietary nature, it is very difficult to find information about PDB and CodeView. -Many -of the sources were made at vastly different times and contain incomplete or somewhat contradictory -information. -As such this page will aim to collect as many sources as possible. +Many of the sources were made at vastly different times +and contain incomplete or somewhat contradictory information. +As such, this page will aim to collect as many sources as possible. * [TIS PE specification](https://web.archive.org/web/20260315080740/http://x-ways.net/winhex/kb/ff/PE_EXE.pdf) which includes a lengthy section titled "Microsoft Symbol and Type Information", detailing much of @@ -103,16 +100,17 @@ Each has its own set of requirements, limitations, and quirks. This unfortunately creates a large surface area to account for. -> NOTE: CDB is a proprietary debugger created by Microsoft. The underlying engine also powers ->WinDbg, KD, the Microsoft C/C++ extension for VSCode, and part of the Visual Studio Debugger. In ->these docs, it will be referred to as CDB for consistency +> NOTE: CDB is a proprietary debugger created by Microsoft. +> The underlying engine also powers WinDbg, KD, the Microsoft C/C++ extension for VSCode, +> and part of the Visual Studio Debugger. +> In these docs, it will be referred to as CDB for consistency While GDB and LLDB do offer facilities to natively support Rust's value layout, this isn't completely necessary. Rust currently outputs debug info very similar to that of C++, allowing debuggers without Rust support to work with a slightly degraded experience. -More detail will be -included in later sections, but here is a quick reference for the capabilities of each debugger: +More detail will be included in later sections, +but here is a quick reference for the capabilities of each debugger: | Debugger | Debug Info Format | Native Rust support | Expression Style | Visualizer Scripts | | --- | --- | --- | --- | --- | @@ -129,9 +127,9 @@ Below, are several unsupported debuggers that are of particular note due to thei in the future. * [Bugstalker](https://github.com/godzie44/BugStalker) is an x86-64 Linux debugger written in Rust, -specifically to debug Rust programs. -While promising, it is still in early development. + specifically to debug Rust programs. + While promising, it is still in early development. * [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) is a Windows-only GUI debugger. It has a custom debug info format that PDB is translated into. -The project also includes a linker that can -generate their new debug info format during the linking phase. + The project also includes a linker that can generate their new debug info format + during the linking phase. From 1e068bbc79dc5b8ad796c0534e010fa169ded16c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:09:57 +0200 Subject: [PATCH 08/22] sembr src/debuginfo/rust-codegen.md --- src/debuginfo/rust-codegen.md | 60 +++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/debuginfo/rust-codegen.md b/src/debuginfo/rust-codegen.md index 73fa68d360..869e209b7b 100644 --- a/src/debuginfo/rust-codegen.md +++ b/src/debuginfo/rust-codegen.md @@ -1,8 +1,10 @@ # Rust Codegen The first phase in debug info generation requires Rust to inspect the MIR of the program and -communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though -some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to +communicate it to LLVM. +This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though +some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. +Rust communicates to LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. @@ -13,31 +15,33 @@ LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exist # Type Information Type information typically consists of the type name, size, alignment, as well as things like -fields, generic parameters, and storage modifiers if they are relevant. Much of this work happens in -[rustc_codegen_llvm/src/debuginfo/metadata][di_metadata]. +fields, generic parameters, and storage modifiers if they are relevant. +Much of this work happens in [rustc_codegen_llvm/src/debuginfo/metadata][di_metadata]. [di_metadata]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs It is important to keep in mind that the goal is not necessarily "represent types exactly how they appear in Rust", rather it is to represent them in a way that allows debuggers to most accurately -reconstruct the data during debugging. This distinction is vital to understanding the core work that +reconstruct the data during debugging. +This distinction is vital to understanding the core work that occurs on this layer; many changes made here will be for the purpose of working around debugger limitations when no other option will work. ## Quirks -Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in -some unintuitive and non-idiomatic debug info. +Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. +This can result in some unintuitive and non-idiomatic debug info. ### Pointers and Reference Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. All non-wide pointers, references, and `Box` pointers are output as pointer nodes, and no -distinction is made between `mut` and non-`mut`. Several attempts have been made to rectify this, -but unfortunately there is not a straightforward solution. Using the `reference` DI nodes of the -respective formats has pitfalls. There is a semantic difference between C++ references and Rust -references that is unreconcilable. +distinction is made between `mut` and non-`mut`. +Several attempts have been made to rectify this, +but unfortunately there is not a straightforward solution. +Using the `reference` DI nodes of the respective formats has pitfalls. +There is a semantic difference between C++ references and Rust references that is unreconcilable. >From [cppreference](https://en.cppreference.com/w/cpp/language/reference.html): > @@ -54,16 +58,19 @@ The current proposed solution is to simply [typedef the pointer nodes][issue_144 Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields, -array elements) when stepping through code. A heuristic is used to determine which values are safely -cache-able, and `const` is part of that heuristic. Research has not been done into how this would +array elements) when stepping through code. +A heuristic is used to determine which values are safely +cache-able, and `const` is part of that heuristic. +Research has not been done into how this would interact with things like Rust's interior mutability constructs. ### DWARF vs PDB While most of the type information is fairly straight forward, one notable issue is the debug info -format of the target. Each format has different semantics and limitations, as such they require -slightly different debug info in some cases. This is gated by calls to -[`cpp_like_debuginfo`][cpp_like]. +format of the target. +Each format has different semantics and limitations, as such they require +slightly different debug info in some cases. +This is gated by calls to [`cpp_like_debuginfo`][cpp_like]. [cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 @@ -97,7 +104,8 @@ consecutive `>`'s with a space (`> >`) in type names. [^2]: While these type names are generated as part of the debug info node (which is then wrapped in a typedef node with the Rust name), once the LLVM-IR node is converted to a CodeView node, the type -name information is lost. This is because CodeView has special shorthand nodes for primitive types, +name information is lost. +This is because CodeView has special shorthand nodes for primitive types, and those shorthand nodes to not have a "name" field. ### Generics @@ -106,8 +114,10 @@ Rust outputs generic *type* information (`T` in `ArrayVec`), but no information (`N` in `ArrayVec`). CodeView does not have a leaf node for generics/C++ templates, so all generic information is lost -when generating PDB debug info. There are workarounds that allow the debugger to retrieve the -generic arguments via the type name, but it is fragile solution at best. Efforts are being made to +when generating PDB debug info. +There are workarounds that allow the debugger to retrieve the +generic arguments via the type name, but it is fragile solution at best. +Efforts are being made to contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as a suitable equivalent. @@ -126,9 +136,10 @@ Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums] #### DWARF -DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. It is a container that -references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. The -hierarchy looks as follows: +DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. +It is a container that +references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. +The hierarchy looks as follows: ```txt DW_TAG_structure_type (top-level type for the coroutine) @@ -175,9 +186,10 @@ union enum2$ { ``` An important note is that due to limitations in LLDB, the `DISCR_*` value generated is always a -`u64` even if the value is not `#[repr(u64)]`. This is largely a non-issue for LLDB because the +`u64` even if the value is not `#[repr(u64)]`. +This is largely a non-issue for LLDB because the `DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type. # Source Information -TODO \ No newline at end of file +TODO From 33cc5f3365d526f5c41b4c8d14c162b3ae3162b9 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:20:57 +0200 Subject: [PATCH 09/22] reflow --- src/debuginfo/rust-codegen.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/debuginfo/rust-codegen.md b/src/debuginfo/rust-codegen.md index 869e209b7b..2228007f9b 100644 --- a/src/debuginfo/rust-codegen.md +++ b/src/debuginfo/rust-codegen.md @@ -4,9 +4,8 @@ The first phase in debug info generation requires Rust to inspect the MIR of the communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. -Rust communicates to -LLVM via the `DIBuilder` API - a thin wrapper around LLVM's internals that exists in -[rustc_llvm][rustc_llvm]. +Rust communicates to LLVM via the `DIBuilder` API, +a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. [llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo @@ -117,9 +116,8 @@ CodeView does not have a leaf node for generics/C++ templates, so all generic in when generating PDB debug info. There are workarounds that allow the debugger to retrieve the generic arguments via the type name, but it is fragile solution at best. -Efforts are being made to -contact Microsoft to correct this deficiency, and/or to use one of the unused CodeView node types as -a suitable equivalent. +Efforts are being made to contact Microsoft to correct this deficiency, +and/or to use one of the unused CodeView node types as a suitable equivalent. ### Type aliases @@ -137,8 +135,8 @@ Enum DI nodes are generated in [rustc_codegen_llvm/src/debuginfo/metadata/enums] #### DWARF DWARF has a dedicated node for discriminated unions: `DW_TAG_variant`. -It is a container that -references `DW_TAG_variant_part` nodes that may or may not contain a discriminant value. +It is a container that references `DW_TAG_variant_part` nodes +that may or may not contain a discriminant value. The hierarchy looks as follows: ```txt From 4af7bb8893fd92e91ab1316293cef4b7b8ca79fd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:29:46 +0200 Subject: [PATCH 10/22] lighter markup --- src/debuginfo/rust-codegen.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/debuginfo/rust-codegen.md b/src/debuginfo/rust-codegen.md index 2228007f9b..b68536e43b 100644 --- a/src/debuginfo/rust-codegen.md +++ b/src/debuginfo/rust-codegen.md @@ -5,7 +5,7 @@ communicate it to LLVM. This is primarily done in [`rustc_codegen_llvm/debuginfo`][llvm_di], though some type-name processing exists in [`rustc_codegen_ssa/debuginfo`][ssa_di]. Rust communicates to LLVM via the `DIBuilder` API, -a thin wrapper around LLVM's internals that exists in [rustc_llvm][rustc_llvm]. +a thin wrapper around LLVM's internals that exists in [rustc_llvm]. [llvm_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_llvm/src/debuginfo [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo @@ -51,9 +51,9 @@ There is a semantic difference between C++ references and Rust references that i > >Because references are not objects, **there are no arrays of references, no pointers to references, and no references to references** -The current proposed solution is to simply [typedef the pointer nodes][issue_144394]. +The current proposed solution is to simply [typedef the pointer nodes]. -[issue_144394]: https://github.com/rust-lang/rust/pull/144394 +[typedef the pointer nodes]: https://github.com/rust-lang/rust/pull/144394 Using the `const` qualifier to denote non-`mut` poses potential issues due to LLDB's internal optimizations. In short, LLDB attempts to cache the child-values of variables (e.g. struct fields, @@ -69,9 +69,9 @@ While most of the type information is fairly straight forward, one notable issue format of the target. Each format has different semantics and limitations, as such they require slightly different debug info in some cases. -This is gated by calls to [`cpp_like_debuginfo`][cpp_like]. +This is gated by calls to [`cpp_like_debuginfo`]. -[cpp_like]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 +[`cpp_like_debuginfo`]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs#L813 ### Naming From 6927e17770f7849c2ca6e136a2fd82a12e47d565 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:33:16 +0200 Subject: [PATCH 11/22] use sentence case for titles --- src/SUMMARY.md | 4 ++-- src/debuginfo/intro.md | 2 +- src/debuginfo/rust-codegen.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 91bb143eb3..cc3fece79d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -239,8 +239,8 @@ - [Debugging LLVM](./backend/debugging.md) - [Backend Agnostic Codegen](./backend/backend-agnostic.md) - [Implicit caller location](./backend/implicit-caller-location.md) -- [Debug Info](./debuginfo/intro.md) - - [Rust Codegen](./debuginfo/rust-codegen.md) +- [Debug info](./debuginfo/intro.md) + - [Rust codegen](./debuginfo/rust-codegen.md) - [LLVM Codegen](./debuginfo/llvm-codegen.md) - [Debugger Internals](./debuginfo/debugger-internals.md) - [LLDB Internals](./debuginfo/lldb-internals.md) diff --git a/src/debuginfo/intro.md b/src/debuginfo/intro.md index 1fa0f62002..e8c4d11d12 100644 --- a/src/debuginfo/intro.md +++ b/src/debuginfo/intro.md @@ -1,4 +1,4 @@ -# Debug Info +# Debug info Debug info is a collection of information generated by the compiler that allows debuggers to correctly interpret the state of a program while it is running. diff --git a/src/debuginfo/rust-codegen.md b/src/debuginfo/rust-codegen.md index b68536e43b..fc3b5270a2 100644 --- a/src/debuginfo/rust-codegen.md +++ b/src/debuginfo/rust-codegen.md @@ -1,4 +1,4 @@ -# Rust Codegen +# Rust codegen The first phase in debug info generation requires Rust to inspect the MIR of the program and communicate it to LLVM. @@ -11,7 +11,7 @@ a thin wrapper around LLVM's internals that exists in [rustc_llvm]. [ssa_di]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_codegen_ssa/src/debuginfo [rustc_llvm]: https://github.com/rust-lang/rust/tree/main/compiler/rustc_llvm -# Type Information +# Type information Type information typically consists of the type name, size, alignment, as well as things like fields, generic parameters, and storage modifiers if they are relevant. @@ -31,7 +31,7 @@ limitations when no other option will work. Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in some unintuitive and non-idiomatic debug info. -### Pointers and Reference +### Pointers and reference Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. @@ -188,6 +188,6 @@ An important note is that due to limitations in LLDB, the `DISCR_*` value genera This is largely a non-issue for LLDB because the `DISCR_*` value and the `tag` are read into `uint64_t` values regardless of their type. -# Source Information +# Source information TODO From f8428bf697a59fe922f8c2db505e90ed3a6fe2bf Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:33:41 +0200 Subject: [PATCH 12/22] fix section title --- src/debuginfo/rust-codegen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debuginfo/rust-codegen.md b/src/debuginfo/rust-codegen.md index fc3b5270a2..f879579de9 100644 --- a/src/debuginfo/rust-codegen.md +++ b/src/debuginfo/rust-codegen.md @@ -31,7 +31,7 @@ limitations when no other option will work. Rust's generated DI nodes "pretend" to be C/C++ for both CDB and LLDB's sake. This can result in some unintuitive and non-idiomatic debug info. -### Pointers and reference +### Pointers and references Wide pointers/references/`Box` are treated as a struct with 2 fields: `data_ptr` and `length`. From fc1c7ee0d04b59695f67ed37452a833f4e491a6b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:36:58 +0200 Subject: [PATCH 13/22] it will happen when it does --- src/debuginfo/gdb-internals.md | 2 +- src/debuginfo/gdb-visualizers.md | 2 +- src/debuginfo/llvm-codegen.md | 2 +- src/debuginfo/natvis-visualizers.md | 2 +- src/debuginfo/testing.md | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/debuginfo/gdb-internals.md b/src/debuginfo/gdb-internals.md index 95f543c8e9..619fb86e15 100644 --- a/src/debuginfo/gdb-internals.md +++ b/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ -# (WIP) GDB Internals +# GDB internals GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` \ No newline at end of file diff --git a/src/debuginfo/gdb-visualizers.md b/src/debuginfo/gdb-visualizers.md index 4027ef897f..3f8fb3bf43 100644 --- a/src/debuginfo/gdb-visualizers.md +++ b/src/debuginfo/gdb-visualizers.md @@ -1,4 +1,4 @@ -# (WIP) GDB - Python Providers +# GDB - Python Providers Below are links to relevant parts of the GDB documentation diff --git a/src/debuginfo/llvm-codegen.md b/src/debuginfo/llvm-codegen.md index cc052b6b96..67df1092bd 100644 --- a/src/debuginfo/llvm-codegen.md +++ b/src/debuginfo/llvm-codegen.md @@ -1,4 +1,4 @@ -# (WIP) LLVM Codegen +# LLVM codegen When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a ["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. diff --git a/src/debuginfo/natvis-visualizers.md b/src/debuginfo/natvis-visualizers.md index 653e7d5d65..1b156465f4 100644 --- a/src/debuginfo/natvis-visualizers.md +++ b/src/debuginfo/natvis-visualizers.md @@ -1,3 +1,3 @@ -# (WIP) CDB - Natvis +# CDB - Natvis Official documentation for Natvis can be found [here](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects) and [here](https://code.visualstudio.com/docs/cpp/natvis) diff --git a/src/debuginfo/testing.md b/src/debuginfo/testing.md index f58050875e..7aec83aa97 100644 --- a/src/debuginfo/testing.md +++ b/src/debuginfo/testing.md @@ -1,8 +1,8 @@ -# (WIP) Testing +# Testing The debug info test suite is undergoing a substantial rewrite. This section will be filled out as the rewrite makes progress. Please see [this tracking issue][148483] for more information. -[148483]: https://github.com/rust-lang/rust/issues/148483 \ No newline at end of file +[148483]: https://github.com/rust-lang/rust/issues/148483 From 659b5739314f25134640ed70e7eaa354e1b373b7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:44:50 +0200 Subject: [PATCH 14/22] use sentence case for titles --- src/SUMMARY.md | 12 ++++++------ src/debuginfo/debugger-internals.md | 4 ++-- src/debuginfo/debugger-visualizers.md | 4 ++-- src/debuginfo/gdb-internals.md | 2 +- src/debuginfo/lldb-internals.md | 12 ++++++------ src/debuginfo/lldb-visualizers.md | 4 ++-- src/debuginfo/llvm-codegen.md | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index cc3fece79d..3b6d0a5032 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -241,16 +241,16 @@ - [Implicit caller location](./backend/implicit-caller-location.md) - [Debug info](./debuginfo/intro.md) - [Rust codegen](./debuginfo/rust-codegen.md) - - [LLVM Codegen](./debuginfo/llvm-codegen.md) - - [Debugger Internals](./debuginfo/debugger-internals.md) - - [LLDB Internals](./debuginfo/lldb-internals.md) - - [GDB Internals](./debuginfo/gdb-internals.md) - - [Debugger Visualizers](./debuginfo/debugger-visualizers.md) + - [LLVM codegen](./debuginfo/llvm-codegen.md) + - [Debugger internals](./debuginfo/debugger-internals.md) + - [LLDB internals](./debuginfo/lldb-internals.md) + - [GDB internals](./debuginfo/gdb-internals.md) + - [Debugger visualizers](./debuginfo/debugger-visualizers.md) - [LLDB - Python Providers](./debuginfo/lldb-visualizers.md) - [GDB - Python Providers](./debuginfo/gdb-visualizers.md) - [CDB - Natvis](./debuginfo/natvis-visualizers.md) - [Testing](./debuginfo/testing.md) - - [(Lecture Notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) + - [(Lecture notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) - [Libraries and metadata](./backend/libs-and-metadata.md) - [Profile-guided optimization](./profile-guided-optimization.md) - [LLVM source-based code coverage](./llvm-coverage-instrumentation.md) diff --git a/src/debuginfo/debugger-internals.md b/src/debuginfo/debugger-internals.md index 114ce8a998..4aec0befcf 100644 --- a/src/debuginfo/debugger-internals.md +++ b/src/debuginfo/debugger-internals.md @@ -1,4 +1,4 @@ -# Debugger Internals +# Debugger internals It is the debugger's job to convert the debug info into an in-memory representation. Both the interpretation of the debug info and the in-memory representation are arbitrary; anything will do @@ -11,4 +11,4 @@ interpret and display the data, a way for users to interact with it, and an API Debuggers are vast systems and cannot be covered completely here. This section will provide a brief overview of the subsystems directly relevant to the Rust debugging experience. -Microsoft's debugging engine is closed source, so it will not be covered here. \ No newline at end of file +Microsoft's debugging engine is closed source, so it will not be covered here. diff --git a/src/debuginfo/debugger-visualizers.md b/src/debuginfo/debugger-visualizers.md index 831acbd2f8..e3b82b1d4a 100644 --- a/src/debuginfo/debugger-visualizers.md +++ b/src/debuginfo/debugger-visualizers.md @@ -1,4 +1,4 @@ -# Debugger Visualizers +# Debugger visualizers These are typically the last step before the debugger displays the information, but the results may be piped through a debug adapter such as an IDE's debugger API. @@ -108,4 +108,4 @@ noticable amount. This does require you to name your fields in advance and initi * List comprehensions are typically faster than loops, generator comprehensions are a bit slower than list comprehensions, but use less memory. You can think of comprehensions as equivalent to Rust's `iter.map()`. List comprehensions effectively call `collect::>` at the end, whereas -generator comprehensions do not. \ No newline at end of file +generator comprehensions do not. diff --git a/src/debuginfo/gdb-internals.md b/src/debuginfo/gdb-internals.md index 619fb86e15..8959f5d719 100644 --- a/src/debuginfo/gdb-internals.md +++ b/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ # GDB internals GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support -can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` \ No newline at end of file +can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` diff --git a/src/debuginfo/lldb-internals.md b/src/debuginfo/lldb-internals.md index e104f1d245..8119662b3d 100644 --- a/src/debuginfo/lldb-internals.md +++ b/src/debuginfo/lldb-internals.md @@ -1,4 +1,4 @@ -# LLDB Internals +# LLDB internals LLDB's debug info processing relies on a set of extensible interfaces largely defined in [lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add @@ -19,7 +19,7 @@ Here are some existing implementations of LLDB's plugin API: This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the underlyng lexing, parsing, function calling, etc. should still offer valuable insights. -## Rust Support and TypeSystemClang +## Rust support and TypeSystemClang As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum @@ -63,7 +63,7 @@ from scratch using publicly available information about the PDB format. [dia_discourse]: https://discourse.llvm.org/t/rfc-removing-the-dia-pdb-plugin-from-lldb/87827 [dia_tracking]: https://github.com/llvm/llvm-project/issues/114906 -## Debug Node Parsing +## Debug node parsing The first step is to process the raw debug nodes into something usable. This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a @@ -135,7 +135,7 @@ impl TypeSystem for TypeSystemLang { } ``` -## Type Systems +## Type systems The [`TypeSystem` interface][ts_interface] has 3 major purposes: @@ -172,7 +172,7 @@ alterations as possible. LLDB's synthetics and frontend can handle making the ty piece of information is useless, the Rust compiler should be altered to not output that debug info in the first place. -## Expression Parsing +## Expression parsing The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the @@ -205,4 +205,4 @@ may be a good stepping stone towards full language support in LLDB. ## Visualizers -WIP \ No newline at end of file +WIP diff --git a/src/debuginfo/lldb-visualizers.md b/src/debuginfo/lldb-visualizers.md index 83e2b0d579..58d4bd068f 100644 --- a/src/debuginfo/lldb-visualizers.md +++ b/src/debuginfo/lldb-visualizers.md @@ -330,7 +330,7 @@ of the synthetic. By implementing an instance summary, we can retrieve the variant name via `self.variant.GetTypeName()` and some string manipulation. -# Writing Visualizer Scripts +# Writing visualizer scripts > IMPORTANT: Unlike GDB and CDB, LLDB can debug executables with either DWARF or PDB debug info. >Visualizers must be written to account for both formats whenever possible. See: @@ -373,7 +373,7 @@ use depending on what version of LLDB the script detects. This is vital for backwards compatibility once we begin using recognizer functions, as recognizers were added in lldb 19.0. -## Visualizer Resolution +## Visualizer resolution The order that visualizers resolve in is listed [here][formatters_101]. In short: diff --git a/src/debuginfo/llvm-codegen.md b/src/debuginfo/llvm-codegen.md index 67df1092bd..3b6bd454b2 100644 --- a/src/debuginfo/llvm-codegen.md +++ b/src/debuginfo/llvm-codegen.md @@ -9,4 +9,4 @@ It is important to note that tags within the debug records are **always stored a the target calls for PDB debug info, during codegen the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. -[cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp \ No newline at end of file +[cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From 589d42eb0cf8ed3550213423313fcb5eeadf7dc6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 20 Jul 2026 19:46:38 +0200 Subject: [PATCH 15/22] sembr src/debuginfo/debugger-internals.md --- src/debuginfo/debugger-internals.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/debuginfo/debugger-internals.md b/src/debuginfo/debugger-internals.md index 4aec0befcf..574bb3be6a 100644 --- a/src/debuginfo/debugger-internals.md +++ b/src/debuginfo/debugger-internals.md @@ -1,14 +1,16 @@ # Debugger internals -It is the debugger's job to convert the debug info into an in-memory representation. Both the +It is the debugger's job to convert the debug info into an in-memory representation. +Both the interpretation of the debug info and the in-memory representation are arbitrary; anything will do -so long as meaningful information can be reconstructed while the program is running. The pipeline -from raw debug info to usable types can be quite complicated. +so long as meaningful information can be reconstructed while the program is running. +The pipeline from raw debug info to usable types can be quite complicated. Once the information is in a workable format, the debugger front-end then must provide a way to interpret and display the data, a way for users to interact with it, and an API for extensibility. -Debuggers are vast systems and cannot be covered completely here. This section will provide a brief +Debuggers are vast systems and cannot be covered completely here. +This section will provide a brief overview of the subsystems directly relevant to the Rust debugging experience. Microsoft's debugging engine is closed source, so it will not be covered here. From d63c7e7669ecb44717225e835825385451a93f39 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:38:06 +0200 Subject: [PATCH 16/22] reflow --- src/debuginfo/debugger-internals.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/debuginfo/debugger-internals.md b/src/debuginfo/debugger-internals.md index 574bb3be6a..3da43fe898 100644 --- a/src/debuginfo/debugger-internals.md +++ b/src/debuginfo/debugger-internals.md @@ -1,8 +1,8 @@ # Debugger internals It is the debugger's job to convert the debug info into an in-memory representation. -Both the -interpretation of the debug info and the in-memory representation are arbitrary; anything will do +Both the interpretation of the debug info and the in-memory representation are arbitrary; +anything will do, so long as meaningful information can be reconstructed while the program is running. The pipeline from raw debug info to usable types can be quite complicated. @@ -10,7 +10,7 @@ Once the information is in a workable format, the debugger front-end then must p interpret and display the data, a way for users to interact with it, and an API for extensibility. Debuggers are vast systems and cannot be covered completely here. -This section will provide a brief -overview of the subsystems directly relevant to the Rust debugging experience. +This section will provide a brief overview of the subsystems +directly relevant to the Rust debugging experience. Microsoft's debugging engine is closed source, so it will not be covered here. From c80e8eca215c0b2ab19f9b4399905f80d0d3cefa Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:38:59 +0200 Subject: [PATCH 17/22] sembr src/debuginfo/lldb-internals.md --- src/debuginfo/lldb-internals.md | 119 ++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/src/debuginfo/lldb-internals.md b/src/debuginfo/lldb-internals.md index 8119662b3d..eaa7a02276 100644 --- a/src/debuginfo/lldb-internals.md +++ b/src/debuginfo/lldb-internals.md @@ -1,7 +1,8 @@ # LLDB internals LLDB's debug info processing relies on a set of extensible interfaces largely defined in -[lldb/src/Plugins][lldb_plugins]. These are meant to allow third-party compiler developers to add +[lldb/src/Plugins][lldb_plugins]. +These are meant to allow third-party compiler developers to add language support that is loaded at run-time by LLDB, but at time of writing (Nov 2025) the public API has not been settled on, so plugins exist either in LLDB itself or in standalone forks of LLDB. @@ -16,27 +17,32 @@ Here are some existing implementations of LLDB's plugin API: * [CodeLLDB's former fork with support for Rust](https://archive.softwareheritage.org/browse/origin/directory/?branch=refs/heads/codelldb/16.x&origin_url=https://github.com/vadimcn/llvm-project&path=lldb/source/Plugins/TypeSystem/Rust×tamp=2023-09-11T04:55:10Z) * [A work in progress reimplementation of Rust support](https://github.com/Walnut356/llvm-project/tree/lldbrust/19.x) * [A Rust expression parser plugin](https://github.com/tromey/lldb/tree/a0fc10ce0dacb3038b7302fff9f6cb8cb34b37c6/source/Plugins/ExpressionParser/Rust). -This was written before the `TypeSystem` API was created. Due to the freeform nature of expression parsing, the +This was written before the `TypeSystem` API was created. +Due to the freeform nature of expression parsing, the underlyng lexing, parsing, function calling, etc. should still offer valuable insights. ## Rust support and TypeSystemClang -As mentioned in the debug info overview, LLDB has partial Rust support. To further clarify, Rust +As mentioned in the debug info overview, LLDB has partial Rust support. +To further clarify, Rust uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum -types), which relies directly on the `clang` compiler's representation of types. This imposes heavy -restrictions on how much we can change when LLDB's output doesn't match what we want. Some +types), which relies directly on the `clang` compiler's representation of types. +This imposes heavy +restrictions on how much we can change when LLDB's output doesn't match what we want. +Some workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure C and C++ compilation and debugging work correctly. -LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. This section serves +LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. +This section serves to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light guidance on implementing a `TypeSystemRust` in the future. [ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is -the intention, but it is not a requirement. One can create all the necessary supporting types within -their plugin implementation. +the intention, but it is not a requirement. +One can create all the necessary supporting types within their plugin implementation. > Note: LLDB's documentation, including comments in the source code, is pretty sparse. Trying to > understand how language support works by reading `TypeSystemClang`'s implementation is somewhat @@ -47,8 +53,9 @@ their plugin implementation. ## DWARF vs PDB -LLDB is unique in being able to handle both DWARF and PDB debug information. This does come with -some added complexity. To complicate matters further, PDB support is split between `dia`, which +LLDB is unique in being able to handle both DWARF and PDB debug information. +This does come with some added complexity. +To complicate matters further, PDB support is split between `dia`, which relies on the `msdia140.dll` library distributed with Visual Studio, and `native`, which is written from scratch using publicly available information about the PDB format. @@ -65,48 +72,59 @@ from scratch using publicly available information about the PDB format. ## Debug node parsing -The first step is to process the raw debug nodes into something usable. This primarily occurs in -the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. These classes are fed a +The first step is to process the raw debug nodes into something usable. +This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. +These classes are fed a deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and -[`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no -transformations to the underlying debug info before passing it to the parsers. For both PDB and -DWARF, the debug info is read using LLVM's debug info handlers. +[`SymbolFileNativePDB`][sf_pdb] respectively. +The `SymbolFile` implementers make almost no +transformations to the underlying debug info before passing it to the parsers. +For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. [dwarf_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/DWARF [pdb_ast]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/SymbolFile/NativePDB [sf_dwarf]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h [sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h -The parsers translate the nodes into more convenient formats for LLDB's purposes. For `clang`, these +The parsers translate the nodes into more convenient formats for LLDB's purposes. +For `clang`, these formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang` -uses internally when compiling C and C++. Again, using the compiler's representation of types is not a +uses internally when compiling C and C++. +Again, using the compiler's representation of types is not a requirement, but the plugin system was built with it as a possibility. > Note: The above types will be referred to language-agnostically as `LangType`, `Decl`, and `DeclContext` when the specific implementation details of `TypeSystemClang` are not relevant. -`LangType` represents a type. This includes information such as the name of the type, the size and +`LangType` represents a type. +This includes information such as the name of the type, the size and alignment, its classification (e.g. struct, primitive, pointer), its qualifiers (e.g. `const`, `volatile`), template arguments, function argument and return types, etc. [Here][rust_type] is an example of what a `RustType` might look like. [rust_type]: https://github.com/Walnut356/llvm-project/blob/13bcfd502452606d69faeea76aec3a06db554af9/lldb/source/Plugins/TypeSystem/Rust/TypeSystemRust.h#L618 -`Decl` represents any kind of declaration. It could be a type, a variable, a static field of a +`Decl` represents any kind of declaration. +It could be a type, a variable, a static field of a struct, the value that a static or const is initialized with, etc. -`DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other -`DeclContexts`, though the relationship isn't that straight forward. For example, a function can be +`DeclContext` more or less represents a scope. +`DeclContext`s typically contain `Decl`s and other +`DeclContexts`, though the relationship isn't that straight forward. +For example, a function can be both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions contain variable declarations, nested functions declarations, etc.). -The translation process can be quite verbose, but is usually straightforward. Much of the work here +The translation process can be quite verbose, but is usually straightforward. +Much of the work here is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`. Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`, -`CompilerDecl`, or `CompilerDeclContext`. These wrappers associate the them with the `TypeSystem` -that owns them. Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back -to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. In Rust terms, +`CompilerDecl`, or `CompilerDeclContext`. +These wrappers associate the them with the `TypeSystem` that owns them. +Methods on these objects delegates to the `TypeSystem`, which casts the `void*` back +to the appropriate `LangType*`/`Decl*`/`DeclContext*` and operates on the internals. +In Rust terms, the relationship looks something like this: ```Rust @@ -141,9 +159,11 @@ The [`TypeSystem` interface][ts_interface] has 3 major purposes: [ts_interface]: https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Symbol/TypeSystem.h#L69 -1. Act as the "sole authority" of a language's types. This allows the type system to be added to -LLDB's "pool" of type systems. When an executable is loaded, the target language is determined, and -the pool is queried to find a `TypeSystem` that claims it can handle the language. One can also use +1. Act as the "sole authority" of a language's types. + This allows the type system to be added to LLDB's "pool" of type systems. +When an executable is loaded, the target language is determined, and +the pool is queried to find a `TypeSystem` that claims it can handle the language. +One can also use the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). 2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects @@ -152,41 +172,49 @@ that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers The first two functions are pretty straightforward so we will focus on the third. Many of the functions in the `TypeSystem` interface will look familiar if you have worked with the -visualizer scripts. These functions underpin `SBType` the `SBValue` functions with matching names. +visualizer scripts. +These functions underpin `SBType` the `SBValue` functions with matching names. For example, `TypeSystem::GetFormat` returns the default format for the type if no custom formatter has been applied to it. -Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. The `TypeSystem` versions of -these functions operate on a *type*, not a value like the `SBValue` versions. The values returned +Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. +The `TypeSystem` versions of +these functions operate on a *type*, not a value like the `SBValue` versions. +The values returned from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by -the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB. +the rest of LLDB. +If a field is ommitted, that field effectively no longer exists to LLDB. Additionally, since they do not work with objects, there is no underlying memory to inspect or -interpret. Essentially, this means these functions do not have the same purpose as their equivalent -`SyntheticProvider` functions. There is no way to determine how many elements a `Vec` has or what -address those elements live at. It is also not possible to determine the value of the discriminant -of a sum-type. +interpret. +Essentially, this means these functions do not have the same purpose as their equivalent +`SyntheticProvider` functions. +There is no way to determine how many elements a `Vec` has or what address those elements live at. +It is also not possible to determine the value of the discriminant of a sum-type. Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few -alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. If some +alterations as possible. +LLDB's synthetics and frontend can handle making the type pretty. +If some piece of information is useless, the Rust compiler should be altered to not output that debug info in the first place. ## Expression parsing -The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. It -requires implementing a few extra functions in the `TypeSystem` interface. The bulk of the -expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr]. +The `TypeSystem` is typically written to have a counterpart that can handle expression parsing. +It requires implementing a few extra functions in the `TypeSystem` interface. +The bulk of the expression parsing code should live in [lldb/source/Plugins/ExpressionParser][expr]. [expr]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/ExpressionParser -There isn't too much of note about the parser. It requires implementing a simple interpreter that -can handle (possibly simplified) Rust syntax. They operate on `lldb::ValueObject`s, which are the -objects that underpin `SBValue`. +There isn't too much of note about the parser. +It requires implementing a simple interpreter that can handle (possibly simplified) Rust syntax. +They operate on `lldb::ValueObject`s, which are the objects that underpin `SBValue`. ## Language -The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. They +The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. +They operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing. The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to learn how visualizers should be written. @@ -200,7 +228,8 @@ their python equivalent. While debug node parsing, type systems, and expression parsing are all closely tied to eachother, the `Language` plugin is encapsulated more and thus can be written "standalone" for any language -that an existing type system supports. Due to the lower barrier of entry, a `RustLanguage` plugin +that an existing type system supports. +Due to the lower barrier of entry, a `RustLanguage` plugin may be a good stepping stone towards full language support in LLDB. ## Visualizers From eb7a9849b1f0a770926b4005511b783a73adb37f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:53:35 +0200 Subject: [PATCH 18/22] reflow --- src/debuginfo/lldb-internals.md | 70 ++++++++++++++++----------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/src/debuginfo/lldb-internals.md b/src/debuginfo/lldb-internals.md index eaa7a02276..98eb1da6e7 100644 --- a/src/debuginfo/lldb-internals.md +++ b/src/debuginfo/lldb-internals.md @@ -24,21 +24,21 @@ underlyng lexing, parsing, function calling, etc. should still offer valuable in ## Rust support and TypeSystemClang As mentioned in the debug info overview, LLDB has partial Rust support. -To further clarify, Rust -uses the plugin-pipeline that was built for C/C++ (though it contains some helpers for Rust enum -types), which relies directly on the `clang` compiler's representation of types. -This imposes heavy -restrictions on how much we can change when LLDB's output doesn't match what we want. -Some -workarounds can help, but at the end of the day Rust's needs are secondary compared to making sure +To further clarify, +Rust uses the plugin-pipeline that was built for C/C++ +(though it contains some helpers for Rust enum types), +which relies directly on the `clang` compiler's representation of types. +This imposes heavy restrictions on how much we can change +when LLDB's output doesn't match what we want. +Some workarounds can help, but at the end of the day, +Rust's needs are secondary compared to making sure C and C++ compilation and debugging work correctly. LLDB is receptive to adding a `TypeSystemRust`, but it is a massive undertaking. -This section serves -to not only document how we currently interact with [`TypeSystemClang`][ts_clang], but also as light -guidance on implementing a `TypeSystemRust` in the future. +This section serves to not only document how we currently interact with [`TypeSystemClang`], +but also as light guidance on implementing a `TypeSystemRust` in the future. -[ts_clang]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang +[`TypeSystemClang`]: https://github.com/llvm/llvm-project/tree/main/lldb/source/Plugins/TypeSystem/Clang It is worth noting that a `TypeSystem` directly interacting with the target language's compiler is the intention, but it is not a requirement. @@ -74,9 +74,8 @@ from scratch using publicly available information about the PDB format. The first step is to process the raw debug nodes into something usable. This primarily occurs in the [`DWARFASTParser`][dwarf_ast] and [`PdbAstBuilder`][pdb_ast] classes. -These classes are fed a -deserialized form of the debug info generated from [`SymbolFileDWARF`][sf_dwarf] and -[`SymbolFileNativePDB`][sf_pdb] respectively. +These classes are fed a deserialized form of the debug info +generated from [`SymbolFileDWARF`][sf_dwarf] and [`SymbolFileNativePDB`][sf_pdb] respectively. The `SymbolFile` implementers make almost no transformations to the underlying debug info before passing it to the parsers. For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. @@ -87,9 +86,8 @@ For both PDB and DWARF, the debug info is read using LLVM's debug info handlers. [sf_pdb]: https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h The parsers translate the nodes into more convenient formats for LLDB's purposes. -For `clang`, these -formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, which are the types `clang` -uses internally when compiling C and C++. +For `clang`, these formats are `clang::QualType`, `clang::Decl`, and `clang::DeclContext`, +which are the types `clang` uses internally when compiling C and C++. Again, using the compiler's representation of types is not a requirement, but the plugin system was built with it as a possibility. @@ -111,13 +109,13 @@ struct, the value that a static or const is initialized with, etc. `DeclContext` more or less represents a scope. `DeclContext`s typically contain `Decl`s and other `DeclContexts`, though the relationship isn't that straight forward. -For example, a function can be -both a `Decl` (because function signatures are types), **and** a `DeclContext` (because functions -contain variable declarations, nested functions declarations, etc.). +For example, a function can be both a `Decl` (because function signatures are types), +**and** a `DeclContext` +(because functions contain variable declarations, nested functions declarations, etc.). The translation process can be quite verbose, but is usually straightforward. -Much of the work here -is dependant on the exact information needed to fill out `LangType`, `Decl`, and `DeclContext`. +Much of the work here is dependant on the exact information needed to fill out `LangType`, +`Decl`, and `DeclContext`. Once a node is translated, a pointer to it is type-erased (`void*`) and wrapped in `CompilerType`, `CompilerDecl`, or `CompilerDeclContext`. @@ -161,11 +159,11 @@ The [`TypeSystem` interface][ts_interface] has 3 major purposes: 1. Act as the "sole authority" of a language's types. This allows the type system to be added to LLDB's "pool" of type systems. -When an executable is loaded, the target language is determined, and -the pool is queried to find a `TypeSystem` that claims it can handle the language. -One can also use -the `TypeSystem` to retrieve the backing `SymbolFile`, search for types, and synthesize basic types -that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). + When an executable is loaded, the target language is determined, and + the pool is queried to find a `TypeSystem` that claims it can handle the language. + One can also use the `TypeSystem` to retrieve the backing `SymbolFile`, + search for types, and synthesize basic types + that might not exist in the debug info (e.g. primitives, arrays-of-`T`, pointers-to-`T`). 2. Manage the lifetimes of the `LangType`, `Decl`, and `DeclContext` objects 3. Customize the "defaults" of how those types appear and how they can be interacted with. @@ -178,11 +176,10 @@ For example, `TypeSystem::GetFormat` returns the default format for the type if has been applied to it. Of particular note are `GetIndexOfChildWithName` and `GetNumChildren`. -The `TypeSystem` versions of -these functions operate on a *type*, not a value like the `SBValue` versions. -The values returned -from the `TypeSystem` functions dictate what parts of the struct can be interacted with *at all* by -the rest of LLDB. +The `TypeSystem` versions of these functions operate on a *type*, +not a value like the `SBValue` versions. +The values returned from the `TypeSystem` functions +dictate what parts of the struct can be interacted with *at all* by the rest of LLDB. If a field is ommitted, that field effectively no longer exists to LLDB. Additionally, since they do not work with objects, there is no underlying memory to inspect or @@ -195,9 +192,8 @@ It is also not possible to determine the value of the discriminant of a sum-type Ideally, the `TypeSystem` should expose types as they appear in the debug info with as few alterations as possible. LLDB's synthetics and frontend can handle making the type pretty. -If some -piece of information is useless, the Rust compiler should be altered to not output that debug info -in the first place. +If some piece of information is useless, +the Rust compiler should be altered to not output that debug info in the first place. ## Expression parsing @@ -214,8 +210,8 @@ They operate on `lldb::ValueObject`s, which are the objects that underpin `SBVal ## Language The [`Language` plugins][lang_plugin] are the C++ equivalent to the Python visualizer scripts. -They -operate on `SBValue` objects for the same purpose: creating synthetic children and pretty-printing. +They operate on `SBValue` objects for the same purpose: +creating synthetic children and pretty-printing. The [CPlusPlusLanguage's implementations][cpp_lang] for the LibCxx types are great resources to learn how visualizers should be written. From fbd475789977fc1a07335a02b074a40412af6c60 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 09:54:35 +0200 Subject: [PATCH 19/22] sembr src/debuginfo/debugger-visualizers.md --- src/debuginfo/debugger-visualizers.md | 86 +++++++++++++++++---------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/debuginfo/debugger-visualizers.md b/src/debuginfo/debugger-visualizers.md index e3b82b1d4a..ce4835728d 100644 --- a/src/debuginfo/debugger-visualizers.md +++ b/src/debuginfo/debugger-visualizers.md @@ -3,40 +3,47 @@ These are typically the last step before the debugger displays the information, but the results may be piped through a debug adapter such as an IDE's debugger API. -The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but -to provide an interface for the user to interact with that is as useful as possible. In many cases +The term "Visualizer" is a bit of a misnomer. +The real goal isn't just to prettify the output, but +to provide an interface for the user to interact with that is as useful as possible. +In many cases this means reconstructing the original type as closely as possible to its Rust representation, but not always. The visualizer interface allows generating "synthetic children" - fields that don't exist in the -debug info, but can be derived from invariants about the language and the type itself. A simple +debug info, but can be derived from invariants about the language and the type itself. +A simple example is allowing one to interact with the elements of a `Vec` instead of just it's `*mut u8` heap pointer, length, and capacity. ## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd` -These support scripts are distributed with Rust toolchains. They locate the appropriate debugger and +These support scripts are distributed with Rust toolchains. +They locate the appropriate debugger and the toolchain's visualizer scripts, then launch the debugger with the appropriate arguments to load the visualizer scripts before a debugee is launched/attached to. ## `#![debugger_visualizer]` [This attribute][dbg_vis_attr] allows Rust library authors to include pretty printers for their -types within the library itself. These pretty printers are of the same format as typical -visualizers, but are embedded directly into the compiled binary. These scripts are loaded -automatically by the debugger, allowing a seamless experience for users. This attribute currently -works for GDB and natvis scripts. +types within the library itself. +These pretty printers are of the same format as typical +visualizers, but are embedded directly into the compiled binary. +These scripts are loaded automatically by the debugger, allowing a seamless experience for users. +This attribute currently works for GDB and natvis scripts. [dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute -GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. More information -can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] +GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. +More information +can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). +Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] [gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt], -and have the [highest priority][priority] when a type is resolving which visualizer to use. The -files specified by the attribute are collected into +and have the [highest priority][priority] when a type is resolving which visualizer to use. +The files specified by the attribute are collected into [`CrateInfo::natvis_debugger_visualizers`][natvis] which are then added as linker arguments in [`rustc_codegen_ssa/src/back/linker.rs`][linker_rs] @@ -46,17 +53,22 @@ files specified by the attribute are collected into [linker_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_ssa/src/back/linker.rs#L1106 LLDB is not currently supported, but there are a few methods that could potentially allow support in -the future. Officially, the intended method is via a [formatter bytecode][bytecode]. This was +the future. +Officially, the intended method is via a [formatter bytecode][bytecode]. +This was created to offer a comparable experience to GDB's, but without the safety concerns associated with -embedding an entire python script. The opcodes are limited, but it works with `SBValue` and `SBType` -in roughly the same way as python visualizer scripts. Implementing this would require writing some -sort of DSL/mini compiler. +embedding an entire python script. +The opcodes are limited, but it works with `SBValue` and `SBType` +in roughly the same way as python visualizer scripts. +Implementing this would require writing some sort of DSL/mini compiler. [bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the -binary and embed a python script in it. LLDB will not load it automatically, but the python API does -allow one to access the [raw sections of the debug info][SBSection]. With this, it may be possible +binary and embed a python script in it. +LLDB will not load it automatically, but the python API does +allow one to access the [raw sections of the debug info][SBSection]. +With this, it may be possible to extract the python script from our bespoke section and then load it in during the startup of Rust's visualizer scripts. @@ -65,8 +77,10 @@ Rust's visualizer scripts. ## Performance Before tackling the visualizers themselves, it's important to note that these are part of a -performance-sensitive system. Please excuse the break in formality, but: if I have to spend -significant time debugging, I'm annoyed. If I have to *wait on my debugger*, I'm pissed. +performance-sensitive system. +Please excuse the break in formality, but: if I have to spend +significant time debugging, I'm annoyed. +If I have to *wait on my debugger*, I'm pissed. Every millisecond spent in these visualizers is a millisecond longer for the user to see output. This can be especially painful for large stackframes that contain many/large container types. @@ -75,15 +89,19 @@ delays of tens of seconds (or even minutes) before being able to interact with a frame. There is a tendancy to balk at the idea of optimizing Python code, but it really can have a -substantial impact. Remember, there is no compiler to help keep the code fast. Even simple -transformations are not done for you. It can be difficult to find Python performance tips through +substantial impact. +Remember, there is no compiler to help keep the code fast. +Even simple transformations are not done for you. +It can be difficult to find Python performance tips through all the noise of people suggesting you don't bother optimizing Python, so here are some things to keep in mind that are relevant to these scripts: * Everything allocates, even `int` -* Use tuples when possible. `list` is effectively `Vec>`, whereas tuples are equivalent -to `Box<[Any]>`. They have one less layer of indirection, don't carry extra capacity and can't -grow/shrink which can be advantageous in many cases. An additional benefit is that Python caches and +* Use tuples when possible. + `list` is effectively `Vec>`, whereas tuples are equivalent to `Box<[Any]>`. +They have one less layer of indirection, don't carry extra capacity and can't +grow/shrink which can be advantageous in many cases. +An additional benefit is that Python caches and recycles the underlying allocations of all tuples up to size 20. * Regexes are slow and should be avoided when simple string manipulation will do * Strings are immutable, thus many string operations implictly copy the contents. @@ -91,21 +109,25 @@ recycles the underlying allocations of all tuples up to size 20. way to do it. * f-strings are generally the fastest way to do small, simple string transformations such as surrounding a string with parentheses. -* The act of calling a function is somewhat slow (even if the function is completely empty). If the -code section is very hot, consider inlining the function manually. +* The act of calling a function is somewhat slow (even if the function is completely empty). + If the code section is very hot, consider inlining the function manually. * Local variable access is significantly faster than global and built-in function access * Member/method access via the `.` operator is also slow, consider reassigning deeply nested values to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). * Accessing inherited methods and fields is about 2x slower than base-class methods and fields. Avoid inheritance whenever possible. -* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way +* Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. + `__slots__` is a way to indicate to Python that your class's fields won't change and speeds up field access by a -noticable amount. This does require you to name your fields in advance and initialize them in +noticable amount. +This does require you to name your fields in advance and initialize them in `__init__`, but it's a small price to pay for the benefits. -* Match statements/if..elif..else are not optimized in any way. The conditions are checked in order, +* Match statements/if..elif..else are not optimized in any way. + The conditions are checked in order, 1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values * Compute lazily when possible * List comprehensions are typically faster than loops, generator comprehensions are a bit slower -than list comprehensions, but use less memory. You can think of comprehensions as equivalent to -Rust's `iter.map()`. List comprehensions effectively call `collect::>` at the end, whereas +than list comprehensions, but use less memory. +You can think of comprehensions as equivalent to Rust's `iter.map()`. +List comprehensions effectively call `collect::>` at the end, whereas generator comprehensions do not. From 0b0f7ba6c2faaf84d454605b80235c896111960d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:19:53 +0200 Subject: [PATCH 20/22] reflow --- src/debuginfo/debugger-visualizers.md | 66 +++++++++++++-------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/debuginfo/debugger-visualizers.md b/src/debuginfo/debugger-visualizers.md index ce4835728d..10167bf69c 100644 --- a/src/debuginfo/debugger-visualizers.md +++ b/src/debuginfo/debugger-visualizers.md @@ -6,15 +6,14 @@ be piped through a debug adapter such as an IDE's debugger API. The term "Visualizer" is a bit of a misnomer. The real goal isn't just to prettify the output, but to provide an interface for the user to interact with that is as useful as possible. -In many cases -this means reconstructing the original type as closely as possible to its Rust representation, but -not always. +In many cases, +this means reconstructing the original type as closely as possible to its Rust representation, +but not always. The visualizer interface allows generating "synthetic children" - fields that don't exist in the debug info, but can be derived from invariants about the language and the type itself. -A simple -example is allowing one to interact with the elements of a `Vec` instead of just it's `*mut u8` -heap pointer, length, and capacity. +A simple example is allowing one to interact with the elements of a `Vec` +instead of just it's `*mut u8` heap pointer, length, and capacity. ## `rust-lldb`, `rust-gdb`, and `rust-windbg.cmd` @@ -34,11 +33,10 @@ This attribute currently works for GDB and natvis scripts. [dbg_vis_attr]: https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute -GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary. -More information -can be found [here](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). -Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs] +GDB python scripts are embedded in the `.debug_gdb_scripts` section of the binary ([more info]). +Rustc accomplishes this in [`rustc_codegen_llvm/src/debuginfo/gdb.rs`][gdb_rs]. +[more info]: https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html [gdb_rs]: https://github.com/rust-lang/rust/blob/main/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs Natvis files can be embedded in the PDB debug info using the [`/NATVIS` linker option][linker_opt], @@ -55,22 +53,20 @@ The files specified by the attribute are collected into LLDB is not currently supported, but there are a few methods that could potentially allow support in the future. Officially, the intended method is via a [formatter bytecode][bytecode]. -This was -created to offer a comparable experience to GDB's, but without the safety concerns associated with -embedding an entire python script. +This was created to offer a comparable experience to GDB's, +but without the safety concerns associated with embedding an entire Python script. The opcodes are limited, but it works with `SBValue` and `SBType` -in roughly the same way as python visualizer scripts. +in roughly the same way as Python visualizer scripts. Implementing this would require writing some sort of DSL/mini compiler. [bytecode]: https://lldb.llvm.org/resources/formatterbytecode.html Alternatively, it might be possible to copy GDB's strategy entirely: create a bespoke section in the binary and embed a python script in it. -LLDB will not load it automatically, but the python API does +LLDB will not load it automatically, but the Python API does allow one to access the [raw sections of the debug info][SBSection]. -With this, it may be possible -to extract the python script from our bespoke section and then load it in during the startup of -Rust's visualizer scripts. +With this, it may be possible to extract the Python script from our bespoke section +and then load it in during the startup of Rust's visualizer scripts. [SBSection]: https://lldb.llvm.org/python_api/lldb.SBSection.html#sbsection @@ -99,35 +95,35 @@ keep in mind that are relevant to these scripts: * Everything allocates, even `int` * Use tuples when possible. `list` is effectively `Vec>`, whereas tuples are equivalent to `Box<[Any]>`. -They have one less layer of indirection, don't carry extra capacity and can't -grow/shrink which can be advantageous in many cases. -An additional benefit is that Python caches and -recycles the underlying allocations of all tuples up to size 20. + They have one less layer of indirection, don't carry extra capacity and can't grow/shrink, + which can be advantageous in many cases. + An additional benefit is that Python caches and + recycles the underlying allocations of all tuples up to size 20. * Regexes are slow and should be avoided when simple string manipulation will do * Strings are immutable, thus many string operations implictly copy the contents. * When concatenating large lists of strings, `"".join(iterable_of_strings)` is typically the fastest -way to do it. + way to do it. * f-strings are generally the fastest way to do small, simple string transformations such as surrounding a string with parentheses. * The act of calling a function is somewhat slow (even if the function is completely empty). If the code section is very hot, consider inlining the function manually. * Local variable access is significantly faster than global and built-in function access * Member/method access via the `.` operator is also slow, consider reassigning deeply nested values -to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). + to local variables to avoid this cost (e.g. `h = a.b.c.d.e.f.g.h`). * Accessing inherited methods and fields is about 2x slower than base-class methods and fields. -Avoid inheritance whenever possible. + Avoid inheritance whenever possible. * Use [`__slots__`](https://wiki.python.org/moin/UsingSlots) wherever possible. `__slots__` is a way -to indicate to Python that your class's fields won't change and speeds up field access by a -noticable amount. -This does require you to name your fields in advance and initialize them in -`__init__`, but it's a small price to pay for the benefits. + to indicate to Python that your class's fields won't change and speeds up field access by a + noticable amount. + This does require you to name your fields in advance and initialize them in + `__init__`, but it's a small price to pay for the benefits. * Match statements/if..elif..else are not optimized in any way. - The conditions are checked in order, -1 by 1. If possible, use an alternative such as dictionary dispatch or a table of values + The conditions are checked in order, 1 by 1. + If possible, use an alternative such as dictionary dispatch or a table of values * Compute lazily when possible * List comprehensions are typically faster than loops, generator comprehensions are a bit slower -than list comprehensions, but use less memory. -You can think of comprehensions as equivalent to Rust's `iter.map()`. -List comprehensions effectively call `collect::>` at the end, whereas -generator comprehensions do not. + than list comprehensions, but use less memory. + You can think of comprehensions as equivalent to Rust's `iter.map()`. + List comprehensions effectively call `collect::>` at the end, whereas + generator comprehensions do not. From 086182185263be036d8b748412723e9b47698812 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:20:30 +0200 Subject: [PATCH 21/22] sembr src/debuginfo/gdb-internals.md --- src/debuginfo/gdb-internals.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debuginfo/gdb-internals.md b/src/debuginfo/gdb-internals.md index 8959f5d719..2b80521f45 100644 --- a/src/debuginfo/gdb-internals.md +++ b/src/debuginfo/gdb-internals.md @@ -1,4 +1,4 @@ # GDB internals -GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. The expression parsing support -can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` +GDB's Rust support lives at `gdb/rust-lang.h` and `gdb/rust-lang.c`. +The expression parsing support can be found in `gdb/rust-exp.h` and `gdb/rust-parse.c` From f74f14ab9907cd5b79b3efbc8eedf72fb61259ed Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 23 Jul 2026 10:21:15 +0200 Subject: [PATCH 22/22] sembr src/debuginfo/llvm-codegen.md --- src/debuginfo/llvm-codegen.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/debuginfo/llvm-codegen.md b/src/debuginfo/llvm-codegen.md index 3b6bd454b2..4f5bdaa1e6 100644 --- a/src/debuginfo/llvm-codegen.md +++ b/src/debuginfo/llvm-codegen.md @@ -1,7 +1,8 @@ # LLVM codegen When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a -["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. +["debug record"][dbg_record] that is format-agnostic. +These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records