Gdb не может найти позиции ошибок утверждения после перекомпиляции

Похоже, что GDB не может найти позицию кода ошибки утверждения после того, как я перекомпилирую свой код. Точнее, я ожидаю, что позиция сигнального повышения относительно неудачного утверждения будет

0x00007ffff7a5ff00 in raise () from /lib64/libc.so.`6

а вместо этого я получаю

0x00007ffff7a5ff00 in ?? ()

Например, рассмотрим следующий код

#include <assert.h>

int main()
{
  assert(0);
  return 0;
}

скомпилирован с отладочными символами и отлажен с помощью gdb.

> gcc -g main.c
> gdb a.out

При первом запуске gdb позиция найдена, и обратная трассировка сообщается правильно:

GNU gdb (Gentoo 8.0.1 p1) 8.0.1 
...
(gdb) r
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
#1  0x00007ffff7a61baa in abort () from /lib64/libc.so.6
#2  0x00007ffff7a57cb7 in ?? () from /lib64/libc.so.6
#3  0x00007ffff7a57d72 in __assert_fail () from /lib64/libc.so.6
#4  0x00005555555546b3 in main () at main.c:5
(gdb)

Проблема возникает, когда я перекомпилирую код. После перекомпиляции я запускаю команду запуска в том же экземпляре gdb. Gdb перечитывает символы, запускает программу с начала, но не находит нужной позиции:

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
`/home/myself/a.out' has changed; re-reading symbols.
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in ?? ()
(gdb) bt
#0  0x00007ffff7a5ff00 in ?? ()
#1  0x0000000000000000 in ?? ()
(gdb) up
Initial frame selected; you cannot go up.
(gdb) n
Cannot find bounds of current function

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

(gdb) file a.out
Load new symbol table from "a.out"? (y or n) y
Reading symbols from a.out...done.
(gdb) r
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
(gdb) 

К сожалению, после перезагрузки файла таким образом gdb не может сбросить точки останова.

ИСПРАВЛЕНИЕ ОШИБКИ: У меня возникла ошибка при сбросе точек останова с помощью gdb 7.12.1. После обновления до 8.0.1 проблема исчезла. Предположительно, это было связано с исправлением ошибки https://sourceware.org/bugzilla/show_bug.cgi?id=21555. Однако позиции кода, в которых утверждения не выполняются, по-прежнему не могут быть правильно найдены.

Кто-нибудь знает, что здесь происходит?

Это началось после обновления системы. При обновлении системы все системные библиотеки, включая glibc, были перекомпилированы как позиционно-независимый код, т. Е. Скомпилированный с помощью -fPIC.

Кроме того, я использую версию gcc 6.4.0.


person Mirco    schedule 02.02.2018    source источник
comment
Вы отлаживаете другой файл, как вы можете использовать точки останова, которые были определены для старого файла?   -  person user202729    schedule 02.02.2018
comment
Используйте IDE. Они достаточно умны, чтобы прикрепить точку останова к строке и сообщить об этом отладчику при запуске. Они также достаточно умны, чтобы знать, что местоположение точки останова изменяется, когда вы добавляете перед ней строку. Очень полезно.   -  person nwp    schedule 02.02.2018
comment
Я не знаю, как это реализовано внутри GDB. Я думаю, было бы желательно иметь возможность повторно запускать ваш код и повторно использовать ваши точки останова после перекомпиляции. Я могу ожидать, что, возможно, точка останова по строке выйдет не на своем месте, но не будет необходимости перезапускать gdb каждый раз   -  person Mirco    schedule 02.02.2018
comment
file a.out не перезапускает gdb. Он загружает правильный двоичный файл. И, возможно, размещение всех ваших точек останова в неправильном месте из-за того, что вы добавили или удалили строку, звучит бесполезно.   -  person nwp    schedule 02.02.2018
comment
Я согласен. На самом деле я ожидаю, что будут найдены точки останова для функций. Но здесь проблема в том, что gdb не может найти никакой позиции (например, где утверждение не работает), независимо от точек останова.   -  person Mirco    schedule 02.02.2018


Ответы (2)


Вот обходной путь. Поскольку file перечитывает символы правильно, а run - нет, мы можем определить ловушку для команды run, чтобы выполнить file раньше:

define hook-run
  pi gdb.execute("file %s" % gdb.current_progspace().filename)
end
person Mirco    schedule 05.02.2018

после того, как вы измените исходный файл и перекомпилируете, вы создадите файл, отличный от того, который был загружен в GDB.

вам необходимо остановить запущенный сеанс отладки и перезагрузить файл.

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

если вы измените источник, поведение будет неопределенным, и вам необходимо сбросить эти точки останова.

вы можете обратиться к руководству gdb относительно сохранения точек останова в файле, как предложил Марк Плотник, но это не сработает, если вы измените файл (по моему опыту) https://sourceware.org/gdb/onlinedocs/gdb/Save-Breakpoints.html

person Itay Sadovnik    schedule 02.02.2018
comment
Действительно, перезагружаю символы. После перекомпиляции я снова запускаю команду запуска, возвращая сообщение об изменении «/home/myself/a.out»; перечитывание символов. Но GDB не может найти правильную позицию, в которой утверждение не удалось. - person Mirco; 02.02.2018
comment
Я не знаю способа сохранить точки останова. вам нужно сбросить их, когда вы перезагружаете файл. Я предполагаю, что это потому, что виртуальный адрес выражения, которое вы пытаетесь изучить, изменился (после изменения файла), а ранее установленная точка останова не связана с ним - person Itay Sadovnik; 02.02.2018
comment
Было бы неплохо, если бы был способ указать точки останова gdb по номеру строки с помощью некоторого фрагмента исходного кода в этой строке и вокруг нее, например ctags, который индексирует каждую строку исходного кода. Тогда ваш список точек останова сможет пережить незначительные правки кода. Может быть, это то, что IDE могла бы сделать. - person Mark Plotnick; 04.02.2018
comment
Действительно, было бы. Тем не менее проблема, с которой я столкнулся, была более тонкой, чем эта. Это было связано с ошибкой сброса точек останова после выполнения команды. Это была ошибка с исполняемыми файлами PIE, которая была исправлена ​​в версии 8.0.1. Я обновил пост соответственно - person Mirco; 04.02.2018