https://issues.dlang.org/show_bug.cgi?id=20460
Mathias LANG <[email protected]> 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 <[email protected]> --- 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) ``` --
