Отладка основных файлов, сгенерированных на коробке клиента

Мы получаем основные файлы от запуска нашего программного обеспечения на коробке клиента. К сожалению, потому что мы всегда компилировали с -O2 без отладочных символов, это привело к ситуациям, когда мы не могли понять, почему это вылетало, мы изменили сборки так, что теперь они генерируют -g и -O2 вместе. Затем мы советуем клиенту запустить двоичный файл -g, чтобы его было легче отлаживать.

У меня есть несколько вопросов:

  1. Что происходит, когда файл ядра создается из дистрибутива Linux, отличного от того, который мы используем в Dev? Является ли трассировка стека вообще значимой?
  2. Есть ли хорошие книги для отладки на Linux или Solaris? Что-то, ориентированное на пример, было бы здорово. Я ищу примеры из реальной жизни, чтобы выяснить, почему рутина рухнула и как автор пришел к решению. Было бы неплохо что-то большее на уровне от среднего до продвинутого, так как я занимаюсь этим уже некоторое время. Некоторая сборка тоже подойдет.

Вот пример сбоя, который требует, чтобы мы сказали Клиенту получить -g вер. двоичного файла:

Program terminated with signal 11, Segmentation fault.
#0  0xffffe410 in __kernel_vsyscall ()
(gdb) where
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x00454ff1 in select () from /lib/libc.so.6
...
<omitted frames>

В идеале я хотел бы выяснить, почему именно приложение зависло - я подозреваю, что это повреждение памяти, но я не уверен на 100%.

Удаленная отладка строго запрещена.

Спасибо

5 ответов

Решение

Что происходит, когда файл ядра создается из дистрибутива Linux, отличного от того, который мы используем в Dev? Является ли трассировка стека вообще значимой?

Если исполняемый файл динамически связан, как и ваш, стек, создаваемый GDB, (скорее всего) не будет иметь смысла.

Причина: GDB знает, что ваш исполняемый файл потерпел крах, вызвав что-то в libc.so.6 по адресу 0x00454ff1, но он не знает, какой код был по этому адресу. Так это выглядит в вашей копии libc.so.6 и обнаруживает, что это в selectтак что печатает это.

Но шансы, что 0x00454ff1 также в избранном в ваших клиентов копию libc.so.6 довольно маленькие. Скорее всего, у клиента была другая процедура по этому адресу, возможно, abort,

Ты можешь использовать disas selectи заметьте, что 0x00454ff1 либо находится в середине инструкции, либо предыдущая инструкция не является CALL, Если что-то из этого верно, ваша трассировка стека не имеет смысла.

Однако вы можете помочь себе: вам просто нужно получить копию всех библиотек, перечисленных в (gdb) info shared из системы клиента. Попросите клиента сменить их, например, на

cd /
tar cvzf to-you.tar.gz lib/libc.so.6 lib/ld-linux.so.2 ...

Затем в вашей системе:

mkdir /tmp/from-customer
tar xzf to-you.tar.gz -C /tmp/from-customer
gdb /path/to/binary
(gdb) set solib-absolute-prefix /tmp/from-customer
(gdb) core core  # Note: very important to set solib-... before loading core
(gdb) where      # Get meaningful stack trace!

Затем мы советуем клиенту запустить двоичный файл -g, чтобы его было легче отлаживать.

Гораздо лучший подход:

  • строить с -g -O2 -o myexe.dbg
  • cp myexe.dbg myexe
  • strip -g myexe
  • распространять myexe клиентам
  • когда клиент получает coreиспользовать myexe.dbg отладить это

Вы будете иметь полную символическую информацию (файл / строка, локальные переменные), без необходимости отправлять специальный двоичный файл клиенту и не раскрывая слишком много деталей о ваших источниках.

Вы действительно можете получить полезную информацию из аварийного дампа, даже из оптимизированной компиляции (хотя это, технически, называется "основной болью в заднице"). -g Компиляция действительно лучше, и да, вы можете сделать это, даже если машина, на которой произошел дамп, является другим дистрибутивом. По сути, с одним предупреждением вся важная информация содержится в исполняемом файле и попадает в дамп.

Когда вы сопоставите файл ядра с исполняемым файлом, отладчик сможет сообщить вам, где произошел сбой, и показать вам стек. Это само по себе должно помочь. Вы также должны узнать как можно больше о ситуации, в которой это происходит, - могут ли они надежно воспроизвести ее? Если да, можете ли вы воспроизвести его?

Теперь, вот предостережение: место, где понятие "все есть" разрушается, - это общие объектные файлы, .so файлы. Если это не удается из-за проблем с ними, у вас не будет нужных вам таблиц символов; вы можете только увидеть, какая библиотека .so это происходит в.

Есть много книг об отладке, но я не могу придумать одну, которую я бы порекомендовал.

Копирование резолюции из моего вопроса, который посчитали дубликатом этого.

set solib-absolute-prefix из принятого решения мне не помогло. set sysrootбыло абсолютно необходимо, чтобы gdb загружал локально предоставленные библиотеки. Вот список команд, которые я использовал для открытия дампа ядра:

      # note: all the .so files obtained from user machine must be put into local directory.
#
# most importantly, the following files are necessary:
#   1. libthread_db.so.1 and libpthread.so.0: required for thread debugging.
#   2. other .so files are required if they occur in call stack.
#
# these files must also be renamed exactly as the symlinks
# i.e. libpthread-2.28.so should be renamed to libpthread.so.0

# load executable file
file ./thedarkmod.x64

# force gdb to forget about local system!
# load all .so files using local directory as root
set sysroot .

# drop dump-recorded paths to .so files
# i.e. load ./libpthread.so.0 instead of ./lib/x86_64-linux-gnu/libpthread.so.0
set solib-search-path .
# disable damn security protection
set auto-load safe-path /

# load core dump file
core core.6487

# print stacktrace
bt

Проверьте значения локальных переменных, которые вы видите, когда вы ходите по стеку? Особенно вокруг вызова select(). Сделайте это на коробке клиента, просто загрузите дамп и пройдитесь по стеку...

Также проверьте значение FD_SETSIZE на платформах DEV и PROD!

Насколько я помню, вам не нужно просить клиента запускать двоичный файл с опцией -g. Что вам нужно, так это то, что у вас должна быть сборка с опцией -g. При этом вы можете загрузить файл ядра, и он покажет всю трассировку стека. Я помню несколько недель назад, я создал файлы ядра, со сборкой (-g) и без -g, и размер ядра был таким же.

Другие вопросы по тегам