- Вопрос или проблема
- Ответ или решение
- Как GDB Получает Имена Файлов Исходного Кода для Глобальных Переменных и Функций?
- 1. Процесс Сборки и Отладочная Информация
- 2. Взаимодействие GDB и ELF Формата
- 3. Почему Имена Файлов Могут Отсутствовать в Файловой Системе
- 4. Настройка GDB для Эффективной Отладки
- Заключение
Вопрос или проблема
Я использую gdb
для подключения к запущенному процессу на системе Linux. Как вы можете видеть, info files
показывает секции из исполняемого файла ELF
, которые отображены в виртуальной памяти процесса, а также секции загруженных общих библиотек .so
.
root@host:/# gdb -q attach 7173
attach: Нет такого файла или каталога.
Подключение к процессу 7173
[Новый LWP 17381]
[Новый LWP 17380]
[Новый LWP 17379]
предупреждение: Ожидался абсолютный путь для libpthread в подчинённом процессе, но получен target:/lib64/libpthread.so.0.
предупреждение: Невозможно найти libthread_db, соответствующую библиотеке потоков подчинённого процесса, отладка потоков не будет доступна.
0x00007f0bf997ac73 in epoll_wait () at ../sysdeps/unix/syscall-template.S:81
предупреждение: 81 ../sysdeps/unix/syscall-template.S: Нет такого файла или каталога
(gdb) info files
Символы из "target:/proc/7173/exe".
Нативный процесс:
Используется запущенный образ прикрепленного процесса 7173.
При выполнении этого GDB не получает доступ к памяти из...
Локальный исполняемый файл:
`target:/proc/7173/exe', тип файла elf64-x86-64.
Точка входа: 0x564521600970
0x00005645215fa200 - 0x00005645215fa21c это .interp
0x00005645215fa21c - 0x00005645215fa23c это .note.ABI-tag
0x00005645215fa23c - 0x00005645215fa260 это .note.gnu.build-id
0x00005645215fa260 - 0x00005645215fb0b8 это .dynsym
0x00005645215fb0b8 - 0x00005645215fb1ea это .gnu.version
0x00005645215fb1ec - 0x00005645215fb23c это .gnu.version_r
0x00005645215fb240 - 0x00005645215fb588 это .gnu.hash
0x00005645215fb588 - 0x00005645215fcc2c это .dynstr
0x00005645215fcc30 - 0x00005645215fe850 это .rela.dyn
0x00005645215fe850 - 0x00005645215feaf0 это .rela.plt
0x00005645215feaf0 - 0x00005645215fff41 это .rodata
0x00005645215fff44 - 0x0000564521600140 это .eh_frame_hdr
0x0000564521600140 - 0x000056452160096c это .eh_frame
0x0000564521600970 - 0x00005645216012f1 это .text
0x00005645216012f4 - 0x000056452160130e это .init
0x0000564521601310 - 0x0000564521601319 это .fini
0x0000564521601320 - 0x00005645216014f0 это .plt
0x0000564521602000 - 0x0000564521602010 это .data
0x0000564521602010 - 0x0000564521602018 это .jcr
0x0000564521602018 - 0x0000564521602018 это .tm_clone_table
0x0000564521602018 - 0x0000564521602020 это .fini_array
0x0000564521602020 - 0x0000564521602028 это .init_array
0x0000564521602028 - 0x0000564521602fe8 это .data.rel.ro
0x0000564521602fe8 - 0x0000564521603298 это .dynamic
0x0000564521603298 - 0x00005645216034e0 это .got
0x00005645216034e0 - 0x00005645216035d8 это .got.plt
0x00005645216035e0 - 0x0000564521603ee4 это .bss
0x00007f0bfa9e4190 - 0x00007f0bfa9e41b4 это .note.gnu.build-id в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e41b8 - 0x00007f0bfa9e467c это .hash в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e4680 - 0x00007f0bfa9e56a0 это .dynsym в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e56a0 - 0x00007f0bfa9e60d1 это .dynstr в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e60d2 - 0x00007f0bfa9e622a это .gnu.version в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e6230 - 0x00007f0bfa9e62d0 это .gnu.version_r в target:/pkg/lib/libmemdbg.so
0x00007f0bfa9e62d0 - 0x00007f0bfa9e6690 это .rela.dyn в target:/pkg/lib/libmemdbg.so
--Нажмите <RET> для получения дополнительной информации, q для выхода, c для продолжения без постраничного отображения--
0x00007f0bfa9e6690 - 0x00007f0bfa9e7158 это .rela.plt в target:/pkg/lib/libmemdbg.so
Вывод info variables
показывает тип и имя (глобальных?) доступных переменных в адресном пространстве процесса вместе с именем исходного файла, в котором они определены.
(gdb)info variables
Все определенные переменные:
Файл ../csu/init-first.c:
38: int __libc_argc;
39: char **__libc_argv;
34: int __libc_multiple_libcs;
Файл ../elf/dl-sysdep.c:
61: void *__GI___libc_stack_end;
56: int __libc_enable_secure;
57: int __libc_enable_secure_internal;
58: int __libc_multiple_libcs;
62: void *__libc_stack_end;
63: void *_dl_random;
<вывод сокращён........>
(gdb)
Как gdb
получает имена этих исходных файлов? Их нет на системе, на которой работает gdb
.
Спасибо.
Ответ или решение
Как GDB Получает Имена Файлов Исходного Кода для Глобальных Переменных и Функций?
Когда вы используете GDB для подключения к работающему процессу на операционной системе Linux, возможно встретить ситуацию, когда вы видите имена исходных файлов для глобальных переменных и функций в выводе команды info variables
. Это может вызывать вопросы, особенно если на вашей системе отсутствуют указанные файлы. В этом ответе мы рассмотрим, как GDB получает информацию об именах этих файлов и откуда она берётся.
1. Процесс Сборки и Отладочная Информация
При компиляции исходного кода с использованием компилятора, такого как GCC, разработчик может включить опции, которые добавляют отладочную информацию в исполняемый файл. Это осуществляется с помощью флага -g
, который позволяет компилятору сохранять информацию о соответствиях между исполняемым кодом и исходными файлами. Например, при компиляции файла example.c
команда может выглядеть так:
gcc -g -o example example.c
В результате этого в облике ELF-исполняемого файла будет добавлена информация о строках исходного кода, их номерах и именах файлов. Эта информация сохраняется в специальных секциях, таких как .debug_info
, .debug_abbrev
, и других отладочных секциях.
2. Взаимодействие GDB и ELF Формата
Когда GDB подключается к исполняемому процессу, он использует информацию, сохранённую в ELF-файле, чтобы отобразить имена переменных и функций. Тем не менее, важно отметить, что, хотя указанные файлы могут отсутствовать в файловой системе в месте, где работает GDB, информация о них всё равно может быть доступна.
GDB получает имена файлов и информацию о порядке строк, извлекая данные из отладочных секций, хранящихся в исполняемом файле или библиотеке, загруженной в память процесса. Указанные в выводе переменные, как __libc_argc
и другие, происходят из ранее указанных секций:
info variables
: Команда показывает все определенные глобальные переменные, включая их типы и имена, а также имена файлов, в которых они определены.info files
: Эта команда отображает информацию об ELF-исполняемом файле и загруженных библиотеках.
3. Почему Имена Файлов Могут Отсутствовать в Файловой Системе
Существует несколько причин, почему GDB показывает имена файлов, которые отсутствуют на системе:
- Удалённый или контейнерный процесс: Если вы подключаетесь к процессу, который был создан или запущен в другом окружении, имени исходного файла могут быть недоступны на вашей текущей системе.
- Удалённые исходники: Исходные файлы могут быть удалены после создания бинарного файла, но информация о них все ещё сохраняется в отладочной информации, что позволяет GDB её извлекать.
- Безопасность и конфиденциальность: Некоторые приложения, особенно в производственных системах, могут либо не распространять, либо удалять исходные файлы для предотвращения несанкционированного доступа.
4. Настройка GDB для Эффективной Отладки
Если вы хотите видеть полные пути к исходным файлам и их содержимое при отладке вашего приложения, вы можете:
- Убедиться, что вы компилируете ваш код с флагом
-g
, чтобы сохранить отладочную информацию. - Использовать
strip
с осторожностью, так как эта команда может удалить отладочную информацию, сделав ваш исполняемый файл менее информативным. - Применять настройку путей для отладочных информации в GDB, чтобы указать, где искать соответствующие исходные файлы с помощью команды
directory
.
Заключение
GDB извлекает имена файлов исходного кода и другую отладочную информацию непосредственно из ELF-исполняемых файлов и загруженных библиотек. Это позволяет вам анализировать глобальные переменные и функции, даже если исходные файлы отсутствуют на вашей системе. Понимание того, как это работает, может значительно улучшить ваш опыт отладки в среде Linux.