llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.96k stars 11.94k forks source link

COFF Debug info missing nested enumeration. #43250

Open CarlosAlbertoEnciso opened 5 years ago

CarlosAlbertoEnciso commented 5 years ago
Bugzilla Link 43905
Version trunk
OS All
CC @dwblaikie,@gregbedwell,@JDevlieghere,@jmorse,@walkerkd,@pogo59,@rnk

Extended Description

Given the following test case:

//------------------------------------------------------------ // enum.cpp //------------------------------------------------------------

struct STRUCT_a { enum ENUM_a { One = '1', Two = '2' }; ENUM_a Enum_a; }; void testEnum_1() { STRUCT_a Struct; }

//------------------------------------------------------------

Using the following command line options to generate debug info (DWARF) and (COFF):

clang -c -g -O0 enum.cpp -o enum-dwarf.o clang -c -g -O0 enum.cpp -o enum-coff.o -gcodeview --target=x86_64-windows

Looking at the output generated by llvm-dwarfdump, llvm-readobj and llvm-diva, the COFF debug info shows the nested 'ENUM_a' in the 'STRUCT_a' scope.

llvm-dwarfdump --debug-info enum-dwarf.o llvm-readobj --codeview enum-coff.o

amykhuang commented 4 years ago

Reproduced it and apparently it crashes because of my heapallocsite change.

rnk commented 4 years ago

Amy, do you mind looking into this?

You can start by re-applying my change locally and then reproducing the crash that Hans ran into. The reproducer should be in https://crbug.com/1022729.

rnk commented 4 years ago

No, it was not resubmitted, it's been on my TODO list to get back to it.

gregbedwell commented 4 years ago

It seems that your fix was reverted:

https://reviews.llvm.org/rGff3b513495c04d87799b3c5a98ddcdb6996af4f3

Re-opening due to Comment 10.

@​rnk: Do you remember whether this got resubmitted? (a quick search of the commit log suggests not, but I may have missed it).

CarlosAlbertoEnciso commented 4 years ago

https://github.com/llvm/llvm-project/commit/ d91ed80e97ac9bfcfb02440874ed8b9a51c9491e Thanks for the report!

It seems that your fix was reverted:

https://reviews.llvm.org/rGff3b513495c04d87799b3c5a98ddcdb6996af4f3

rnk commented 5 years ago

https://github.com/llvm/llvm-project/commit/d91ed80e97ac9bfcfb02440874ed8b9a51c9491e Thanks for the report!

CarlosAlbertoEnciso commented 5 years ago

I'd recommend using llvm-pdbutil dump -types over llvm-readobj -codeview in the future. The output is more readable.

Thanks for your recommendation to use llvm-pdbutil dump -types.

rnk commented 5 years ago

I'd recommend using llvm-pdbutil dump -types over llvm-readobj -codeview in the future. The output is more readable.

Here are two related test cases:

struct Outer { enum Inner { One = '1', Two = '2' }; }; void testEnum_2() { Outer::Inner val; }


struct Outer { struct Inner { int x; }; }; void testNested() { Outer::Inner val; }

For both examples, Outer is emitted when producing DWARF, but not when producing codeview.

This happens even with -fstandalone-debug, which is clearly a bug. If we wanted to avoid emitting these with -flimit-debug, that's reasonable, but if the frontend makes them complete, the backend should emit them.

gregbedwell commented 5 years ago

For reference, llvm-diva is a local tool at Sony that we hope to contribute to the upstream LLVM project in coming months, in case anyone is confused by the references here.

CarlosAlbertoEnciso commented 5 years ago

A simplified output from llvm-dwarfdump, showing the definitions for 'STRUCT_a', 'STRUCT_b' and 'ENUM_a'

DW_TAG_structure_type DW_AT_name ("STRUCT_a") <-- STRUCT_a DW_AT_decl_line (1) ... DW_TAG_enumeration_type ... DW_AT_name ("ENUM_a") <-- ENUM_a DW_AT_decl_line (2) ... ... DW_TAG_structure_type DW_AT_name ("STRUCT_b") <-- STRUCT_b DW_AT_decl_line (4) ... DW_TAG_member DW_AT_name ("Enum_a") DW_AT_type (0x00000033 "ENUM_a") DW_AT_decl_line (5)

CarlosAlbertoEnciso commented 5 years ago

A simplified output from llvm-readobj, showing the references to 'STRUCT_a' and 'ENUM_a'.

Enum (0x1005) { TypeLeafKind: LF_ENUM (0x1507) NumEnumerators: 2 Properties [ (0x208) HasUniqueName (0x200) Nested (0x8) <-- Is nested ] UnderlyingType: int (0x74) FieldListType: (0x1004) Name: STRUCT_a::ENUM_a <-- 'STRUCT_a' its parent. LinkageName: .?AW4ENUM_a@STRUCT_a@@ } ... UdtSourceLine (0x1007) { TypeLeafKind: LF_UDT_SRC_LINE (0x1606) <-- Source line information. UDT: STRUCT_a::ENUM_a (0x1005) SourceFile: /data/projects/tests/bugzillas/enum.cpp (0x1006) LineNumber: 2 } ... FieldList (0x1008) { TypeLeafKind: LF_FIELDLIST (0x1203) DataMember { TypeLeafKind: LF_MEMBER (0x150D) AccessSpecifier: Public (0x3) Type: STRUCT_a::ENUM_a (0x1005) <-- Member type, 'STRUCT_a::ENUM_a' FieldOffset: 0x0 Name: Enum_a <-- Structure Member 'Enum_a' } }

CarlosAlbertoEnciso commented 5 years ago

Using llvm-diva with the following command:

llvm-diva --print=scopes,symbols --attribute=level,format,base --sort=name enum-dwarf.o enum-coff.o

The output for both object files looks like:

Logical View: [000] {File} 'enum-dwarf.o' -> ELF64-x86-64

[001] {CompileUnit} 'enum.cpp' [002] 1 {Struct} 'STRUCT_a' [003] 2 {Enumeration} 'ENUM_a' -> 'unsigned int' [002] 4 {Struct} 'STRUCT_b' [003] 5 {Member} public 'Enum_a' -> 'ENUM_a' [002] 7 {Function} extern not_inlined 'testEnum_2' -> '' [003] 8 {Variable} 'Struct' -> 'STRUCT_b'

Logical View: [000] {File} 'enum-coff.o' -> COFF-x86-64

[001] {CompileUnit} 'enum.cpp' [002] 4 {Struct} 'STRUCT_b' [003] {Member} public 'Enum_a' -> 'ENUM_a' [002] {Function} not_inlined 'testEnum_2' -> 'void' [003] {Variable} 'Struct' -> 'STRUCT_b'

The DWARF format shows at: Line-1, level-2, the definition for 'STRUCT_a' Line-2, level-3, the definition for 'ENUM_a' Line-4, level-2, the definition for 'STRUCT_b'

The COFF format shows at: Line-4, level-2, the definition for 'STRUCT_b'

CarlosAlbertoEnciso commented 5 years ago

But changing the test case to:

//------------------------------------------------------------ // enum.cpp //------------------------------------------------------------

struct STRUCT_a { enum ENUM_a { One = '1', Two = '2' }; }; struct STRUCT_b { STRUCT_a::ENUM_a Enum_a; }; void testEnum_2() { STRUCT_b Struct; }

//------------------------------------------------------------

The COFF debug information does not include any definition for 'STRUCT_a', despite 'ENUM_a' being referenced in 'STRUCT_b'.

CarlosAlbertoEnciso commented 5 years ago

Using llvm-diva with the following command:

llvm-diva --print=scopes,symbols,types --attribute=level,format,base --sort=name enum-dwarf.o enum-coff.o

The output for both object files looks like:

Logical View: [000] {File} 'enum-dwarf.o' -> ELF64-x86-64

[001] {CompileUnit} 'enum.cpp' [002] 1 {Struct} 'STRUCT_a' [003] 2 {Enumeration} 'ENUM_a' -> 'unsigned int' [004] {Enumerator} 'One' = '0x00000031' [004] {Enumerator} 'Two' = '0x00000032' [003] 3 {Member} public 'Enum_a' -> 'ENUM_a' [002] 5 {Function} extern not_inlined 'testEnum_1' -> '' [003] 6 {Variable} 'Struct' -> 'STRUCT_a' [002] {BaseType} 'unsigned int'

Logical View: [000] {File} 'enum-coff.o' -> COFF-x86-64

[001] {CompileUnit} 'enum.cpp' [002] {TypeAlias} 'STRUCT_a' -> 'STRUCT_a' [002] 1 {Struct} 'STRUCT_a' [003] 2 {Enumeration} 'ENUM_a' -> 'int' [004] {Enumerator} 'One' = '0x31' [004] {Enumerator} 'Two' = '0x32' [003] {Member} public 'Enum_a' -> 'ENUM_a' [002] {BaseType} 'int' [002] {Function} not_inlined 'testEnum_1' -> 'void' [003] {Variable} 'Struct' -> 'STRUCT_a' [002] {BaseType} 'void'

line-2, level-3 shows 'ENUM_a', which is correct.

CarlosAlbertoEnciso commented 5 years ago

assigned to @amykhuang