alexcrichton edited issue #3403:
I've been attempting to debug some C code recently but unfortunately I keep running into an error that indicates "failed to emit DWARF debug information" when passing the
-g
flag to thewasmtime
CLI. The reproduction of this is:// foo.c __attribute__((export_name("foo"))) int foo() { return 3; } int bar(int a) { int b[50]; b[0] = a; b[29] = a; return a; }
$ clang -O3 foo.c -o foo.wasm -mexec-model=reactor -g $ wasmtime -g ./foo.wasm Error: failed to run main module `./foo.wasm` Caused by: 0: failed to emit DWARF debug information 1: The end offset of a location list entry must not be before the beginning.
Inspecting the results of
llvm-dwarfdump
I see:<details>
foo.wasm: file format WASM .debug_info contents: 0x00000000: Compile Unit: length = 0x00000093, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x00000097) 0x0000000b: DW_TAG_compile_unit DW_AT_producer ("clang version 12.0.0 (https://github.com/llvm/llvm-project d28af7c654d8db0b68c175db5ce212d74fb5e9bc)") DW_AT_language (DW_LANG_C99) DW_AT_name ("foo.c") DW_AT_stmt_list (0x00000000) DW_AT_comp_dir ("/home/acrichto/code/wasmtime") DW_AT_low_pc (0x00000000) DW_AT_ranges (0x00000000 [0x0000000e, 0x00000012)) 0x00000026: DW_TAG_subprogram DW_AT_low_pc (0x0000000e) DW_AT_high_pc (0x00000012) DW_AT_frame_base (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value) DW_AT_GNU_all_call_sites (true) DW_AT_name ("foo") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (2) DW_AT_type (0x0000007c "int") DW_AT_external (true) 0x00000041: DW_TAG_subprogram DW_AT_low_pc (dead code) DW_AT_high_pc (0x00000004) DW_AT_frame_base (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value) DW_AT_GNU_all_call_sites (true) DW_AT_name ("bar") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (4) DW_AT_prototyped (true) DW_AT_type (0x0000007c "int") DW_AT_external (true) 0x0000005c: DW_TAG_formal_parameter DW_AT_location (DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value) DW_AT_name ("a") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (4) DW_AT_type (0x0000007c "int") 0x0000006c: DW_TAG_variable DW_AT_location (0x00000000: [0xfffffffe, 0x100000002): DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_piece 0x70, DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4) DW_AT_name ("b") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (5) DW_AT_type (0x00000083 "int[50]") 0x0000007b: NULL 0x0000007c: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x00000083: DW_TAG_array_type DW_AT_type (0x0000007c "int") 0x00000088: DW_TAG_subrange_type DW_AT_type (0x0000008f "__ARRAY_SIZE_TYPE__") DW_AT_count (0x32) 0x0000008e: NULL 0x0000008f: DW_TAG_base_type DW_AT_name ("__ARRAY_SIZE_TYPE__") DW_AT_byte_size (0x08) DW_AT_encoding (DW_ATE_unsigned) 0x00000096: NULL
</details>
With some digging the issue appears to be this:
0x0000006c: DW_TAG_variable DW_AT_location (0x00000000: [0xfffffffe, 0x100000002): DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_piece 0x70, DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4)
where gimli is doing addition in the 32-bit address space for ranges which means that from gimli's perspective the start address of this variable is 0xfffffffe and the end address is 0x2, hence the error from gimli itself.
This appears to come about with DWARF debug information for dead code in a program. It appears that LLD specifically uses the value of -2 for representing relocations against dead functions that don't actually show up in the output. The
DW_AT_location
attribute here I believe is encoded as a offset/length which means that the offset receives the relocation of -2 and when gimli adds the length it gets the error that the range is messed up.I believe the real fix here is to basically avoid generating native DWARF debugging information for dead code, or code that comes at the address of -1.
llvm-dwarfdump
already itself prints:0x00000041: DW_TAG_subprogram DW_AT_low_pc (dead code)
and for something like that we should probably just skip over that and not copy over any other attributes related to this subprogram (function). I unfortunately don't know the dwarf code well enough in Wasmtime to know of a great place to put this.
alexcrichton commented on issue #3403:
Fixed in https://github.com/bytecodealliance/wasmtime/pull/3498
alexcrichton closed issue #3403:
I've been attempting to debug some C code recently but unfortunately I keep running into an error that indicates "failed to emit DWARF debug information" when passing the
-g
flag to thewasmtime
CLI. The reproduction of this is:// foo.c __attribute__((export_name("foo"))) int foo() { return 3; } int bar(int a) { int b[50]; b[0] = a; b[29] = a; return a; }
$ clang -O3 foo.c -o foo.wasm -mexec-model=reactor -g $ wasmtime -g ./foo.wasm Error: failed to run main module `./foo.wasm` Caused by: 0: failed to emit DWARF debug information 1: The end offset of a location list entry must not be before the beginning.
Inspecting the results of
llvm-dwarfdump
I see:<details>
foo.wasm: file format WASM .debug_info contents: 0x00000000: Compile Unit: length = 0x00000093, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x00000097) 0x0000000b: DW_TAG_compile_unit DW_AT_producer ("clang version 12.0.0 (https://github.com/llvm/llvm-project d28af7c654d8db0b68c175db5ce212d74fb5e9bc)") DW_AT_language (DW_LANG_C99) DW_AT_name ("foo.c") DW_AT_stmt_list (0x00000000) DW_AT_comp_dir ("/home/acrichto/code/wasmtime") DW_AT_low_pc (0x00000000) DW_AT_ranges (0x00000000 [0x0000000e, 0x00000012)) 0x00000026: DW_TAG_subprogram DW_AT_low_pc (0x0000000e) DW_AT_high_pc (0x00000012) DW_AT_frame_base (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value) DW_AT_GNU_all_call_sites (true) DW_AT_name ("foo") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (2) DW_AT_type (0x0000007c "int") DW_AT_external (true) 0x00000041: DW_TAG_subprogram DW_AT_low_pc (dead code) DW_AT_high_pc (0x00000004) DW_AT_frame_base (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value) DW_AT_GNU_all_call_sites (true) DW_AT_name ("bar") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (4) DW_AT_prototyped (true) DW_AT_type (0x0000007c "int") DW_AT_external (true) 0x0000005c: DW_TAG_formal_parameter DW_AT_location (DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value) DW_AT_name ("a") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (4) DW_AT_type (0x0000007c "int") 0x0000006c: DW_TAG_variable DW_AT_location (0x00000000: [0xfffffffe, 0x100000002): DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_piece 0x70, DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4) DW_AT_name ("b") DW_AT_decl_file ("/home/acrichto/code/wasmtime/foo.c") DW_AT_decl_line (5) DW_AT_type (0x00000083 "int[50]") 0x0000007b: NULL 0x0000007c: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x00000083: DW_TAG_array_type DW_AT_type (0x0000007c "int") 0x00000088: DW_TAG_subrange_type DW_AT_type (0x0000008f "__ARRAY_SIZE_TYPE__") DW_AT_count (0x32) 0x0000008e: NULL 0x0000008f: DW_TAG_base_type DW_AT_name ("__ARRAY_SIZE_TYPE__") DW_AT_byte_size (0x08) DW_AT_encoding (DW_ATE_unsigned) 0x00000096: NULL
</details>
With some digging the issue appears to be this:
0x0000006c: DW_TAG_variable DW_AT_location (0x00000000: [0xfffffffe, 0x100000002): DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_piece 0x70, DW_OP_WASM_location 0x0 0x0, DW_OP_stack_value, DW_OP_piece 0x4)
where gimli is doing addition in the 32-bit address space for ranges which means that from gimli's perspective the start address of this variable is 0xfffffffe and the end address is 0x2, hence the error from gimli itself.
This appears to come about with DWARF debug information for dead code in a program. It appears that LLD specifically uses the value of -2 for representing relocations against dead functions that don't actually show up in the output. The
DW_AT_location
attribute here I believe is encoded as a offset/length which means that the offset receives the relocation of -2 and when gimli adds the length it gets the error that the range is messed up.I believe the real fix here is to basically avoid generating native DWARF debugging information for dead code, or code that comes at the address of -1.
llvm-dwarfdump
already itself prints:0x00000041: DW_TAG_subprogram DW_AT_low_pc (dead code)
and for something like that we should probably just skip over that and not copy over any other attributes related to this subprogram (function). I unfortunately don't know the dwarf code well enough in Wasmtime to know of a great place to put this.
Last updated: Nov 22 2024 at 16:03 UTC