GDB strace показывает, что пытается выполнить ptrace по неверному адресу

Я столкнулся с такой ошибкой при выполнении команды ni во время отладки gdb:

Предупреждение:
Невозможно вставить точку останова 0.
Ошибка доступа к адресу памяти 0x3ac706a: ошибка ввода/вывода.

0xf6fa4771 в siglongjmp() из /lib/libc.so. 6

Чтобы выяснить, с какой проблемой сталкивается gdb, я запускаю gdb и получаю такой вывод:

rt_sigprocmask(SIG_BLOCK, NULL, [RT_1], 8) = 0
ptrace(PTRACE_PEEKTEXT, 651, 0xcc4fdf60, [0x1cc4fe470]) = 0
ptrace(PTRACE_PEEKTEXT, 651, 0xcc4fe480, [0x3ac706a4506fa1d]) = 0
ptrace(PTRACE_PEEKTEXT, 651, 0xcc4fe480, [0x3ac706a4506fa1d] 0
rt_sigprocmask(SIG_BLOCK, NULL, [RT_1], 8) = 0

...
rt_sigprocmask(SIG_BLOCK, NULL, [RT_1], 8) = 0< br> rt_sigprocmask(SIG_BLOCK, NULL, [RT_1], 8) = 0
ptrace(PTRACE_GETREGS, 27781, 0, 0x7fff8990e8b0) = 0
ptrace(PTRACE_PEEKTEXT, 27781, 0x3ac7068, [0x28b]) = -1 EIO (ошибка ввода/вывода)
ptrace(PTRACE_PEEKTEXT, 27781, 0x3ac7068, [0x28b]) = -1 EIO (ошибка ввода/вывода)

Это означает, что gdb сначала выполняет трассировку по адресу памяти 0xcc4fe480 и получает значение 0x3ac706a4506fa1d (фактически 8-байтовое значение 0x03ac706a4506fa1d). Позже он получает выровненный адрес 0x3ac7068 из первых 4 байтов этого значения, что является недопустимым адресом и приводит к сбою ptrace gdb.

Содержимое /proc/[pid]/maps:

cc3f0000-cc3f6000 br> cc3f6000-cc3fe000 rw-p cc3f6000 00:00 0
cc3fe000-cc3ff000 ---p cc3fe000 00:00 0
cc3ff000-cc4ff000 rwxp cc3ff000 00:00 0
cc4ff000-cc500000 ---p cc4ff000 00:00 0

cc500000-cc600000 rwxp cc500000 00:00 0
cc62d000-cc673000 r-xp 00000000 08:03 07cc
06-br00.yyy ---p 00046000 08:03 295545 yyy.so
cc674000-cc675000 r--p 00046000 08:03 295545 yyy.so
cc675000-cc676000 rw-p 00047000 08:03 yy
5.45 295y

Он показывает, что адрес 0xcc4fe480 взят из раздела, выделенного жирным шрифтом выше. Этот раздел не связан ни с каким файлом .so или bin.

Этот вопрос на самом деле связан с другим вопросом http://stackoverflow.com/questions/9564417/gdb-cant-insert-internal- точка останова, которая еще не разрешена. Я обнаружил эти проблемы во время исследования предыдущей проблемы.

У меня есть 3 вопроса:
1. Взгляните на вывод strace для ptrace здесь:
ptrace(PTRACE_PEEKTEXT, 651, 0xcc4fe480, [0x3ac706a4506fa1d]) = 0
Почему последний параметр заключен в квадратные скобки? Означает ли это, что он представляет возвращаемое значение? На странице руководства говорится, что ptrace должен возвращать слово, прочитанное для PTRACE_PEEKTEXT, но похоже, что вывод strace не следует этому, поэтому я подозреваю, что он показывает возвращаемое значение в последнем параметре.
2. Между двумя разделами есть раздел (кто выделен жирным шрифтом). .so, но не связанный с каким-либо инодом. Что представляет такой раздел?
3. Gdb читает одно слово из этого раздела и использует это слово как адрес, но на самом деле это недопустимый адрес. Каковы возможные причины такой ошибки?

Спасибо!


person Ma Vincent    schedule 10.03.2012    source источник


Ответы (2)


  1. Взгляните на вывод strace для ptrace здесь: ptrace(PTRACE_PEEKTEXT, 651, 0xcc4fe480, [0x3ac706a4506fa1d]) = 0 Почему последний параметр заключен в квадратные скобки? Означает ли это, что он представляет возвращаемое значение?

Правильный.

  1. Между двумя .so есть раздел (который выделен жирным шрифтом), но он не связан ни с одним inode. Что представляет собой такой раздел?

Это область памяти, которая была mmap отмечена флагом MAP_ANONYMOUNS (т. е. она не соответствует ни одному файлу на диске).

Поскольку размер этой области составляет ровно 1 МБ и поскольку она окружена частными областями, отображаемыми с помощью PROT_NONE, можно с уверенностью сказать, что эта область представляет некоторый стек потоков, окруженный зонами защиты стека.

  1. Gdb читает одно слово из этого раздела и использует это слово как адрес, но на самом деле это недопустимый адрес. Каковы возможные причины такой ошибки?

По какой-то причине GDB считает, что по адресу 0x3ac7068 должен быть код, и хочет разместить там внутреннюю точку останова. GDB использует внутренние точки останова для отслеживания загруженных разделяемых библиотек (среди прочего).

Вывод из maintenance info break должен показать, какой код, по мнению GDB, находится по "плохому" адресу.

person Employed Russian    schedule 11.03.2012

Я предполагаю, что ваш код переполняется и записывает действительный адрес, а gdb обращается к этой области памяти, ожидая адрес, но получая ненужные данные. Какой раздел кода вы пытаетесь отлаживать? Это может помочь нам.

person Marshall Conover    schedule 10.03.2012
comment
Я отлаживаю функцию в общей библиотеке (.so). Но это не одна из двух библиотек, перечисленных выше. Это говорит о том, что я отлаживаю библиотеку A, а gdb считывает недопустимый адрес из раздела между lib B и lib C. Вот почему это меня смущает. - person Ma Vincent; 10.03.2012