如何使用gdb逐步执行宏扩展的每一行

时间:2022-07-10 16:41:29

i am having a macro whose definition runs into around 50 lines and has lot of 'if else' statements. This macro def'n appears in a .h file. I am running 'gdb in TUI mode', but when the execution reaches that macro, the code window goes blank and returns back only after the macro code gets executed. I want to see line by line execution of the full macro code. Please let me know how can that be done (one way is to replace the macro with its definition in the code and then recompile it. i don't want to use this option as there are several such macros in my code).

我有一个宏,它的定义大约有50行,并且有很多if else语句。这个宏def出现在.h文件中。我正在TUI模式下运行“gdb”,但是当执行到达该宏时,代码窗口将为空,只有在执行宏代码之后才能返回。我希望看到完整的宏代码逐行执行。请让我知道怎么做(一种方法是用代码中的定义替换宏,然后重新编译它。我不想使用这个选项,因为在我的代码中有几个这样的宏)。

Any help will be greatly appreciated. looking forward to get the solution for this problem. Please let me know if there is some other way for this issue rather than the usage of preprocessed file ? i am having a code which runs into several hundred .c & .h files.

如有任何帮助,我们将不胜感激。期待解决这个问题。请让我知道这个问题是否有其他方法而不是使用预处理文件?我有一个代码,它运行到几百个。c和。h文件中。

3 个解决方案

#1


11  

One option is to fully preprocess your C file, expanding all macros in it, and then compile the resulting preprocessed file.

一个选项是对C文件进行完全预处理,展开其中的所有宏,然后编译得到的预处理文件。

For example, consider this simple C program:

例如,考虑这个简单的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;
}

Compile it, saving the temporary files (including the preprocessed source code):

编译它,保存临时文件(包括预处理的源代码):

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

This should give you a preprocessed version of prep.c, prep.i (shortened for brevity):

这将为您提供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;
}

Now you want to get rid of the #-lines. One way or another, if they are left in, they will affect the debug info. Surprisingly, that means that the macro won't appear expanded in gdb.

现在您想要删除#-lines。无论如何,如果它们被保留,它们将影响调试信息。令人惊讶的是,这意味着宏不会出现在gdb中展开。

Thankfully, grep can help (I'm not a grep pro, so check whether the params are correct, but they seem to work for me on Windows with MinGW x86):

幸运的是,grep可以帮助(我不是grep pro,所以检查一下params是否正确,但是它们似乎在Windows和mingwx86上为我工作):

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

This will give you a stripped version of prep.i in prepi.c:

这将为您提供prepi. i的简化版本。

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;
}

Now you can compile it:

现在你可以编译它:

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

And run it in gdb:

在gdb中运行:

gdb prepi.exe

Issue the following commands:

发出以下命令:

b main
r
l

This will execute the app until main() and list the source code related to the reached breakpoint:

这将执行app直到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)

As you can see, the macro body is now in the plain view.

正如您所看到的,宏主体现在在普通视图中。

One small problem here is that multi-line macros (those continued with \) are expanded into a single line. I haven't found an option to expand them into multiple lines, but you can do that manually.

这里的一个小问题是,多行宏(那些继续使用\)被扩展成一行。我还没有找到将它们扩展成多行的选项,但是您可以手动执行。

#2


4  

"One does not simply step into macros."

“我们不能简单地进入宏。”

You still have a few options:

你还有一些选择:

  1. Use the preprocessor, as @WhozCraig recommended.
  2. 使用预处理器,如@WhozCraig推荐的那样。
  3. For a little less code bloat, convert your macros to functions and re-compile.
  4. 为了减少代码膨胀,将宏转换为函数并重新编译。
  5. If you absolutely don't want to recompile and you're comfortable with assembly code you can use stepi to execute your macro one machine instruction at a time.
  6. 如果您绝对不想重新编译并且对汇编代码很满意,那么您可以使用stepi一次执行宏1个机器指令。

#3


1  

If all the above does not work, really you should go back to using printf/fprintf within your large macro.

如果上述方法都不起作用,那么您应该回到在大型宏中使用printf/fprintf。

I had to deal with a 300 lines MACRO, burried deep into the library. This was easier than compiling by hand and dealing with post-processed files.

我必须处理一个300行宏,深入到库中。这比手工编译和处理后处理文件更容易。

#1


11  

One option is to fully preprocess your C file, expanding all macros in it, and then compile the resulting preprocessed file.

一个选项是对C文件进行完全预处理,展开其中的所有宏,然后编译得到的预处理文件。

For example, consider this simple C program:

例如,考虑这个简单的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;
}

Compile it, saving the temporary files (including the preprocessed source code):

编译它,保存临时文件(包括预处理的源代码):

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

This should give you a preprocessed version of prep.c, prep.i (shortened for brevity):

这将为您提供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;
}

Now you want to get rid of the #-lines. One way or another, if they are left in, they will affect the debug info. Surprisingly, that means that the macro won't appear expanded in gdb.

现在您想要删除#-lines。无论如何,如果它们被保留,它们将影响调试信息。令人惊讶的是,这意味着宏不会出现在gdb中展开。

Thankfully, grep can help (I'm not a grep pro, so check whether the params are correct, but they seem to work for me on Windows with MinGW x86):

幸运的是,grep可以帮助(我不是grep pro,所以检查一下params是否正确,但是它们似乎在Windows和mingwx86上为我工作):

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

This will give you a stripped version of prep.i in prepi.c:

这将为您提供prepi. i的简化版本。

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;
}

Now you can compile it:

现在你可以编译它:

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

And run it in gdb:

在gdb中运行:

gdb prepi.exe

Issue the following commands:

发出以下命令:

b main
r
l

This will execute the app until main() and list the source code related to the reached breakpoint:

这将执行app直到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)

As you can see, the macro body is now in the plain view.

正如您所看到的,宏主体现在在普通视图中。

One small problem here is that multi-line macros (those continued with \) are expanded into a single line. I haven't found an option to expand them into multiple lines, but you can do that manually.

这里的一个小问题是,多行宏(那些继续使用\)被扩展成一行。我还没有找到将它们扩展成多行的选项,但是您可以手动执行。

#2


4  

"One does not simply step into macros."

“我们不能简单地进入宏。”

You still have a few options:

你还有一些选择:

  1. Use the preprocessor, as @WhozCraig recommended.
  2. 使用预处理器,如@WhozCraig推荐的那样。
  3. For a little less code bloat, convert your macros to functions and re-compile.
  4. 为了减少代码膨胀,将宏转换为函数并重新编译。
  5. If you absolutely don't want to recompile and you're comfortable with assembly code you can use stepi to execute your macro one machine instruction at a time.
  6. 如果您绝对不想重新编译并且对汇编代码很满意,那么您可以使用stepi一次执行宏1个机器指令。

#3


1  

If all the above does not work, really you should go back to using printf/fprintf within your large macro.

如果上述方法都不起作用,那么您应该回到在大型宏中使用printf/fprintf。

I had to deal with a 300 lines MACRO, burried deep into the library. This was easier than compiling by hand and dealing with post-processed files.

我必须处理一个300行宏,深入到库中。这比手工编译和处理后处理文件更容易。