Given the following test case: //------------------------------------------------------------ // inlined.cpp //------------------------------------------------------------ int inlineFunction(int Param) __attribute__((always_inline)); int inlineFunction(int Param) { int Var_1 = Param; { int Var_2 = Param + Var_1; Var_1 = Var_2; } return Var_1; } int testInlined(int Param_1, int Param_2) { int A = Param_1; A += inlineFunction(Param_2); return A; } //------------------------------------------------------------ Using the following command line options to generate debug info (DWARF) and (COFF): clang -c -g -O0 inlined.cpp -o inlined-dwarf.o clang -c -g -O0 inlined.cpp -o inlined-coff.o -gcodeview --target=x86_64-windows Looking at the output generated by llvm-dwarfdump and llvm-readobj, the COFF debug info shows the variable 'Var_2' at the same lexical scope as the variable 'Var_1' in the 'testInlined' as results of the function 'inlineFunction' being inlined. llvm-dwarfdump --debug-info inlined-dwarf.o
This is the reduced output generated by llvm-dwarfdump: ----------------------------------------------------------------- inlined-dwarf.o: file format ELF64-x86-64 .debug_info contents: DW_TAG_compile_unit DW_TAG_subprogram DW_TAG_formal_parameter DW_AT_abstract_origin (0x00000074 "Param") DW_TAG_variable DW_AT_abstract_origin (0x0000007f "Var_1") DW_TAG_lexical_block DW_TAG_variable DW_AT_abstract_origin (0x0000008b "Var_2") DW_TAG_subprogram DW_AT_name ("InlineFunction") DW_TAG_formal_parameter DW_AT_name ("Param") DW_TAG_variable DW_AT_name ("Var_1") DW_TAG_lexical_block DW_TAG_variable DW_AT_name ("Var_2") DW_TAG_subprogram DW_AT_name ("testInlined") DW_TAG_formal_parameter DW_AT_name ("Param_1") DW_TAG_formal_parameter DW_AT_name ("Param_2") DW_TAG_variable DW_AT_name ("A") DW_TAG_inlined_subroutine DW_TAG_formal_parameter DW_AT_abstract_origin (0x00000074 "Param") DW_TAG_variable DW_AT_abstract_origin (0x0000007f "Var_1") <------ (*) DW_TAG_lexical_block DW_TAG_variable DW_AT_abstract_origin (0x0000008b "Var_2") <------ (*) ----------------------------------------------------------------- (*) Var_1 and Var_2 are at different lexical scopes.
This is the reduced output generated by llvm-readobj: outline copy (inlineFunction) ----------------------------------------------------------------- Subsection [ ... GlobalProcIdSym { Kind: S_GPROC32_ID (0x1147) ... DisplayName: inlineFunction LinkageName: ?inlineFunction@@YAHH@Z } FrameProcSym { Kind: S_FRAMEPROC (0x1012) ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Param } DefRangeFramePointerRelSym { ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Var_1 <-- Var_1 (*) } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } BlockSym { Kind: S_BLOCK32 (0x1103) <-- Lexical scope ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Var_2 <-- Var_2(*) } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } ScopeEndSym { Kind: S_END (0x6) <-- End lexical scope } ProcEnd { Kind: S_PROC_ID_END (0x114F) } ] (*) Var_1 and Var_2 at different lexical scopes.
This is the reduced output generated by llvm-readobj: caller (testInlined) ----------------------------------------------------------------- Subsection [ ... GlobalProcIdSym { Kind: S_GPROC32_ID (0x1147) ... DisplayName: testInlined LinkageName: ?testInlined@@YAHHH@Z } FrameProcSym { Kind: S_FRAMEPROC (0x1012) ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Param_1 } DefRangeFramePointerRelSym { ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Param_2 } DefRangeFramePointerRelSym { ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: A } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } InlineSiteSym { Kind: S_INLINESITE (0x114D) <-- Lexical scope for inlined function ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Param } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Var_1 <-- Var_1 (*) } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } LocalSym { Kind: S_LOCAL (0x113E) ... VarName: Var_2 <-- Var_2 (*) } DefRangeFramePointerRelSym { Kind: S_DEFRANGE_FRAMEPOINTER_REL (0x1142) ... } InlineSiteEnd { Kind: S_INLINESITE_END (0x114E) <-- End lexical scope inlined function } ProcEnd { Kind: S_PROC_ID_END (0x114F) } ] ] (*) Var_1 and Var_2 at the same lexical scope.
This is the ouput from llvm-diva (tool under development). llvm-diva --print=scopes,symbols,types inlined-dwarf.o inlined-coff.o --attribute=level,format Logical View: [000] {File} 'inlined-dwarf.o' -> ELF64-x86-64 [001] {CompileUnit} 'inlined.cpp' [002] 2 {Function} inlined 'inlineFunction' -> 'int' [003] {Block} [004] 5 {Variable} 'Var_2' -> 'int' [003] 2 {Parameter} 'Param' -> 'int' [003] 3 {Variable} 'Var_1' -> 'int' [002] 2 {Function} extern inlined 'inlineFunction' -> 'int' [003] {Block} [004] 5 {Variable} 'Var_2' -> 'int' [003] 2 {Parameter} 'Param' -> 'int' [003] 3 {Variable} 'Var_1' -> 'int' [002] 11 {Function} extern not_inlined 'testInlined' -> 'int' [003] 13 {InlinedFunction} inlined 'inlineFunction' -> 'int' [004] {Block} [005] 5 {Variable} 'Var_2' -> 'int' <-- Var_2 (*) [004] 2 {Parameter} 'Param' -> 'int' [004] 3 {Variable} 'Var_1' -> 'int' <-- Var_1 (*) [003] 11 {Parameter} 'Param_1' -> 'int' [003] 11 {Parameter} 'Param_2' -> 'int' [003] 12 {Variable} 'A' -> 'int' Logical View: [000] {File} 'inlined-coff.o' -> COFF-x86-64 [001] {CompileUnit} 'inlined.cpp' [002] {Function} not_inlined 'inlineFunction' -> 'int' [003] {Block} [004] {Variable} 'Var_2' -> 'int' [003] {Parameter} 'Param' -> 'int' [003] {Variable} 'Var_1' -> 'int' [002] {Function} not_inlined 'testInlined' -> 'int' [003] {Variable} 'A' -> 'int' [003] {Parameter} 'Param_1' -> 'int' [003] {Parameter} 'Param_2' -> 'int' [003] {InlinedFunction} inlined 'inlineFunction' -> 'int' [004] {Parameter} 'Param' -> 'int' [004] {Variable} 'Var_1' -> 'int' <-- (**) Var_1 [004] {Variable} 'Var_2' -> 'int' <-- (**) Var_2 The logical view for the DWARF debug info, shows 'Var_1' and 'Var_2' at different lexical scopes: (*) Var_1, scope [004] (*) Var_2, scope [005] The logical view for the COFF debug-info, shows 'Var_1' and 'Var_2' at the same lexical scopes. (**) Var_1, scope [004] (**) Var_2, scope [004]
Would it be correct to say that the bug is: lexical scopes disappear from codeview after inlining? There are some conditions under which lexical scopes may be ignored: https://github.com/llvm/llvm-project/blob/master/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp#L2754 Perhaps this example hits one of those cases.
(In reply to Reid Kleckner from comment #5) > There are some conditions under which lexical scopes may be ignored: > https://github.com/llvm/llvm-project/blob/master/llvm/lib/CodeGen/AsmPrinter/ > CodeViewDebug.cpp#L2754 Thanks very much for the link. For the given case, https://github.com/llvm/llvm-project/blob/master/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp#L2769 const DILexicalBlock *DILB = dyn_cast<DILexicalBlock>(Scope.getScopeNode()); DILB is null. From my understanding, the lexical blocks created due to the inlining are not treated as standard ones and they have been ignored.
(In reply to Reid Kleckner from comment #5) > Would it be correct to say that the bug is: lexical scopes disappear from > codeview after inlining? Yes. That would be a better description for the bug.
I am just starting to get familiar with the CodeView format and the main question I have now is: Why the lexical scopes created during inlining are treated in a different way as in DWARF?