Как разыменовать ссылку в DWARF

Как я могу получить адрес моей переменной по ссылке из 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

Я хочу знать, как вручную найти адрес 0x1fff6e48, если у меня есть только ссылка в as_ref.

Информация о гномах для main_struct это:

<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

0

Решение

TLDR: указатель и ссылки — это то же самое, что и под крюком. 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);
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]