Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to see step by step execution of each line of a macro expansion using gdb

Tags:

c

linux

gdb

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).

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.

like image 720
mezda Avatar asked Oct 02 '12 07:10

mezda


People also ask

How do I execute a line in gdb?

To execute one line of code, type "step" or "s". If the line to be executed is a function call, gdb will step into that function and start executing its code one line at a time. If you want to execute the entire function with one keypress, type "next" or "n".

What is the GDB step over command?

This is equivalent to the "step over" command of most debuggers. If you want gdb to resume normal execution, type "continue" or "c". gdb will run until your program ends, your program crashes, or gdb encounters a breakpoint.

How do I run GDB in Linux?

Run gdb with the generated executable. Here are few useful commands to get started with gdb for the above example:- run or r –> executes the program from start to end. break or b –> sets breakpoint on a particular line.

How do I run a macro from a single step?

On the Design tab, in the Tools group, click Single Step. Click Run. If the macro is a new or edited macro, you will be prompted to save the macro before you can run it.


Video Answer


3 Answers

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

For example, consider this simple C program:

// 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):

# 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.

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 ^[^\#].*$ prep.i > prepi.c

This will give you a stripped version of prep.i in 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;
}

Now you can compile it:

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

And run it in 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:

(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.

like image 196
Alexey Frunze Avatar answered Oct 20 '22 05:10

Alexey Frunze


"One does not simply step into macros."

You still have a few options:

  1. Use the preprocessor, as @WhozCraig recommended.
  2. For a little less code bloat, convert your macros to functions and re-compile.
  3. 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.
like image 21
Eran Avatar answered Oct 20 '22 05:10

Eran


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

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.

like image 1
malat Avatar answered Oct 20 '22 07:10

malat