binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

DWARF errors: `Trying to add a local variable at positive storage offset`

Open psifertex opened this issue 1 year ago • 3 comments

"Trying to add a local variable at positive storage offset" in customer reported binary from slack. Uploaded internally as tiptoe bet addicted property

psifertex avatar Aug 26 '24 15:08 psifertex

Another user's binary https://github.com/user-attachments/files/16773531/libbar-x86_64.zip

emesare avatar Aug 28 '24 13:08 emesare

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.

negasora avatar Oct 10 '24 21:10 negasora

Resolution for CFA-based locations has improved dramatically (see: is implemented) in 4.2.6176-dev, but there are still some edge cases

negasora avatar Oct 10 '24 22:10 negasora

This is improved again in 4.2.6250.dev, most new cases likely fall under https://github.com/Vector35/binaryninja-api/issues/5991

negasora avatar Oct 21 '24 20:10 negasora