Я пытаюсь использовать dwarf для сравнения двух файлов C ++, но у меня возникают проблемы, когда я получаю локальные переменные в функциях, не являющихся членами. Рассмотрим следующий код —
int f(){
[static] int j=0;
return j;
}
Если я скомпилирую без static
модификатор я получаю следующую информацию о гномах —
<1><eb>: Abbrev Number: 13 (DW_TAG_subprogram)
<ec> DW_AT_external : 1
<ed> DW_AT_name : f
<ef> DW_AT_decl_file : 1
<f0> DW_AT_decl_line : 15
<f1> DW_AT_MIPS_linkage_name: (indirect string, offset: 0x22): _Z1fv
<f5> DW_AT_type : <0xa8>
<f9> DW_AT_low_pc : 0x0
<101> DW_AT_high_pc : 0x10
<109> DW_AT_frame_base : 0x0 (location list)
<10d> DW_AT_sibling : <0x130>
<2><111>: Abbrev Number: 14 (DW_TAG_lexical_block)
<112> DW_AT_low_pc : 0x4
<11a> DW_AT_high_pc : 0xe
<3><122>: Abbrev Number: 15 (DW_TAG_variable)
<123> DW_AT_name : j
<125> DW_AT_decl_file : 1
<126> DW_AT_decl_line : 16
<127> DW_AT_type : <0xa8>
<12b> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20)
но если я скомпилирую с static
модификатор я получаю —
<1><eb>: Abbrev Number: 13 (DW_TAG_subprogram)
<ec> DW_AT_external : 1
<ed> DW_AT_name : f
<ef> DW_AT_decl_file : 1
<f0> DW_AT_decl_line : 22
<f1> DW_AT_MIPS_linkage_name: (indirect string, offset: 0x24): _Z1fv
<f5> DW_AT_type : <0xa8>
<f9> DW_AT_low_pc : 0x0
<101> DW_AT_high_pc : 0xc
<109> DW_AT_frame_base : 0x0 (location list)
<10d> DW_AT_sibling : <0x137>
<2><111>: Abbrev Number: 14 (DW_TAG_lexical_block)
<112> DW_AT_low_pc : 0x4
<11a> DW_AT_high_pc : 0xa
<3><122>: Abbrev Number: 15 (DW_TAG_variable)
<123> DW_AT_name : j
<125> DW_AT_decl_file : 1
<126> DW_AT_decl_line : 23
<127> DW_AT_type : <0xa8>
<12b> DW_AT_location : 9 byte block: 3 20 0 0 0 0 0 0 0 (DW_OP_addr: 20)
Теперь, насколько я могу судить, между этими файлами есть только одно реальное различие — размер байтового блока на DW_AT_location
атрибуты для переменной j разные (вот почему DW_AT_sibling
атрибуты в теге функции f различны, поэтому я не считаю это). Я предполагаю, что это как-то подразумевает статичность, но я не знаю как.
DWARF не пытается описать связь переменной, только ее тип, область действия и способ ее определения. И под «областью действия» я подразумеваю, когда код может видеть / получать доступ к значению, которое означает только в теле f()
даже если это статично.
fbreg
регистр, который является основой вашего стекового фрейма — чаще всего на x86_64, rbp
, Локальные переменные содержатся в стеке внутри стекового фрейма функции (опять же в x86_64, обычно между rbp
а также rsp
). Стек растет вниз так rbp
имеет более высокое значение, чем rsp
,
Насколько DW_AT_location
для вашего статического значения, равного 20, я предполагаю, что вы сбросили DWARF файла .o до того, как он был связан с исполняемым файлом. Когда это связано с окончательным исполняемым файлом, я ожидаю, что компоновщик обновит это DW_AT_location
с фактическим адресом статического — прямо сейчас я держу пари, что это просто заполнитель перемещения.
Обычно отладчики используют имена символов в самом исполняемом файле, чтобы расширить свой список глобальных / статических переменных, потому что пользователи могут захотеть проверить f
«s j
переменная, даже если f()
выходит за рамки Имя статики будет каким-то образом искажено (не обязательно в смысле искажения в C ++) (иначе будет другой функцией). g()
который также имел static j
будет конфликтовать), поэтому отладчик должен знать, как справиться с этим.
Я не эксперт по «DWARF», но я вижу очень четкую разницу между этими строками:
<12b> DW_AT_location : 2 byte block: 91 6c (DW_OP_fbreg: -20)
<12b> DW_AT_location : 9 byte block: 3 20 0 0 0 0 0 0 0 (DW_OP_addr: 20)
Один из fbreg: -20
— так «regeister буфера кадра, смещение -20».
Другой, я полагаю, ссылается на абсолютный адрес (32 байта в сегменте DATA, возможно?)