[Issue 20460] [OSX] DMD writes the same address everywhere in DWARF debug infos

d-bugmail at puremagic.com d-bugmail at puremagic.com
Tue Jan 19 18:59:45 UTC 2021


https://issues.dlang.org/show_bug.cgi?id=20460

Mathias LANG <pro.mathias.lang at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|pull                        |backend, industry
            Summary|[OSX] Stack traces          |[OSX] DMD writes the same
                   |involving extern(C++) can   |address everywhere in DWARF
                   |show wrong file / line      |debug infos

--- Comment #4 from Mathias LANG <pro.mathias.lang at gmail.com> ---
Did some more investigation on this. Turns out the issue is that DMD writes
complete nonsense in the debug infos!

Take the following example, in C:
```C
#include <stdio.h>

void callB ()
{
    printf("Hello World\n");
}

int main (void)
{
    callB();
    return 0;
}
```

Compiled with `gcc -g -c ca.c`.
Using `dwarfdump` on it gives a pretty standard output:
```
ca.o:   file format Mach-O 64-bit x86-64

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000064 version = 0x0004 abbr_offset =
0x0000 addr_size = 0x08 (next unit at 0x00000068)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("Apple clang version 12.0.0
(clang-1200.0.32.28)")
              DW_AT_language    (DW_LANG_C99)
              DW_AT_name        ("ca.c")
              DW_AT_LLVM_sysroot       
("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
              DW_AT_APPLE_sdk   ("MacOSX.sdk")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/Users/geod24/projects/dlang/druntime")
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x000000000000003c)

0x00000032:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000014)
                DW_AT_frame_base        (DW_OP_reg6 RBP)
                DW_AT_name      ("callB")
                DW_AT_decl_file ("/Users/geod24/projects/dlang/druntime/ca.c")
                DW_AT_decl_line (3)
                DW_AT_external  (true)

0x00000047:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000000020)
                DW_AT_high_pc   (0x000000000000003c)
                DW_AT_frame_base        (DW_OP_reg6 RBP)
                DW_AT_name      ("main")
                DW_AT_decl_file ("/Users/geod24/projects/dlang/druntime/ca.c")
                DW_AT_decl_line (8)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x00000060 "int")
                DW_AT_external  (true)

0x00000060:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x00000067:   NULL
```

We can see that the DW_TAG_compile_unit contain a DW_AT_low_pc which is the
DW_AT_low_pc of callB, and a DW_AT_high_pc which is that of main. In other
words, the two functions are stored contiguously in the binary.

We can verify this using `nm`:
```
0000000000000000 T _callB
0000000000000020 T _main <== Value is DW_AT_low_pc, as expected
                 U _printf
```

Now what does DMD produce for equivalent code:
```D
import core.stdc.stdio;

void callB ()
{
    printf("Hello World\n");
}

int main ()
{
    callB();
    return 0;
}
```

Compiled with `dmd -g -c ca.d`, using v2.095.0, and using dwarfdump:
```
ca.o:   file format Mach-O 64-bit x86-64

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000135 version = 0x0003 abbr_offset =
0x0000 addr_size = 0x08 (next unit at 0x00000139)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("Digital Mars D v2.095.0\n")
              DW_AT_language    (DW_LANG_D)
              DW_AT_name        ("ca.d")
              DW_AT_comp_dir    ("/Users/geod24/projects/dlang/druntime")
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_entry_pc    (0x0000000000000000)
              DW_AT_ranges      (0x00000000
                 [0x0000000000000500, 0x0000000000000500))
              DW_AT_stmt_list   (0x00000000)

0x00000069:   DW_TAG_module
                DW_AT_name      ("ca")

0x0000006d:   DW_TAG_subprogram
                DW_AT_name      ("ca.callB")
                DW_AT_MIPS_linkage_name ("_D2ca5callBFZv")
                DW_AT_decl_file ("/Users/geod24/projects/dlang/druntime/ca.d")
                DW_AT_decl_line (3)
                DW_AT_low_pc    (0x0000000000000500)
                DW_AT_high_pc   (0x0000000000000500)
                DW_AT_frame_base        (0x00000000:
                   [0x0000000000000500, 0x0000000000000500): DW_OP_breg7 RSP+8
                   [0x0000000000000500, 0x0000000000000500): DW_OP_breg7 RSP+16
                   [0x0000000000000500, 0x0000000000000500): DW_OP_breg6
RBP+16)

0x0000009d:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_byte_size (0x04)
                DW_AT_encoding  (DW_ATE_signed)

0x000000a4:   DW_TAG_subprogram
                DW_AT_name      ("D main")
                DW_AT_MIPS_linkage_name ("_Dmain")
                DW_AT_decl_file ("/Users/geod24/projects/dlang/druntime/ca.d")
                DW_AT_decl_line (8)
                DW_AT_type      (0x0000009d "int")
                DW_AT_external  (0x01)
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000000)
                DW_AT_frame_base        (0x0000004c: )

0x000000cf:   DW_TAG_base_type
                DW_AT_name      ("char")
                DW_AT_byte_size (0x01)
                DW_AT_encoding  (DW_ATE_unsigned_char)

0x000000d7:   DW_TAG_pointer_type
                DW_AT_type      (0x000000cf "char")

0x000000dc:   DW_TAG_pointer_type
                DW_AT_type      (0x000000d7 "char*")

0x000000e1:   DW_TAG_subprogram
                DW_AT_sibling   (0x00000138)
                DW_AT_name      ("ca._d_cmain!().main")
                DW_AT_MIPS_linkage_name ("main")
                DW_AT_decl_file
("/usr/local/opt/dmd/include/dlang/dmd/core/internal/entrypoint.d")
                DW_AT_decl_line (27)
                DW_AT_type      (0x0000009d "int")
                DW_AT_external  (0x01)
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000000)
                DW_AT_frame_base        (0x00000098: )

0x0000011b:     DW_TAG_formal_parameter
                  DW_AT_name    ("argc")
                  DW_AT_type    (0x0000009d "int")
                  DW_AT_artificial      (0x00)
                  DW_AT_location        (DW_OP_fbreg -32)

0x00000129:     DW_TAG_formal_parameter
                  DW_AT_name    ("argv")
                  DW_AT_type    (0x000000dc "char**")
                  DW_AT_artificial      (0x00)
                  DW_AT_location        (DW_OP_fbreg -24)

0x00000137:     NULL

0x00000138:   NULL
```

And here we have complete nonsense in terms of address. Either we get 0 - 0, or
0x0000000000000500 - 0x0000000000000500. Neither of those is correct.
Using `nm` on the binary outputs:
```
0000000000000060 s EH_frame0
00000000000000a0 S _D main.eh
0000000000000050 S __D2ca12__ModuleInfoZ
0000000000000500 S __D2ca5callBFZv
0000000000000000 T __Dmain
                 U __Dmain
                 U __d_run_main
00000000000000c8 S _ca._d_cmain!().main.eh
0000000000000078 S _ca.callB.eh
                 U _main
0000000000000010 T _main
                 U _printf
```

Here we can see that 0x0000000000000500 is the start address of callB, and so
the DW_AT_low_pc for "D main" and "callB" are the only two things correct with
this.
I took a look at the backend, and somehow it seems that all relocations end up
with the same addresses.

For reference, LDC's output here is much saner, and as expected:
```
.debug_info contents:
0x00000000: Compile Unit: length = 0x000000d4 version = 0x0004 abbr_offset =
0x0000 addr_size = 0x08 (next unit at 0x000000d8)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("LDC 1.24.0 (LLVM 9.0.1)")
              DW_AT_language    (DW_LANG_D)
              DW_AT_name        ("ca.d")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/Users/geod24/projects/dlang/druntime")
              DW_AT_APPLE_major_runtime_vers    (0x01)
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x000000000000005b)

0x0000002b:   DW_TAG_module
                DW_AT_name      ("ca")

0x00000030:     DW_TAG_imported_module
                  DW_AT_import  (0x000000ad)

0x00000035:     DW_TAG_imported_module
                  DW_AT_decl_file      
("/Users/geod24/projects/dlang/druntime/ca.d")
                  DW_AT_decl_line       (1)
                  DW_AT_import  (0x000000b2)

0x0000003c:     DW_TAG_subprogram
                  DW_AT_low_pc  (0x0000000000000000)
                  DW_AT_high_pc (0x0000000000000014)
                  DW_AT_frame_base      (DW_OP_reg6 RBP)
                  DW_AT_linkage_name    ("_D2ca5callBFZv")
                  DW_AT_name    ("callB")
                  DW_AT_decl_file      
("/Users/geod24/projects/dlang/druntime/ca.d")
                  DW_AT_decl_line       (3)
                  DW_AT_external        (true)

0x00000055:     DW_TAG_subprogram
                  DW_AT_low_pc  (0x0000000000000020)
                  DW_AT_high_pc (0x000000000000002d)
                  DW_AT_frame_base      (DW_OP_reg6 RBP)
                  DW_AT_linkage_name    ("_Dmain")
                  DW_AT_name    ("D main")
                  DW_AT_decl_file      
("/Users/geod24/projects/dlang/druntime/ca.d")
                  DW_AT_decl_line       (8)
                  DW_AT_type    (0x000000b7 "int")
                  DW_AT_external        (true)

0x00000072:     DW_TAG_subprogram
                  DW_AT_low_pc  (0x0000000000000030)
                  DW_AT_high_pc (0x000000000000005b)
                  DW_AT_frame_base      (DW_OP_reg6 RBP)
                  DW_AT_linkage_name    ("main")
                  DW_AT_name    ("main")
                  DW_AT_decl_file      
("/usr/local/Cellar/ldc/1.24.0/include/dlang/ldc/core/internal/entrypoint.d")
                  DW_AT_decl_line       (39)
                  DW_AT_type    (0x000000b7 "int")
                  DW_AT_external        (true)
```

--


More information about the Digitalmars-d-bugs mailing list