Инструменты для визуализации «стека» в сборке

#assembly #gdb #x86-64 #callstack

#сборка #gdb #x86-64 #callstack

Вопрос:

Есть ли какие-либо способы увидеть, какие значения помещаются в стек простым, предпочтительно визуальным способом? В настоящее время я использую gdb для отладки, но мне было интересно, существуют ли какие-либо другие программы (или, возможно, даже gdb в другом режиме), чтобы иметь представление о том, как выглядит стек, когда я выполняю каждую инструкцию, например, в этой программе:

 .globl main
main:
    push %rbp
    mov %rsp, %rbp
    movb $8, -1(%rbp)
    movw $30, -4(%rbp)
    mov -1(%rbp), %rax
    add -4(%rbp), %rax
  

Я знаю, что в gdb есть x/8xw $rbp или их варианты, но я хотел бы рассматривать это почти как анимацию или постоянную визуализацию при пошаговом просмотре кода. Есть ли способ сделать это?

Ответ №1:

display Нужно что-то печатать каждый раз, когда GDB останавливается, например

 display /x (long [8])*(long*)$rsp
  

чтобы получать такой вывод после каждого шага. (Это из _start , поэтому RSP указывает на argc (0x1), затем argv[0] (указатель), затем argv[1] (NULL), затем envp[0] и т.д.)

 {0x1, 0x7fffffffea02, 0x0, 0x7fffffffea0e, 0x7fffffffea1e, 0x7fffffffea6c, 0x7fffffffea7e, 0x7fffffffea92}
  

Выражение приведения GDB работает путем разыменования $rsp (указателя стека) как единого long , затем преобразуя его в массив long . Это, конечно, на самом деле не сработало бы на C, но выражения GDB используют только C-подобный синтаксис, они не являются правильными C. Возможно, есть более простой способ написать это, но это то, к чему я пришел методом проб и ошибок.

При этом qwords будут отображаться в порядке возрастания адреса памяти, начиная с того, на который указывает RSP, поэтому оно изменится, например, после call или push . Если вы хотите видеть RSP ниже, в красной зоне, используйте другую базу, например ($rsp-16) или что-то в этом роде.


Если вы хотите просмотреть фрейм стека вашей функции ниже RBP, который не перемещается при нажатии / всплывании, вам может понадобиться база, подобная ($rbp - 16) или что-то в этом роде.

Конечно, ваша x/8xw $rbp команда не показывает вам никакой памяти, в которую хранятся ваши инструкции, потому что вы сохраняете ее ниже RBP = RSP. (На самом деле это гарантированно безопасно в системе x86-64 V ABI, которая имеет красную зону. Во многих других соглашениях о вызовах это может быть асинхронно выполнено обработчиком сигналов или отладчиком, оценивающим, print foo(1) где foo находится функция в вашей программе.)