GDB теряется, когда указатель стека изменяется вручную

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

При запуске этого кода через GDB, после того как инициализация моего другого стека завершена и выполнение возвращается к вызывающей функции, GDB выдает мне это предупреждение:

warning: GDB can't find the start of the function at 0x12.

    GDB is unable to find the start of the function at 0x12
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0x12 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.

Кроме того, при печати $sp отображается старое значение.

Поскольку эта часть кода без GDB работает корректно, а по адресу 0x12 нет функции, это происходит потому, что GDB использует указатель стека для адресации, чтобы отслеживать кадр функции.

Есть ли способ избежать такого поведения и иметь возможность отлаживать это приложение?


person volpato    schedule 20.04.2012    source источник


Ответы (2)


Я думаю, вам нужен кадр GDB/Python раскручивание. Я никогда не использовал его сам, но раскручивание кадра - это (внутренний) процесс восстановления стека вызовов процесса.

Как вы упомянули, вы изменяете значение $SP, поэтому GDB не распознает стандартные соглашения о вызовах. Пользовательские разматыватели фреймов должны позволить вам научить GDB, какой макет стека вы используете.

Вот пример, который они предоставляют в документации:

 from gdb.unwinders import Unwinder

 class FrameId(object):
     def __init__(self, sp, pc):
         self.sp = sp
         self.pc = pc


 class MyUnwinder(Unwinder):
     def __init__(....):
         super(MyUnwinder, self).__init___(<expects unwinder name argument>)

     def __call__(pending_frame):
         if not <we recognize frame>:
             return None
         # Create UnwindInfo.  Usually the frame is identified by the stack
         # pointer and the program counter.
         sp = pending_frame.read_register(<SP number>)
         pc = pending_frame.read_register(<PC number>)
         unwind_info = pending_frame.create_unwind_info(FrameId(sp, pc))

         # Find the values of the registers in the caller's frame and
         # save them in the result:
         unwind_info.add_saved_register(<register>, <value>)
         ....

         # Return the result:
         return unwind_info

Согласно документации, вы можете получить доступ к регистрам процессора с помощью PendingFrame.read_register (reg_name or reg_id), но очевидно, что чтение локальных переменных может быть проблемой!

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

person Kevin    schedule 08.01.2016

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

Да, видимо да:

get_frame_id в gdb_reader_funcs должен вернуть gdb_frame_id, соответствующий текущему фрейму. [...] Один из способов сделать это - указать CODE_ADDRESS на первую инструкцию функции, а STACK_ADDRESS указать на значение указателя стека при входе в функцию.

Я предполагаю, что одним из способов исправить это было бы разделить ваш код на две разные функции (даже если вы просто прыгаете между ними).

person ysdx    schedule 08.01.2016