Skip to content

Missing debug information about type definitions in PDB #98678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
artemmukhin opened this issue Jun 29, 2022 · 4 comments · Fixed by #104342
Closed

Missing debug information about type definitions in PDB #98678

artemmukhin opened this issue Jun 29, 2022 · 4 comments · Fixed by #104342
Assignees
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug. O-windows-msvc Toolchain: MSVC, Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@artemmukhin
Copy link
Contributor

artemmukhin commented Jun 29, 2022

It seems like rustc does not generate enough information about types in PDB debug information. Particularly, the PDB IPI Stream contains invalid LF_UDT_MOD_SRC_LINE entries without source file information. Due to this issue, from the debugger's perspective, it is impossible to check whether a certain type corresponds to Rust source code or not. This affects both user-defined and stdlib types.

Steps to reproduce

  1. Create a simple Rust program with a structure definition rusttest::MyType located in main.rs
  2. Dump PDB data using llvm-pdbutil.exe dump -all main.pdb > main.pdb.txt command
  3. Look at rusttest::MyType information in the TPI Stream and IPI Stream sections

It may look as follows:

                     Types (TPI Stream)                     
============================================================
  0x107A | LF_STRUCTURE [size = 76, hash = 0x2C45E] `rusttest::MyType`
           unique name: `36f9e7b2e2f4a0c8d5bebaa1feba526d`
           vtable: <no type>, base list: <no type>, field list: 0x1079
           options: has unique name, sizeof 8

                     Types (IPI Stream)                     
============================================================
   0x1051 | LF_UDT_MOD_SRC_LINE [size = 20, hash = 0x1C61]
            udt = 0x107A, mod = 4, file = 1, line = 0

                        String Table                        
============================================================
     ID | String
      1 | '\<unknown>'

Note, in the corresponding entry of IPI Stream (udt = 0x107A) we have file = 1, which refers to an unknown file.

In comparison, this is an example of correct information generated by cl.exe when compiling a similar C++ program:

                     Types (TPI Stream)                     
============================================================
   0x5760 | LF_STRUCTURE [size = 44, hash = 0x1D1EA] `MyType`
            unique name: `.?AUMyType@@`
            vtable: <no type>, base list: <no type>, field list: 0x575F
            options: has unique name, sizeof 4

                     Types (IPI Stream)                     
============================================================
   0x287E | LF_UDT_MOD_SRC_LINE [size = 18, hash = 0x5B53]
            udt = 0x5760, mod = 1, file = 19765, line = 3

                        String Table                        
============================================================
   19765 | 'C:\path\to\main.cpp'
@artemmukhin artemmukhin added the C-bug Category: This is a bug. label Jun 29, 2022
@wesleywiser wesleywiser added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) O-windows-msvc Toolchain: MSVC, Operating system: Windows labels Jun 30, 2022
@wesleywiser
Copy link
Member

Interesting! It looks like we generate a LF_UDT_SRC_LINE (godbolt example) but the line number and source file are both wrong. That happens in LLVM.

The PDB source implies that this record is converted into a LF_UDT_MOD_SRC_LINE by the linker so the problem has something to do with DIType not having the correct file & line information when addUDTSrcLine is called.

@mweber15
Copy link
Contributor

mweber15 commented Nov 8, 2022

Is it possible that this simply isn't implemented? I looked at the Godbolt example and specifically looked at the LLVM IR that gets emitted to build the debug info. It seems like any information that gets created through this stub function will lack file information. I thought maybe the intent of the stub was to create a metadata instance that would be updated later, but I didn't find anything that looked like it was updating file information after the fact.

// foo.rs

pub struct MyType {
    x: u32,
}

pub fn main(_: MyType) {}
$ rustc --emit llvm-ir --target x86_64-pc-windows-msvc --crate-type rlib -C debuginfo=2 foo.rs
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...

I hacked around a little bit and it seems like one possibility would be to allow for passing the file information into the stub function. I'm not sure if there is enough information inside the stub function to derive file information for any caller. I'm aping the lookup code that is used to add location information for global variables here.

The gist of what I did was:

--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -980,6 +986,15 @@ fn build_struct_type_di_node<'ll, 'tcx>(
     let struct_type_and_layout = cx.layout_of(struct_type);
     let variant_def = adt_def.non_enum_variant();

+    let tcx = cx.tcx;
+    let struct_span = tcx.def_span(adt_def.did());
+    let (file_metadata, line_number) = if !struct_span.is_dummy() {
+        let loc = cx.lookup_debug_loc(struct_span.lo());
+        (file_metadata(cx, &loc.file), loc.line)
+    } else {
+        (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
+    };
+
     type_map::build_type_with_children(
         cx,
         type_map::stub(
@@ -987,6 +1002,8 @@ fn build_struct_type_di_node<'ll, 'tcx>(
             Stub::Struct,
             unique_type_id,
             &compute_debuginfo_type_name(cx.tcx, struct_type, false),
+            file_metadata,
+            line_number,
             size_and_align_of(struct_type_and_layout),
             Some(containing_scope),
             DIFlags::FlagZero,

Which results in:

; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...

@wesleywiser
Copy link
Member

@mweber15 Nice find! That patch seems reasonable to me at a glance so if you want to open a PR with that change, I'd be happy to review it 🙂

@mweber15
Copy link
Contributor

mweber15 commented Nov 9, 2022

@wesleywiser Thanks! I will put together a PR to see if this still seems like the right approach in the context of the broader changes. I think there are about 18 call sites for stub, so it's probably worth looking at them in some detail to see if other debug info is lacking potentially useful file information.

@rustbot claim

bors pushed a commit to rust-lang-ci/rust that referenced this issue Jan 27, 2023
This change attaches file information (`DIFile` reference and line
number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678
@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
mweber15 added a commit to mweber15/rust that referenced this issue Mar 2, 2024
This change attaches file information (`DIFile` reference and line
number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678
bors added a commit to rust-lang-ci/rust that referenced this issue Mar 15, 2024
…ypes, r=wesleywiser

Require `type_map::stub` callers to supply file information

This change attaches file information (`DIFile` reference and line number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678

r? `@wesleywiser`
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 30, 2024
…ypes, r=<try>

Require `type_map::stub` callers to supply file information

This change attaches file information (`DIFile` reference and line number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678

r? `@wesleywiser`
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 2, 2024
…ypes, r=wesleywiser

Require `type_map::stub` callers to supply file information

This change attaches file information (`DIFile` reference and line number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678

r? `@wesleywiser`
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 3, 2024
…ypes, r=wesleywiser

Require `type_map::stub` callers to supply file information

This change attaches file information (`DIFile` reference and line number) to struct debug info nodes.

Before:

```
; foo.ll
...
!5 = !DIFile(filename: "<unknown>", directory: "")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !5, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "4cb373851db92e732c4cb5651b886dd0")
...
```

After:

```
; foo.ll
...
!3 = !DIFile(filename: "foo.rs", directory: "/home/matt/src/rust98678", checksumkind: CSK_SHA1, checksum: "bcb9f08512c8f3b8181ef4726012bc6807bc9be4")
...
!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "MyType", scope: !2, file: !3, line: 3, size: 32, align: 32, elements: !17, templateParams: !19, identifier: "9e5968c7af39c148acb253912b7f409f")
...
```

Fixes rust-lang#98678

r? `@wesleywiser`
@bors bors closed this as completed in 2f00b6a Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) C-bug Category: This is a bug. O-windows-msvc Toolchain: MSVC, Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants