Как увидеть пошаговое выполнение каждой строки макрорасширения с помощью gdb

У меня есть макрос, определение которого выполняется примерно в 50 строк и содержит множество операторов "if else". Этот макрос def'n появляется в файле .h. Я запускаю 'gdb в режиме TUI', но когда выполнение достигает этого макроса, окно кода остается пустым и возвращается назад только после выполнения макрокода. Я хочу посмотреть, как выполняется построчный код макрокоманды. Пожалуйста, дайте мне знать, как это можно сделать (одним из способов является замена макроса его определением в коде, а затем его перекомпиляция. Я не хочу использовать этот параметр, поскольку в моем коде есть несколько таких макросов).

Любая помощь будет принята с благодарностью. с нетерпением ожидая решения этой проблемы. Пожалуйста, дайте мне знать, если есть какой-то другой способ для этой проблемы, а не использование предварительно обработанного файла? У меня есть код, который содержит несколько сотен файлов .c и .h.

Ответ 1

Один из вариантов - полностью препроцитировать ваш файл C, развернуть все макросы и затем скомпилировать полученный предварительно обработанный файл.

Например, рассмотрим эту простую программу на C:

// file: prep.c
#include <stdio.h>

#define MY_BIG_MACRO \
  int i; \
  printf("integers from 0 to 9:\n"); \
  for (i = 0; i < 10; i++) \
    printf("%d ", i); \
  printf("\n");

int main(void)
{
  MY_BIG_MACRO
  return 0;
}

Скомпилируйте его, сохранив временные файлы (включая предварительно обработанный исходный код):

gcc -Wall -O2 -g -std=c99 prep.c -o prep.exe -save-temps

Это должно дать вам предварительно обработанную версию prep.c, prep.i (сокращенную для краткости):

# 1 "prep.c"
# 1 "C:\\MinGW\\msys\\1.0\\home\\Alex//"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "prep.c"

# 1 "c:\\mingw\\bin\\../lib/gcc/mingw32/4.6.2/../../../../include/stdio.h" 1 3

...

int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) vswscanf (const wchar_t * __restrict__,
         const wchar_t * __restrict__, __gnuc_va_list);
# 3 "prep.c" 2
# 11 "prep.c"
int main(void)
{
  int i; printf("integers from 0 to 9:\n"); for (i = 0; i < 10; i++) printf("%d ", i); printf("\n");
  return 0;
}

Теперь вы хотите избавиться от # -lines. Так или иначе, если они останутся, они будут влиять на информацию об отладке. Удивительно, но это означает, что макрос не будет расширяться в gdb.

К счастью, grep может помочь (я не grep pro, поэтому проверьте правильность параметров, но они, похоже, работают для меня в Windows с MinGW x86):

grep ^[^\#].*$ prep.i > prepi.c

Это даст вам лишенную версию prep.i в prepi.c:

typedef unsigned int size_t;
typedef short unsigned int wchar_t;
typedef short unsigned int wint_t;

...

int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) vswscanf (const wchar_t * __restrict__,
         const wchar_t * __restrict__, __gnuc_va_list);
int main(void)
{
  int i; printf("integers from 0 to 9:\n"); for (i = 0; i < 10; i++) printf("%d ", i); printf("\n");
  return 0;
}

Теперь вы можете скомпилировать его:

gcc -Wall -O2 -g -std=c99 prepi.c -o prepi.exe

И запустите его в gdb:

gdb prepi.exe

Выполните следующие команды:

b main
r
l

Это выполнит приложение до main() и перечислит исходный код, связанный с достигнутой точкой останова:

(gdb) b main
Breakpoint 1 at 0x40643f: file prepi.c, line 184.
(gdb) r
Starting program: C:\MinGW\msys\1.0\home\Alex\prepi.exe
[New Thread 7340.0x20c4]

Breakpoint 1, main () at prepi.c:184
184       int i; printf("integers from 0 to 9:\n"); for (i = 0; i < 10; i++) pri
ntf("%d ", i); printf("\n");
(gdb) l
179              const wchar_t * __restrict__, __gnuc_va_list);
180     int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) vswscanf (c
onst wchar_t * __restrict__,
181              const wchar_t * __restrict__, __gnuc_va_list);
182     int main(void)
183     {
184       int i; printf("integers from 0 to 9:\n"); for (i = 0; i < 10; i++) pri
ntf("%d ", i); printf("\n");
185       return 0;
186     }
(gdb)

Как вы можете видеть, тело макроса теперь находится в простом виде.

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

Ответ 2

"В макросы не просто step.

У вас все еще есть несколько вариантов:

  • Используйте препроцессор, как рекомендовал @WhozCraig.
  • Для немного меньше раздувания кода, конвертируйте свои макросы в функции и перекомпилируйте.
  • Если вы абсолютно не хотите перекомпилировать, и вам удобнее использовать код сборки, вы можете использовать stepi для выполнения вашей макрокоманды по одной машинной инструкции за раз.

Ответ 3

Если все вышеперечисленное не работает, действительно, вы должны вернуться к использованию printf/fprintf в своем большом макросе.

Мне пришлось иметь дело с 300-строчным MACRO, погруженным в глубь библиотеки. Это было проще, чем компиляция вручную и обработка файлов после обработки.