【问题标题】:How to dereference a reference in DWARF如何取消引用 DWARF 中的引用
【发布时间】:2016-04-25 09:54:28
【问题描述】:

如何通过 DWARF 的引用获取变量的地址?

例如,我们有以下结构:

struct sub_struct
{
    int a, b;
    sub_struct(int a, int b) : a(a), b(b) {}
}

struct main_struct
{
    sub_struct & as_ref;
    int c, d;
    main_struct(sub_struct & ss) : as_ref(ss), c(0x100), d(0x101) {}
}

之后我们在全局环境中初始化这个结构:

sub_struct test_sub(0x10, 0x11);
main_struct test_inst(sub_struct);

实际上test_inst.as_ref 应该引用结构test_sub。我想获取存储在 as_ref 参考中的变量的位置。

如果我读取已编译代码的 dwarf 文件,那么我将获得我创建的结构:

  Compilation Unit @ offset 0x1a80bf:
   Length:        0x11e (32-bit)
   Version:       3
   Abbrev Offset: 0xd3e6
   Pointer Size:  4
 <0><1a80ca>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <1a814d>   DW_AT_stmt_list   : 0x8e02a
    <1a8151>   DW_AT_macro_info  : 0xc6fb
 <1><1a819b>: Abbrev Number: 3 (DW_TAG_variable)
    <1a819c>   DW_AT_name        : test_inst
    <1a81ad>   DW_AT_type        : <0x1a7643>
    <1a81b6>   DW_AT_location    : 5 byte block: 3 50 6e ff 1f  (DW_OP_addr: 1fff6e50)
    <1a81bc>   Unknown AT value: 2768: 1
 <1><1a81e0>: Abbrev Number: 0

  Compilation Unit @ offset 0x1a829e:
   Length:        0xb8 (32-bit)
   Version:       3
   Abbrev Offset: 0xd3e6
   Pointer Size:  4
 <0><1a82a9>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <1a832c>   DW_AT_stmt_list   : 0x8e02a
    <1a8330>   DW_AT_macro_info  : 0xc6fb
 <1><1a8334>: Abbrev Number: 3 (DW_TAG_variable)
    <1a8335>   DW_AT_name        : test_sub
    <1a834a>   DW_AT_type        : <0x1a761a>
    <1a8352>   DW_AT_location    : 5 byte block: 3 48 7d ff 1f  (DW_OP_addr: 1fff7d48)
    <1a8358>   Unknown AT value: 2768: 1
 <1><1a8359>: Abbrev Number: 0

如您所见,test_inst 位于 0x1fff6e50 地址。 test_sub 位于 0x1fff6e48。这是对的。如果我们要检查内存,那么:

  • test_sub.a 位于 0x1fff6e48
  • test_sub.b 位于 0x1fff6e4c
  • test_inst.as_ref 应该位于 0x1fff6e50
  • test_inst.c 位于 0x1fff6e54
  • test_inst.d 位于 0x1fff6e58

如果我在as_ref中只有参考,我想知道如何手动查找0x1fff6e48地址。

main_struct 的 Dwarf 信息如下:

<1><1a7643>: Abbrev Number: 40 (DW_TAG_structure_type)
    <1a7644>   DW_AT_sibling     : <0x1a76cf>
    <1a7648>   DW_AT_name        : test_struct
    <1a7654>   DW_AT_byte_size   : 44
 <2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
    <1a7656>   DW_AT_type        : <0x1a683a>
    <1a7658>   DW_AT_accessibility: 1   (public)
    <1a7659>   DW_AT_name        : as_ref
    <1a7660>   DW_AT_data_member_location: 2 byte block: 23 0   (DW_OP_plus_uconst: 0)
 <2><1a7663>: Abbrev Number: 44 (DW_TAG_member)
    <1a7664>   DW_AT_type        : <0x1a6833>
    <1a7666>   DW_AT_accessibility: 1   (public)
    <1a7667>   DW_AT_name        : c
    <1a7669>   DW_AT_data_member_location: 2 byte block: 23 4   (DW_OP_plus_uconst: 4)
 <2><1a766c>: Abbrev Number: 44 (DW_TAG_member)
    <1a766d>   DW_AT_type        : <0x1a6833>
    <1a766f>   DW_AT_accessibility: 1   (public)
    <1a7670>   DW_AT_name        : d
    <1a7672>   DW_AT_data_member_location: 2 byte block: 23 8   (DW_OP_plus_uconst: 8)
 <2><1a76ce>: Abbrev Number: 0

as_ref 类型是对此的引用:

<1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
<1a683b>   DW_AT_type        : <0x1a761a>

这将被重新引用:

 <1><1a761a>: Abbrev Number: 40 (DW_TAG_structure_type)
    <1a761b>   DW_AT_sibling     : <0x1a7643>
    <1a761f>   DW_AT_name        : sub_struct
    <1a762f>   DW_AT_byte_size   : 8
 <2><1a7630>: Abbrev Number: 44 (DW_TAG_member)
    <1a7631>   DW_AT_type        : <0x1a6833>
    <1a7633>   DW_AT_accessibility: 1   (public)
    <1a7634>   DW_AT_name        : a
    <1a7636>   DW_AT_data_member_location: 2 byte block: 23 0   (DW_OP_plus_uconst: 0)
 <2><1a7639>: Abbrev Number: 44 (DW_TAG_member)
    <1a763a>   DW_AT_type        : <0x1a6833>
    <1a763c>   DW_AT_accessibility: 1   (public)
    <1a763d>   DW_AT_name        : b
    <1a763f>   DW_AT_data_member_location: 2 byte block: 23 4   (DW_OP_plus_uconst: 4)
 <2><1a7642>: Abbrev Number: 0

【问题讨论】:

    标签: c++ debugging dwarf


    【解决方案1】:

    TLDR:在 hookd 下指针和引用是一回事。 as_ref 包含引用的sub_struct 的地址。

    这告诉您as_ref 位于偏移量 0(因此为 0x1fff6e50):

    <2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
        <1a7656>   DW_AT_type        : <0x1a683a>
        <1a7658>   DW_AT_accessibility: 1   (public)
        <1a7659>   DW_AT_name        : as_ref
        <1a7660>   DW_AT_data_member_location: 2 byte block: 23 0   (DW_OP_plus_uconst: 0)
    

    它的类型由以下给出:

    <1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
      <1a683b>   DW_AT_type        : <0x1a761a>
    

    这意味着它是对另一种类型的引用。引用和指针本质上是一样的:它们包含另一个变量的地址。

    进程内部:

    void* main_struct_addr = 0x1fff6e50; // from DWARF
    std::uint64_t as_ref_offset = 0;     // from DWARF
    void* main_as_ref_addr = (char*) main_struct_addr + as_ref_offset;
    void as_addr = *(void**) main_a_ref_addr;
    assert(as_adddr == (void*) 0x1fff6e48);
    

    来自另一个进程:

    std::uint64_t main_struct_addr = 0x1fff6e50; // from DWARF
    std::uint64_t as_ref_offset = 0;             // from DWARF
    std::uint64_t main_as_ref_addr = main_struct_addr + as_ref_offset;
    errno = 0;
    void* as_addr = (void*) ptrace(PTRACE_PEEKDATA, pid, (void*) main_as_ref_addr, NULL);
    if (errno) { ... }
    assert(as_adddr == (void*) 0x1fff6e48);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-08
      • 2016-05-31
      • 2014-05-15
      • 2014-10-12
      • 2016-11-18
      • 2013-09-15
      • 2015-11-16
      • 1970-01-01
      相关资源
      最近更新 更多