Stream: git-wasmtime

Topic: wasmtime / issue #3403 Failed to generate native debug in...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 01 2021 at 14:25):

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 the wasmtime 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.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 08 2021 at 15:31):

alexcrichton commented on issue #3403:

Fixed in https://github.com/bytecodealliance/wasmtime/pull/3498

view this post on Zulip Wasmtime GitHub notifications bot (Nov 08 2021 at 15:31):

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 the wasmtime 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