potentially incorrect DWARF location list

Hi,

I’ve encountered a situation where Clang generates an incorrect location list for the variable. GDB chokes on it, but LLDB understands it.

DWARF standard doesn’t say that this location list is legal. Is it a bug in Clang that got compensated by LLDB? Or is it done on purpose?

Here is more information.

Consider the following test:

—main.cpp—

#include “stuff.h”

int main()

{

int c = 0;

for (int a = 0; a < 100; ++a)

c += func(a);

return c;

}

— stuff.h—

extern int func(int a);

—stuff.cpp—

#include “stuff.h”

int func(int a)

{

return a * 15;

}

The following DWARF is generated for variables “a” and “c”:

<2><43>: Abbrev Number: 3 (DW_TAG_variable)

<44> DW_AT_location : 0x0 (location list)

<48> DW_AT_name : (indirect string, offset: 0x73): c

<4c> DW_AT_decl_file : 1

<4d> DW_AT_decl_line : 5

<4e> DW_AT_type : <0x70>

<2><52>: Abbrev Number: 4 (DW_TAG_lexical_block)

<53> DW_AT_low_pc : 0x12

<5b> DW_AT_high_pc : 0x10

<3><5f>: Abbrev Number: 3 (DW_TAG_variable)

<60> DW_AT_location : 0x39 (location list)

<64> DW_AT_name : (indirect string, offset: 0x75): a

<68> DW_AT_decl_file : 1

<69> DW_AT_decl_line : 7

<6a> DW_AT_type : <0x70>

Content of the .debug_loc section:

Offset Begin End Expression

00000000 0000000000000003 0000000000000026 (DW_OP_consts: 13)

00000014 0000000000000026 0000000000000029 (DW_OP_reg0 (rax); DW_OP_piece: 4)

00000029

00000039 0000000000000008 000000000000001d (DW_OP_consts: 0)

0000004d 000000000000001d 0000000000000022 (DW_OP_reg3 (rbx); DW_OP_piece: 4)

00000062

DWARF expressions"DW_OP_consts 13" and “DW_OP_consts 0” are legal, but are they legal as locations? I’ve checked DWARF-3, DWAWF-4 and DWARF-5

and it seems that the proper way to describe the situation where in a specific address range the value is constant is “DW_OP_constu 0, DW_OP_stack_value”.

DW_OP_const pushes a value on to the expression stack, this describes a location, not a value. In order for the stack to represent a value the expression needs to end with DW_OP_stack_value.

GDB thinks that “DW_OP_consts 0” represents a location in memory:

Breakpoint 1, main () at main.cpp:8

8 c += func(a);

(gdb) p c

Cannot access memory at address 0xd

(gdb) p a

Cannot access memory at address 0x0

(gdb)

LLDB seems to know how to interpret DW_OP_consts correctly.

(lldb) run

Process 8216 launching

  • thread #1: tid = 8216, 0x0000000000400502 main.O2.exe`main + 18 at main.cpp:8, name =

‘main.O2.exe’, stop reason = breakpoint 1.1

frame #0: 0x0000000000400502 main.O2.exe`main + 18 at main.cpp:8

5 int c = 13;

6

7 for (int a = 0; a < 100; ++a)

→ 8 c += func(a);

9

10 return c;

11 }

(lldb) p c

(int) $0 = 13

(lldb) p a

(int) $1 = 0

Is this implemented in Clang on purpose for some reason? Or is it a bug in Clang that gets compensated by the debugger?

Thanks!

Katya.

Hi,

Hi,

I've encountered a situation where Clang generates an incorrect location list for the variable. GDB chokes on it, but LLDB understands it.
DWARF standard doesn't say that this location list is legal. Is it a bug in Clang that got compensated by LLDB? Or is it done on purpose?

Here is more information.

Consider the following test:

---main.cpp---

#include "stuff.h"

int main()
{
                int c = 0;

                for (int a = 0; a < 100; ++a)
                                c += func(a);

                return c;
}

--- stuff.h---

extern int func(int a);

---stuff.cpp---

#include "stuff.h"

int func(int a)
{
        return a * 15;
}

The following DWARF is generated for variables "a" and "c":
<2><43>: Abbrev Number: 3 (DW_TAG_variable)
    <44> DW_AT_location : 0x0 (location list)
    <48> DW_AT_name : (indirect string, offset: 0x73): c
    <4c> DW_AT_decl_file : 1
    <4d> DW_AT_decl_line : 5
    <4e> DW_AT_type : <0x70>
<2><52>: Abbrev Number: 4 (DW_TAG_lexical_block)
    <53> DW_AT_low_pc : 0x12
    <5b> DW_AT_high_pc : 0x10
<3><5f>: Abbrev Number: 3 (DW_TAG_variable)
    <60> DW_AT_location : 0x39 (location list)
    <64> DW_AT_name : (indirect string, offset: 0x75): a
    <68> DW_AT_decl_file : 1
    <69> DW_AT_decl_line : 7
    <6a> DW_AT_type : <0x70>

Content of the .debug_loc section:

    Offset Begin End Expression
    00000000 0000000000000003 0000000000000026 (DW_OP_consts: 13)
    00000014 0000000000000026 0000000000000029 (DW_OP_reg0 (rax); DW_OP_piece: 4)
    00000029 <End of list>
    00000039 0000000000000008 000000000000001d (DW_OP_consts: 0)
    0000004d 000000000000001d 0000000000000022 (DW_OP_reg3 (rbx); DW_OP_piece: 4)
    00000062 <End of list>

DWARF expressions"DW_OP_consts 13" and "DW_OP_consts 0" are legal, but are they legal as locations? I've checked DWARF-3, DWAWF-4 and DWARF-5
and it seems that the proper way to describe the situation where in a specific address range the value is constant is "DW_OP_constu 0, DW_OP_stack_value”.

I agree with this interpretation. IIRC, the OP_stack_value didn’t exist before the DWARF4 standard. Expressing this situation simply was impossible without this operation and I am quite sure that producers and consumers started to rely on heuristics to disambiguate the value vs. location status of the expression. GDB might have moved away from that by now. We’d need to fix lldb to DTRT also.

Fred

Thank you, Frédéric.

I will file a bug against the compiler and work on it. I will also file a corresponding bug against the debugger.

Katya.

Thank you, Frédéric.

I will file a bug against the compiler and work on it. I will also file a corresponding bug against the debugger.

(I too agree with the analysis)

Sounds good. Patches for this will almost assuredly be to llvm-commits FWIW.

-eric