DWARF errors: `Trying to add a local variable at positive storage offset`
"Trying to add a local variable at positive storage offset" in customer reported binary from slack. Uploaded internally as tiptoe bet addicted property
Another user's binary https://github.com/user-attachments/files/16773531/libbar-x86_64.zip
This is difficult to handle properly for binaries that change function frame base offsets in a function (aka functions that don't use CFA frame base).
For example:
.debug_info:
0x00000c8e: DW_TAG_subprogram
DW_AT_low_pc (0x0000000000008c00)
DW_AT_high_pc (0x0000000000008c2e)
DW_AT_frame_base (DW_OP_reg7 RSP)
DW_AT_linkage_name ("_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17hfb4f6378c21d627dE")
DW_AT_name ("{closure#0}<()>")
DW_AT_decl_file ("/rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/rt.rs")
DW_AT_decl_line (166)
DW_AT_type (0x00000e0d "i32")
0x00000cab: DW_TAG_variable
DW_AT_location (DW_OP_fbreg +8, DW_OP_deref)
DW_AT_name ("main")
DW_AT_alignment (1)
DW_AT_decl_file ("/rustc/aedd173a2c086e558c2b66d3743b344f977621a7/library/std/src/rt.rs")
DW_AT_decl_line (160)
DW_AT_type (0x00000df8 "void (*)()")
.eh_frame:
00000100 00000014 00000104 FDE cie=00000000 pc=00008c00...00008c2e
Format: DWARF32
DW_CFA_advance_loc: 4
DW_CFA_def_cfa_offset: +32
DW_CFA_advance_loc: 41
DW_CFA_def_cfa_offset: +8
DW_CFA_nop:
0x8c00: CFA=RSP+8: RIP=[CFA-8]
0x8c04: CFA=RSP+32: RIP=[CFA-8]
0x8c2d: CFA=RSP+8: RIP=[CFA-8]
Function:
00008c00 uint32_t std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hfb4f6378c21d627d()
00008c00 4883ec18 sub rsp, 0x18
00008c04 48897c2408 mov qword [rsp+0x8 {var_10}], rdi
00008c09 488b3f mov rdi, qword [rdi]
00008c0c e8af000000 call std::sys_common::backtra...in_short_backtrace::h19bbe0de0f738a6c
00008c11 e89a000000 call _$LT$$LP$$RP$$u20$as$u20...nation$GT$::report::h5ee8b94d852135b7
00008c16 88442407 mov byte [rsp+0x7 {var_11}], al {0x0}
00008c1a 488d442407 lea rax, [rsp+0x7 {var_11}]
00008c1f 4889442410 mov qword [rsp+0x10 {var_8}], rax {var_11}
00008c24 0fb6442407 movzx eax, byte [rsp+0x7 {var_11}]
00008c29 4883c418 add rsp, 0x18
00008c2d c3 retn {__return_addr}
"main" should be at offset -16 (var_10), since it's RSP+8, but we don't have a way of saying that the variable is only applicable starting at 0x8c04 after RSP is decreased by 0x18 because it's not in a lexical block. So instead we have to assume the variable's lifetime starts at the function start address.
Possible ways to work around this:
- For functions with SP frame base, walk CFA offsets and try to guess where stack adjustment for variable allocations happens
- Assume that if there are more than two CFA offsets and the first and last are the same, then we should base variables off the second offset Neither of these are perfect.
The ability to define stack variable lifetimes at start/end offsets in a function would help solve this.
Resolution for CFA-based locations has improved dramatically (see: is implemented) in 4.2.6176-dev, but there are still some edge cases
This is improved again in 4.2.6250.dev, most new cases likely fall under https://github.com/Vector35/binaryninja-api/issues/5991