【问题标题】:Find frame base and variable locations using DWARF version 4使用 DWARF 版本 4 查找框架基础和变量位置
【发布时间】:2021-03-18 22:19:15
【问题描述】:

我正在关注Eli Bendersky's blog on parsing the DWARF debug information。他在他的博客中展示了一个使用 DWARF 版本 2 解析二进制文件的示例。 函数的框架基础(进一步用于检索局部变量)可以从location list

<1><71>: Abbrev Number: 5 (DW_TAG_subprogram)
    <72>   DW_AT_external    : 1
    <73>   DW_AT_name        : (...): do_stuff
    <77>   DW_AT_decl_file   : 1
    <78>   DW_AT_decl_line   : 4
    <79>   DW_AT_prototyped  : 1
    <7a>   DW_AT_low_pc      : 0x8048604
    <7e>   DW_AT_high_pc     : 0x804863e
    <82>   DW_AT_frame_base  : 0x0      (location list)
    <86>   DW_AT_sibling     : <0xb3>
...
$ objdump --dwarf=loc tracedprog2
Contents of the .debug_loc section:

    Offset   Begin    End      Expression
    00000000 08048604 08048605 (DW_OP_breg4: 4 )
    00000000 08048605 08048607 (DW_OP_breg4: 8 )
    00000000 08048607 0804863e (DW_OP_breg5: 8 )

但是,我发现在 DWARF 版本 4 中没有这样的 .debug_loc 部分。这是我机器上的功能信息:

<1><300>: Abbrev Number: 17 (DW_TAG_subprogram)
    <301>   DW_AT_external    : 1
    <301>   DW_AT_name        : (indirect string, offset: 0x1e0): do_stuff
    <305>   DW_AT_decl_file   : 1
    <306>   DW_AT_decl_line   : 3
    <307>   DW_AT_decl_column : 6
    <308>   DW_AT_prototyped  : 1
    <308>   DW_AT_low_pc      : 0x1149
    <310>   DW_AT_high_pc     : 0x47
    <318>   DW_AT_frame_base  : 1 byte block: 9c        (DW_OP_call_frame_cfa)
    <31a>   DW_AT_GNU_all_tail_call_sites: 1

行表示框架基数是1 byte block: 9c (DW_OP_call_frame_cfa)。知道如何找到 DWARF v4 二进制文件的框架基础吗?


根据@Employed Russian 的回答更新: 子程序的frame_base似乎指向Canonical Frame Address (CFA),即调用指令之前的RBP值。

 <2><329>: Abbrev Number: 19 (DW_TAG_variable)
    <32a>   DW_AT_name        : (indirect string, offset: 0x7d): my_local
    <32e>   DW_AT_decl_file   : 1
    <32f>   DW_AT_decl_line   : 5
    <330>   DW_AT_decl_column : 9
    <331>   DW_AT_type        : <0x65>
    <335>   DW_AT_location    : 2 byte block: 91 6c     (DW_OP_fbreg: -20)

因此,CFA 可以使用以下计算来定位局部变量(上例中的my_local):&amp;my_local = CFA - 20 = (current RBP + 16) - 20 = current RBP - 4. 通过检查程序集来验证它:

void do_stuff(int my_arg)
{
    1149:   f3 0f 1e fa             endbr64 
    114d:   55                      push   %rbp
    114e:   48 89 e5                mov    %rsp,%rbp
    1151:   48 83 ec 20             sub    $0x20,%rsp
    1155:   89 7d ec                mov    %edi,-0x14(%rbp)
    int my_local = my_arg + 2;
    1158:   8b 45 ec                mov    -0x14(%rbp),%eax
    115b:   83 c0 02                add    $0x2,%eax
    115e:   89 45 fc                mov    %eax,-0x4(%rbp)

my_local 位于-0x4(%rbp)

【问题讨论】:

    标签: linux elf dwarf


    【解决方案1】:

    这与DWARFv2DWARFv4 无关——使用任一版本,编译器可能会选择使用或不使用位置列表。您的编译器选择不这样做。

    知道如何找到 DWARF v4 二进制文件的框架基础吗?

    它会告诉你:使用CFA 伪寄存器,也称为“规范帧地址”。

    那个“虚构”寄存器的值与%rsp 在调用当前函数之前的值相同。也就是说,当前函数的返回地址总是存储在CFA+0,进入函数时是%rsp == CFA+8

    如果函数使用帧指针,那么%rbp的先前值通常存储在CFA+8

    更多信息here

    【讨论】:

    • 刚刚使用 CFA 检查了变量地址,它与程序集的偏移量匹配。
    • 顺便说一句,位置后面的代码是什么意思,比如2 byte block: 91 6c,或者1 byte block: 9c
    猜你喜欢
    • 1970-01-01
    • 2010-12-23
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 2012-07-13
    相关资源
    最近更新 更多