Используя предложение user2162550, код удалось скомпилировать, но какой-то код, который мне пришлось распечатать, имена функций, которые были в отладочной информации, ничего не печатали.Затем я увидел комментарий в скрипте компоновщика по умолчанию, который использует gcc (передав ему -Wl,--verbose
при компоновке исполняемого файла):
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
...
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
...
Это убедило меня, что не имеет значения, где находятся символы отладки,в финальном бинарном файле.Затем я попытался использовать дырочку (из здесь ), но я не был уверен, как скопировать отладочную информацию до того, как исполняемый файл будет связан (как только исполняемый файл будет связан, я не думаю, objcopy
работает больше).Поэтому я решил оставить некоторое пространство, которое загружается и выделяется в двоичном файле, а затем, после компоновки, скопировать необходимые разделы в это пространство.
Для этого я использовал скрипт компоновщика, чтобы оставить дыру итакже предоставьте символы, чтобы выяснить, где находятся разделы отладки.Метод, который я получил, состоял в том, чтобы использовать скрипт компоновщика, чтобы сначала измерить размер каждого раздела отладки, а затем выделить для него достаточно места.Это выглядит так (в test.lds
:
/* This finds the start and end of each section so we know its size */
SECTIONS
{
.debug_info 0 : {
__my_old_debug_info_start = .;
KEEP (*(.debug_info .gnu.linkonce.wi.*)) *(.debug_info .gnu.linkonce.wi.*)
__my_old_debug_info_end = .;
}
.debug_abbrev 0 : {
__my_old_debug_abbrev_start = .;
KEEP (*(.debug_abbrev)) *(.debug_abbrev)
__my_old_debug_abbrev_end = .;
}
.debug_str 0 : {
__my_old_debug_str_start = .;
KEEP (*(.debug_str)) *(.debug_str)
__my_old_debug_str_end = .;
}
}
INSERT AFTER .rodata;
/* This creates some space in the binary which is loaded and big enough to store all the debugging info, as well as marking the start and end of each area */
SECTIONS
{
.debug_all : {
__my_debug_info_start = .;
. += __my_old_debug_info_end - __my_old_debug_info_start;
__my_debug_info_end = .;
__my_debug_abbrev_start = .;
. += __my_old_debug_abbrev_end - __my_old_debug_abbrev_start;
__my_debug_abbrev_end = .;
__my_debug_str_start = .;
. += __my_old_debug_str_end - __my_old_debug_str_start;
__my_debug_str_end = .;
}
}
INSERT AFTER .rodata;
Я думаю, что выбор .rodata
для INSERT AFTER
является произвольным.
Затем я скомпилировал и связал с:
gcc libtest.a -g -o test -T test.lds -static
Вдохновившись этим , у меня был скрипт bash, который анализировал вывод readelf
и вычислял, где в двоичном файле получить отладочную информацию и куда ее скопировать, чтобы оназагружается. Копирование выполняется с использованием dd
.
function getSymbolValue {
binary=$1
symbol=$2
# Assumes that this will only find one symbol
truncated_symbol=`echo $symbol | cut -c 1-25`
readelf -s $binary | grep $truncated_symbol | awk '{print $2}'
}
function getSectionInfo {
binary=$1
section=$2
# returns all but the [Nr] column of data returned by readelf
# https://stackoverflow.com/a/3795522/3492895
readelf -S $binary | cut -c7- | grep '\.'"$section"
}
function getSectionAddress {
binary=$1
section=$2
getSectionInfo $binary $section | awk '{print $3}'
}
function getSectionOffset {
binary=$1
section=$2
getSectionInfo $binary $section | awk '{print $4}'
}
function copyData {
binary=$1
from_start=$2
to_start=$3
len=$4
dd iflag=skip_bytes,count_bytes if=$binary skip=$from_start count=$len | dd oflag=seek_bytes of=$binary seek=$to_start count=$len conv=notrunc
}
function copyDebugSection {
binary=$1
from_section=$2
to_section=$3
from_off=`getSectionOffset $binary $from_section`
to_section_off=`getSectionOffset $binary $to_section`
to_section_addr=`getSectionAddress $binary $to_section`
to_start_addr=`getSymbolValue $binary "__my_${from_section}_start"`
to_end_addr=`getSymbolValue $binary "__my_${from_section}_end"`
copyData $binary $((0x$from_off)) $((0x$to_start_addr - 0x$to_section_addr + 0x$to_section_off)) $((0x$to_end_addr - 0x$to_start_addr))
}
copyDebugSection ./test 'debug_info' 'debug_all'
copyDebugSection ./test 'debug_abbrev' 'debug_all'
copyDebugSection ./test 'debug_str' 'debug_all'
После выполнения этого имена функций, которые я ожидал, были распечатаны.
Если кому-то было интересно, как я распечаталимена функций, я написал некоторый код в ржавчине, используя библиотеку gimli. Так как это не имело отношения к вопросу, я не включил его. Я использовал это, чтобы убедиться, что там была правильная информация отладки, так как я не нашел никакой магииномера карликов, чтобы искать в Интернете, чтобы обеспечить целостность информации.
Единственная потенциальная проблема заключается в том, что при запуске readelf
, он выводит:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
readelf: Warning: [ 3]: Link field (0) should index a symtab section.
[ 3] .rela.plt RELA 0000000000400168 00000168
0000000000000228 0000000000000018 AI 0 25 8
Но я не понимаю, что этомнеANS, и это не кажется представлять проблему.
Пожалуйста, скажите мне, что я могу сделать, чтобы улучшить этот вопрос или ответ.