LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 43860 - COFF Debug info shows variable at the wrong lexical scope.
Summary: COFF Debug info shows variable at the wrong lexical scope.
Status: NEW
Alias: None
Product: libraries
Classification: Unclassified
Component: DebugInfo (show other bugs)
Version: trunk
Hardware: PC All
: P enhancement
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-10-31 07:54 PDT by Carlos Alberto Enciso
Modified: 2019-11-04 02:22 PST (History)
8 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Carlos Alberto Enciso 2019-10-31 07:54:46 PDT
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
Comment 1 Carlos Alberto Enciso 2019-10-31 07:58:44 PDT
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.
Comment 2 Carlos Alberto Enciso 2019-10-31 08:13:18 PDT
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.
Comment 3 Carlos Alberto Enciso 2019-10-31 08:18:10 PDT
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.
Comment 4 Carlos Alberto Enciso 2019-10-31 08:25:56 PDT
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]
Comment 5 Reid Kleckner 2019-11-01 12:03:14 PDT
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.
Comment 6 Carlos Alberto Enciso 2019-11-04 02:02:29 PST
(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.
Comment 7 Carlos Alberto Enciso 2019-11-04 02:03:35 PST
(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.
Comment 8 Carlos Alberto Enciso 2019-11-04 02:22:30 PST
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?