当前位置:   article > 正文

ARM GDB调试器常用命令用法解析_arm-gdb

arm-gdb

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,GDB主要可帮助工程师完成下面4个方面的功能:

  • 启动程序,可以按照工程师自定义的要求随心所欲的运行程序。
  • 让被调试的程序在工程师指定的断点处停住,断点可以是条件表达式。
  • 当程序被停住时,可以检查此时程序中所发生的事,并追索上文。
  • 动态地改变程序的执行环境。

我这里讲述的是GNU Arm Embedded GCC里的GDB调试器。GNU Arm Embedded GCC由xPack论坛提供,支持多个系统安装包括(Windows/macOS/GNU/Linux)。相关Release版本获取,大家可以去The xPack GNU Arm Embedded GCC releases | The xPack Build Framework下载相应的版本。

常用调试命令

GDB 的主要功能就是监控程序的执行流程。这也就意味着,只有当源程序文件编译为可执行文件并执行时,并且该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等),GDB才会派上用场。

所以在编译时需要使用 gcc/g++ -g 选项编译源文件,才可生成满足 GDB 要求的可执行文件

帮助信息与基本信息命令

CommandDescription
help <command>Command description. eg help show to list the show commands
info breakpoints/b/breakList breakpoints
info break <breakpoint-number>List info about specific breakpoint.
info registers/rList registers in use

help <command> 命令

在gdb中运行help命令(缩写h)可以查询相关命令使用方法。

  1. (gdb) help list
  2. list, l
  3. List specified function or line.
  4. With no argument, lists ten more lines after or around previous listing.
  5. "list -" lists the ten lines before a previous ten-line listing.
  6. One argument specifies a line, and ten lines are listed around that line.
  7. Two arguments with comma between specify starting and ending lines to list.
  8. Lines can be specified in these ways:
  9. LINENUM, to list around that line in current file,
  10. FILE:LINENUM, to list around that line in that file,
  11. FUNCTION, to list around beginning of that function,
  12. FILE:FUNCTION, to distinguish among like-named static functions.
  13. *ADDRESS, to list around the line containing that address.
  14. With two args, if one is empty, it stands for ten lines away from
  15. the other arg.
  16. By default, when a single location is given, display ten lines.
  17. This can be changed using "set listsize", and the current value
  18. can be shown using "show listsize".

info <args> 命令

在gdb中运行info命令(缩写i)可以查询相关断点或者MCU/CPU registers使用信息。

  1. (gdb) info register # info r / i r
  2. r0 0x0 0
  3. r1 0x20 32
  4. r2 0xa 10
  5. r3 0x3 3
  6. r4 0x20000364 536871780
  7. r5 0x3f 63
  8. r6 0x20003d08 536886536
  9. r7 0x20007fb0 536903600
  10. r8 0x20000010 536870928
  11. r9 0x0 0
  12. r10 0x20001200 536875520
  13. r11 0x1 1
  14. r12 0x800bda5 134266277
  15. sp 0x20007fb0 0x20007fb0
  16. lr 0x8003ab7 134232759
  17. pc 0x8011172 0x8011172 <main+6>
  18. xpsr 0x2100000f 553648143
  19. msp 0x20007fb0 536903600
  20. psp 0x20001120 536875296
  21. primask 0x0 0
  22. basepri 0xbe 190
  23. faultmask 0x0 0
  24. control 0x0 0
  25. (gdb) info breakpoints # info b / i b
  26. Num Type Disp Enb Address What
  27. 1 breakpoint keep y 0x0800144c Device/Source/ARM/startup_ac78xx.s:91
  28. breakpoint already hit 1 time
  29. 2 breakpoint keep y 0x08011172 in main at App/main.c:70
  30. breakpoint already hit 1 time
  31. 3 breakpoint keep y 0x08004622 in Show_CPU_Type
  32. at Bios/hw_init.c:173
  33. breakpoint already hit 1 time
  34. (gdb) info b 3
  35. Num Type Disp Enb Address What
  36. 3 breakpoint keep y 0x08004622 in Show_CPU_Type
  37. at Bios/hw_init.c:173
  38. breakpoint already hit 1 time

断点与查看命令

Break and Watch
break funtion-name break line-number break ClassName::functionNameSuspend program at specified function of line number.
break +offset break -offsetSet a breakpoint specified number of lines forward or back from the position at which execution stopped.
break filename:functionDon't specify path, just the file name and function name.
break filename:line-numberDon't specify path, just the file name and line number. break Directory/Path/filename.cpp:62
break *addressSuspend processing at an instruction address. Used when you do not have source.
break line-number if conditionWhere condition is an expression. i.e. x > 5 Suspend when boolean expression is true.
watch conditionSuspend processing when condition is met. i.e. x > 5
clear clear function clear line-numberDelete breakpoints as identified by command option. Delete all breakpoints in function Delete breakpoints at a given line
delete dDelete all breakpoints, watchpoints, or catchpoints.
delete breakpoint-number delete rangeDelete the breakpoints, watchpoints, or catchpoints of the breakpoint ranges specified as arguments.
disable breakpoint-number-or-range enable breakpoint-number-or-rangeDoes not delete breakpoints. Just enables/disables them. Example: Show breakpoints: info break Disable: disable 2-9
continue cContinue executing until next break point/watchpoint.
continue numberContinue but ignore current breakpoint number times. Usefull for breakpoints within a loop.
finishContinue to end of function.

break命令

在gdb中用break命令(缩写b)来设置断点,设置断点的方法包括:

break <function> 在进入指定函数时停住,C++中可以使用class::function或function(type, type)格式来指定函数名。

  1. (gdb) b main
  2. Breakpoint 2 at 0x8011172: file App/main.c, line 70.
  3. Thread 2 hit Breakpoint 2, main () at App/main.c:70
  4. 70 CPU_Init();
  5. (gdb) l
  6. 65 * @brief main function
  7. 66 *
  8. 67 */
  9. 68 int main(void)
  10. 69 {
  11. 70 CPU_Init();
  12. 71
  13. 72 CPU_Running = 0x00;

break <linenum> 在指定行号停住。

  1. (gdb) b 81
  2. Reading 64 bytes @ address 0x08011140
  3. Read 2 bytes @ address 0x08011182 (Data = 0xF7F8)
  4. Breakpoint 3 at 0x8011182: file App/main.c, line 81.

break +offset / break -offset 在当前行号的前面或后面的offset行停住,offiset为自然数。

break filename:linenum 在源文件filename的linenum行处停住。

  1. (gdb) b interprt.c:630
  2. Reading 64 bytes @ address 0x08005440
  3. Read 4 bytes @ address 0x08005700 (Data = 0x20000BB8)
  4. Read 2 bytes @ address 0x080056B0 (Data = 0xF008)
  5. Breakpoint 6 at 0x80056b0: file Bios/interprt.c, line 630.

break filename:function 在源文件filename的function函数的入口处停住。

  1. (gdb) b interprt.c:interpreter
  2. Read 4 bytes @ address 0x08005700 (Data = 0x20000BB8)
  3. Read 2 bytes @ address 0x08005450 (Data = 0x4BAB)
  4. Breakpoint 7 at 0x8005450: file Bios/interprt.c, line 590.

break *address 在程序运行的内存地址处停住。

break break命令没有参数时,表示在下一条指令处停住。

break ... if <condition> “...”可以是上述的break <linenum>、break +offset / break –offset中的参数,condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100,表示当i为100时停住程序。

查看断点时,可使用info命令,如info breakpoints [n]、info break [n](n表示断点号)。

watch命令

watch一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。我们有下面的几种方法来设置观察点: watch <expr>:为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。rwatch <expr>:当表达式(变量)expr被读时,停住程序。awatch <expr>:当表达式(变量)的值被读或被写时,停住程序。info watchpoints:列出当前所设置了的所有观察点。 下面演示了观察i并在连续运行next时一旦发现i变化,i值就会显示出来的过程:

  1. (gdb) watch i
  2. Hardware watchpoint 3: i
  3. (gdb) next
  4. 23 for (i = 0; i < 10; i++)
  5. (gdb) next
  6. Hardware watchpoint 3: i
  7. Old value = 0
  8. New value = 1
  9. 0x0804838d in main () at gdb_example.c:23
  10. 23 for (i = 0; i < 10; i++)
  11. (gdb) next
  12. Breakpoint 1, main () at gdb_example.c:25
  13. 25 sum[i] = add(array1[i], array2[i]);
  14. (gdb) next
  15. 23 for (i = 0; i < 10; i++)
  16. (gdb) next
  17. Hardware watchpoint 3: i
  18. Old value = 1
  19. New value = 2
  20. 0x0804838d in main () at gdb_example.c:23
  21. 23 for (i = 0; i < 10; i++)

continue命令

当程序被停住后,可以使用continue命令(缩写c,fg命令同continue命令)恢复程序的运行直到程序结束,或到达下一个断点,命令格式为:

  1. continue [ignore-count]
  2. c [ignore-count]
  3. fg [ignore-count]

ignore-count表示忽略其后多少次断点。 假设我们设置了函数断点add(),并watch i,则在continue过程中,每次遇到add()函数或i发生变化,程序就会停住,如:

  1. (gdb) continue
  2. Continuing.
  3. Hardware watchpoint 3: i
  4. Old value = 2
  5. New value = 3
  6. 0x0804838d in main () at gdb_example.c:23
  7. 23 for (i = 0; i < 10; i++)
  8. (gdb) continue
  9. Continuing.
  10. Breakpoint 1, main () at gdb_example.c:25
  11. 25 sum[i] = add(array1[i], array2[i]);
  12. (gdb) continue
  13. Continuing.
  14. Hardware watchpoint 3: i
  15. Old value = 3
  16. New value = 4
  17. 0x0804838d in main () at gdb_example.c:23
  18. 23 for (i = 0; i < 10; i++)

finish命令

运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。

  1. Breakpoint 4, CPU_Init () at Bios/hw_init.c:71 #断点在CPU_Init
  2. 71 disable_WDOG();
  3. (gdb) finish
  4. Read 4 bytes @ address 0x08011176 (Data = 0x22004B54)
  5. Run till exit from #0 CPU_Init () at Bios/hw_init.c:71
  6. Read 2 bytes @ address 0x08011176 (Data = 0x4B54)
  7. Setting breakpoint @ address 0x0800144C, Size = 2, BPHandle = 0x0009
  8. Setting breakpoint @ address 0x08011172, Size = 2, BPHandle = 0x000A
  9. Setting breakpoint @ address 0x08011176, Size = 2, BPHandle = 0x000B
  10. Setting breakpoint @ address 0x0801128C, Size = 2, BPHandle = 0x000C
  11. Setting breakpoint @ address 0x08017EF4, Size = 2, BPHandle = 0x000D
  12. Performing single step...
  13. ...Breakpoint reached @ address 0x0800457C
  14. Reading all registers
  15. Setting breakpoint @ address 0x0800458C, Size = 2, BPHandle = 0x000E
  16. Starting target CPU...
  17. ...Breakpoint reached @ address 0x08011176
  18. Reading all registers
  19. Read 4 bytes @ address 0x08011176 (Data = 0x22004B54)
  20. Reading 64 bytes @ address 0x20007FC0
  21. Removing breakpoint @ address 0x08011176, Size = 2
  22. Removing breakpoint @ address 0x08017EF4, Size = 2
  23. Removing breakpoint @ address 0x0800144C, Size = 2
  24. Removing breakpoint @ address 0x0800458C, Size = 2
  25. Removing breakpoint @ address 0x08011172, Size = 2
  26. Removing breakpoint @ address 0x0801128C, Size = 2
  27. Read 4 bytes @ address 0x08011176 (Data = 0x22004B54)
  28. main () at App/main.c:72
  29. 72 CPU_Running = 0x00;
  30. (gdb)

单步命令

Line Execution
step s step number-of-steps-to-performStep to next line of code. Will step into a function.
next n next numberExecute next line of code. Will not enter functions.
until until line-numberContinue processing until you reach a specified line number. Also: function name, address, filename:function or filename:line-number.
Machine Language
info line info line numberDisplays the start and end position in object code for the current line in source. Display position in object code for a specified line in source.
disassemble 0xstart 0xendDisplays machine code for positions in object code specified (can use start and end hex memory values given by the info line command.
stepi si nexti nistep/next assembly/processor instruction.
0xaddress x/nfu 0xaddressExamine the contents of memory. Examine the contents of memory and specify formatting. n: number of display items to print f: specify the format for the output u: specify the size of the data unit (eg. byte, word, ...) Example: x/4dw var

在调试过程中,next命令用于单步执行,类似VC++中的step over。next的单步不会进入函数的内部,与next对应的step(缩写s)命令则在单步执行一个函数时,会进入其内部,类似VC++中的step into。下面演示了step命令的执行情况,在23行的add()函数调用处执行step会进入其内部的“return a+b;”语句:

  1. (gdb) break 25
  2. Breakpoint 1 at 0x8048362: file gdb_example.c, line 25.
  3. (gdb) run
  4. Starting program: /driver_study/gdb_example
  5. Breakpoint 1, main () at gdb_example.c:25
  6. 25 sum[i] = add(array1[i], array2[i]);
  7. (gdb) step
  8. add (a=48, b=85) at gdb_example.c:3
  9. 3 return a + b;

单步执行的更复杂用法包括:

step命令

当程序被停住后,可以使用step命令单步跟踪(缩写s)。单步跟踪,如果有函数调用,则***进入该函数***(进入函数的前提是,此函数被编译有debug信息)。step后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。

  1. Breakpoint 5, main () at App/main.c:84
  2. 84 msgScript(AUTORUNSCRIPT, 0, 200);
  3. (gdb) info line
  4. Line 84 of "App/main.c" starts at address 0x8011186 <main+26>
  5. and ends at 0x8011192 <main+38>.
  6. (gdb) l # 查看main函数断点在84
  7. 79
  8. 80 // start default mbc channels
  9. 81 Init_Gateway_Standard();
  10. 82
  11. 83 #if (SW_SCRIPT == 1)
  12. 84 msgScript(AUTORUNSCRIPT, 0, 200);
  13. 85
  14. 86 // run msgPoll till both autorun are executed; force broadcast to all known interfaces
  15. 87 while (msgPoll(true))
  16. 88 {};
  17. (gdb) l msgScript #查看 msgScript 函数内容
  18. 1515 //--------------------------------------------------------------------------------------------------------
  19. 1516 // Input:
  20. 1517 // Output: none
  21. 1518 //********************************************************************************************************
  22. 1519 unsigned msgScript(uint32_t auto_packet, uint32_t auto_flash, uint32_t auto_delay)
  23. 1520 {
  24. 1521 static unsigned state = S_INIT;
  25. 1522 static unsigned cnt = 0;
  26. 1523 static uint32_t time;
  27. 1524 static uint32_t script;
  28. (gdb) l
  29. 1525 static uint32_t script_next;
  30. 1526 static uint32_t script_delay;
  31. 1527 unsigned error;
  32. 1528
  33. 1529 switch (state)
  34. 1530 {
  35. 1531 case S_INIT: // init
  36. 1532 script = auto_packet;
  37. 1533 script_next = auto_flash;
  38. 1534 script_delay = auto_delay;
  39. (gdb)
  40. (gdb) s # 单步调试进入 msgScript函数
  41. Setting breakpoint @ address 0x08017EF4, Size = 2, BPHandle = 0x001C
  42. Performing single step...
  43. ...Breakpoint reached @ address 0x08011188
  44. Reading all registers
  45. ......
  46. ......
  47. msgScript (auto_packet=134331756, auto_flash=0, auto_delay=200)
  48. at Bios/comm_mbc.c:1529
  49. 1529 switch (state) #停在msgScript函数的第一条代码

next命令

当程序被停住后,可以使用next命令单步跟踪(缩写n)。单步跟踪,如果有函数调用,不会进入该函数。同样地,next后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。

  1. (gdb) l 117 #显示当前函数执行位置内容
  2. 113 hprintf(" Built on %s at %s.\n", __DATE__, __TIME__);
  3. 114 hprintf(" Startaddress : 0x%08lX\n", BiosVersionInfo.Programstart);
  4. 115 hprintf(" CPU Clock : %dHz\n", __SYSTEM_CLOCK);
  5. 116
  6. 117 Show_CPU_Type(1);
  7. 118 hprintf("\n");
  8. 119
  9. 120 ADCDrv_Init();
  10. (gdb)
  11. (gdb) n # 单步调试,跟踪下一行
  12. Setting breakpoint @ address 0x08011186, Size = 2, BPHandle = 0x0023
  13. ......
  14. ......
  15. Read 4 bytes @ address 0x08011260 (Data = 0xF7F9481B)
  16. 118 hprintf("\n");
  17. (gdb) n # 单步调试,跟踪下一行
  18. Setting breakpoint @ address 0x08011186, Size = 2, BPHandle = 0x0027
  19. ......
  20. ......
  21. Read 4 bytes @ address 0x08011266 (Data = 0xFC49F7F9)
  22. 121 ADCDrv_Init();
  23. (gdb)

until命令

一直在循环体内执行单步,退不出来是一件令人烦恼的事情,until命令可以运行程序直到退出循环体。

  1. Breakpoint 3, Get_Portproperties (channel=3 '\003',
  2. port_isvalid_mask=0x20007f80, port_isgpio_mask=0x20007f7c)
  3. at Bios/port.c:86
  4. 86 *port_isgpio_mask = 0x00000000;
  5. (gdb) l
  6. 81 // but may be configured as alternate function
  7. 82 *port_isvalid_mask = (uint32_t)(((uint32_t)1 << productinfo[Cputype].portn_pin_count[channel]) -1);
  8. 83
  9. 84 // create info on gpio function
  10. 85 // every bitnumber is portpin, which is configured as gpio
  11. 87 for (i=0; i < GPIO_ONE_GROUP_NUM; i++)
  12. 88 { // scan all bits
  13. 89 if ((*port_isvalid_mask & (0x00000001 << i)) != 0)
  14. 90 { // portpin is existing, now additional check wether configured as gpio
  15. 91
  16. 92 if ((GPIO_GetPinFunc(channel*GPIO_ONE_GROUP_NUM + i)) == 0)
  17. 93 { // mark portpin as gpio pin
  18. 94 *port_isgpio_mask |= 0x00000001 << i;
  19. 95 }
  20. 96 }
  21. 97 }
  22. 98
  23. 99 return (TRUE);
  24. 100 }
  25. (gdb) until 99 #直到停在Bios/port.c的99
  26. Reading 64 bytes @ address 0x0800D580
  27. Read 2 bytes @ address 0x0800DE10 (Data = 0x4603)
  28. Read 2 bytes @ address 0x0800D630 (Data = 0x2301)
  29. ......
  30. ......
  31. Read 4 bytes @ address 0x0800D630 (Data = 0x46182301)
  32. Read 4 bytes @ address 0x0800DE10 (Data = 0xF0834603)
  33. Reading 64 bytes @ address 0x20007F80
  34. Get_Portproperties (channel=3 '\003', port_isvalid_mask=0x20007f80,
  35. port_isgpio_mask=0x20007f7c) at Bios/port.c:99
  36. 99 return (TRUE);

stepi和nexti命令

stepi和nexti用于单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。 另外,运行“display/i $pc”命令后,单步跟踪会在打出程序代码的同时打出机器指令,即汇编代码。

  1. (gdb) display/i $pc # 单步跟踪打出程序汇编代码
  2. Reading 64 bytes @ address 0x0800D600
  3. 1: x/i $pc
  4. => 0x800d630 <Get_Portproperties+180>: movs r3, #1
  5. (gdb) si # 单步执行机器指令
  6. Setting breakpoint @ address 0x0800D5E0, Size = 2, BPHandle = 0x000C
  7. Setting breakpoint @ address 0x08011172, Size = 2, BPHandle = 0x000D
  8. Performing single step...
  9. ...Breakpoint reached @ address 0x0800D634
  10. Reading all registers
  11. Read 4 bytes @ address 0x0800D634 (Data = 0x46BD3718)
  12. Reading 64 bytes @ address 0x20007F40
  13. Removing breakpoint @ address 0x0800D5E0, Size = 2
  14. Removing breakpoint @ address 0x08011172, Size = 2
  15. Read 4 bytes @ address 0x0800D634 (Data = 0x46BD3718)
  16. 0x0800d634 100 }
  17. Reading 64 bytes @ address 0x0800D600
  18. 1: x/i $pc
  19. => 0x800d634 <Get_Portproperties+184>: adds r7, #24
  20. (gdb) ni # 单步执行机器指令
  21. Setting breakpoint @ address 0x0800D5E0, Size = 2, BPHandle = 0x000E
  22. Setting breakpoint @ address 0x08011172, Size = 2, BPHandle = 0x000F
  23. Setting breakpoint @ address 0x08017EF4, Size = 2, BPHandle = 0x0010
  24. Performing single step...
  25. ...Breakpoint reached @ address 0x0800D636
  26. Reading all registers
  27. Read 4 bytes @ address 0x0800D636 (Data = 0xBD8046BD)
  28. Reading 64 bytes @ address 0x20007F40
  29. Removing breakpoint @ address 0x08017EF4, Size = 2
  30. Removing breakpoint @ address 0x0800D5E0, Size = 2
  31. Removing breakpoint @ address 0x08011172, Size = 2
  32. Read 4 bytes @ address 0x0800D636 (Data = 0xBD8046BD)
  33. 0x0800d636 100 }
  34. Reading 64 bytes @ address 0x0800D600
  35. 1: x/i $pc
  36. => 0x800d636 <Get_Portproperties+186>: mov sp, r7
  37. (gdb)

源码查看指令

Source Code
list l list line-number list function list - list start#,end# list filename:functionList source code.

list命令

在gdb中运行list命令(缩写l)可以列出代码,list的具体形式包括:

list <linenum> ,显示程序第linenum行周围的源程序,如:

  1. (gdb) list 15
  2. 10
  3. 11 int array1[10] =
  4. 12 {
  5. 13 48, 56, 77, 33, 33, 11, 226, 544, 78, 90
  6. 14 };
  7. 15 int array2[10] =
  8. 16 {
  9. 17 85, 99, 66, 0x199, 393, 11, 1, 2, 3, 4
  10. 18 };
  11. 19

list <function> ,显示函数名为function的函数的源程序,如:

  1. (gdb) list main
  2. 2 {
  3. 3 return a + b;
  4. 4 }
  5. 5
  6. 6 main()
  7. 7 {
  8. 8 int sum[10];
  9. 9 int i;
  10. 10
  11. 11 int array1[10] =
  • list,显示当前行后面的源程序。
  • list - ,显示当前行前面的源程序。

下面演示了使用gdb中的run(缩写r)、break(缩写b)、next(缩写n)命令控制程序的运行,并使用print(缩写p)命令打印程序中的变量sum的过程:

  1. (gdb) break add
  2. Breakpoint 1 at 0x80482f7: file gdb_example.c, line 3.
  3. (gdb) run
  4. Starting program: /driver_study/gdb_example
  5. Breakpoint 1, add (a=48, b=85) at gdb_example.c:3
  6. warning: Source file is more recent than executable.
  7. 3 return a + b;
  8. (gdb) next
  9. 4 }
  10. (gdb) next
  11. main () at gdb_example.c:23
  12. 23 for (i = 0; i < 10; i++)
  13. (gdb) next
  14. 25 sum[i] = add(array1[i], array2[i]);
  15. (gdb) print sum
  16. $1 = {133, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  17. gdb) break add
  18. Breakpoint 1 at 0x80482f7: file gdb_example.c, line 3.
  19. (gdb) run
  20. Starting program: /driver_study/gdb_example
  21. Breakpoint 1, add (a=48, b=85) at gdb_example.c:3
  22. warning: Source file is more recent than executable.
  23. 3 return a + b;
  24. (gdb) next
  25. 4 }
  26. (gdb) next
  27. main () at gdb_example.c:23
  28. 23 for (i = 0; i < 10; i++)
  29. (gdb) next
  30. 25 sum[i] = add(array1[i], array2[i]);
  31. (gdb) print sum
  32. $1 = {133, 0, 0, 0, 0, 0, 0, 0, 0, 0}

查看变量命令

Examine Variables
print variable-name p variable-name p file-name::variable-name p 'file-name'::variable-namePrint value stored in variable.
p *array-variable@lengthPrint first # values of array specified by length. Good for pointers to dynamicaly allocated memory.
p/x variablePrint as integer variable in hex.
p/d variablePrint variable as a signed integer.
p/u variablePrint variable as a un-signed integer.
p/o variablePrint variable as a octal.
p/t variable x/b address x/b &variablePrint as integer value in binary. (1 byte/8bits)
p/c variablePrint integer as character.
p/f variablePrint variable as floating point number.
p/a variablePrint as a hex address.
x/w address x/4b &variablePrint binary representation of 4 bytes (1 32 bit word) of memory pointed to by address.
ptype variable ptype data-typePrints type definition of the variable or declared variable type. Helpful for viewing class or struct definitions while debugging.

print命令

在调试程序时,当程序被停住时,可以使用print命令(缩写为p),或是同义命令inspect来查看当前程序的运行数据。print命令的格式是:

  1. print <expr>
  2. print /<f> <expr>

<expr>是表达式,是被调试的程序中的表达式,<f>是输出的格式,比如,如果要把表达式按16进制的格式输出,那么就是/x。在表达式中,有几种GDB所支持的操作符,它们可以用在任何一种语言中,“@”是一个和数组有关的操作符,“::”指定一个在文件或是函数中的变量,“{<type>} <addr>”表示一个指向内存地址<addr>的类型为type的一个对象。

下面演示了查看sum[]数组的值的过程:

  1. (gdb) print sum
  2. $2 = {133, 155, 0, 0, 0, 0, 0, 0, 0, 0}
  3. (gdb) next
  4. Breakpoint 1, main () at gdb_example.c:25
  5. 25 sum[i] = add(array1[i], array2[i]);
  6. (gdb) next
  7. 23 for (i = 0; i < 10; i++)
  8. (gdb) print sum
  9. $3 = {133, 155, 143, 0, 0, 0, 0, 0, 0, 0}

当需要查看一段连续内存空间的值的时间,可以使用GDB的“@”操作符,“@”的左边是第一个内存地址,“@”的右边则是想查看内存的长度。例如如下动态申请的内存:

  1. int *array = (int *) malloc (len * sizeof (int));
  2. *array = (int *) malloc (len * sizeof (int));

GDB调试过程中这样显示出这个动态数组的值:

  1. p *array@len
  2. *array@len

print的输出格式包括:

  • x 按十六进制格式显示变量。
  • d 按十进制格式显示变量。
  • u 按十六进制格式显示无符号整型。
  • o 按八进制格式显示变量。
  • t 按二进制格式显示变量。
  • a 按十六进制格式显示变量。
  • c 按字符格式显示变量。
  • f 按浮点数格式显示变量。

我们可用display命令设置一些自动显示的变量,当程序停住时,或是单步跟踪时,这些变量会自动显示。 如果要修改变量,如x的值,可使用如下命令:

  1. print x=4
  2. x=4

当用GDB的print查看程序运行时的数据时,每一个print都会被GDB记录下来。GDB会以$1,$2,$3 …这样的方式为每一个print命令编号。我们可以使用这个编号访问以前的表达式,如$1。

堆栈查询命令

Stack
backtrace bt bt inner-function-nesting-depth bt -outer-function-nesting-depthShow trace of where you are currently. Which functions you are in. Prints stack backtrace.
backtrace fullPrint values of local variables.
frame frame number f numberShow current stack frame (function where you are stopped) Select frame number. (can also user up/down to navigate frames)
up down up number down numberMove up a single frame (element in the call stack) Move down a single frame Move up/down the specified number of frames in the stack.
info frameList address, language, address of arguments/local variables and which registers were saved in frame.

backtrace命令

backtrace命令用于打印当前调试环境中所有栈帧的信息,常用的语法格式如下:

(gdb) backtrace [-full] [n]

其中,用 [ ] 括起来的参数为可选项,它们的含义分别为:

n:一个整数值,当为正整数时,表示打印最里层的 n 个栈帧的信息;n为负整数时,那么表示打印最外层n个栈帧的信息;

-full:打印栈帧信息的同时,打印出局部变量的值。

注意,当调试多线程程序时,该命令仅用于打印当前线程中所有栈帧的信息。如果想要打印所有线程的栈帧信息,应执行thread apply all backtrace命令。

  1. (gdb) bt
  2. #0 0x0800d636 in Get_Portproperties (channel=3 '\003',
  3. port_isvalid_mask=0x20007f80, port_isgpio_mask=0x20007f7c)
  4. at Bios/port.c:100
  5. #1 0x0800de10 in Port_WR_32bit () at Bios/port.c:619
  6. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  7. #3 0x080056a8 in interpreter () at Bios/interprt.c:624
  8. #4 0x080079a4 in msgPoll (broadcast=true) at Bios/comm_mbc.c:1719
  9. #5 0x0801119a in main () at App/main.c:87
  10. (gdb) backtrace full
  11. #0 0x0800d636 in Get_Portproperties (channel=3 '\003',
  12. port_isvalid_mask=0x20007f80, port_isgpio_mask=0x20007f7c)
  13. at Bios/port.c:100
  14. i = 16 '\020'
  15. #1 0x0800de10 in Port_WR_32bit () at Bios/port.c:619
  16. Read 4 bytes @ address 0x0800D8B8 (Data = 0x4B64E0C4)
  17. Reading 64 bytes @ address 0x20007FC0
  18. error = 0
  19. gpio = 0x800a6cb <hprintf+22>
  20. port_isvalid_mask = 7
  21. port_isgpio_mask = 1
  22. port_mask = 134320932
  23. channel = 3 '\003'
  24. port_bit = 32 ' '
  25. port_altfunc = 0 '\000'
  26. port_intfunc = 32 ' '
  27. i = 536903588
  28. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  29. Read 4 bytes @ address 0x080056A8 (Data = 0xF007E027)
  30. channel_old_command = 32 ' '
  31. channel_new_command = 13 '\r'
  32. channel_shift = 0
  33. command = 0 '\000'
  34. param1 = 536874464
  35. param2 = 0
  36. port_isvalid_mask = 536878716
  37. port_isgpio_mask = 0
  38. #3 0x080056a8 in interpreter () at Bios/interprt.c:624
  39. Read 4 bytes @ address 0x080079A4 (Data = 0x7BFBBF00)
  40. Read 4 bytes @ address 0x0801119A (Data = 0x2B004603)
  41. No locals.
  42. #4 0x080079a4 in msgPoll (broadcast=true) at Bios/comm_mbc.c:1719
  43. ch = 0 '\000'
  44. txMsg = "\020\006"
  45. #5 0x0801119a in main () at App/main.c:87
  46. Read 4 bytes @ address 0x0800147A (Data = 0xB3AC4770)
  47. Reading 64 bytes @ address 0x08

frame 命令

frame命令的常用形式有 2 个:

根据栈帧编号或者栈帧地址,选定要查看的栈帧,语法格式如下:

(gdb) frame spec

该命令可以将 spec 参数指定的栈帧选定为当前栈帧。spec 参数的值,常用的指定方法有 3 种:

通过栈帧的编号指定。0 为当前被调用函数对应的栈帧号,最大编号的栈帧对应的函数通常就是 main() 主函数; 借助栈帧的地址指定。栈帧地址可以通过 info frame 命令(后续会讲)打印出的信息中看到; 通过函数的函数名指定。注意,如果是类似递归函数,其对应多个栈帧的话,通过此方法指定的是编号最小的那个栈帧。 除此之外,对于选定一个栈帧作为当前栈帧,GDB 调试器还提供有up 和down两个命令。其中,up命令的语法格式为:

  1. (gdb) up n
  2. (gdb) bt
  3. #0 0x0800d636 in Get_Portproperties (channel=3 '\003',
  4. port_isvalid_mask=0x20007f80, port_isgpio_mask=0x20007f7c)
  5. at Bios/port.c:100
  6. #1 0x0800de10 in Port_WR_32bit () at Bios/port.c:619
  7. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  8. #3 0x080056a8 in interpreter () at Bios/interprt.c:624
  9. #4 0x080079a4 in msgPoll (broadcast=true) at Bios/comm_mbc.c:1719
  10. #5 0x0801119a in main () at App/main.c:87
  11. (gdb) frame
  12. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  13. 285 Port_WR_32bit();
  14. (gdb) up 1
  15. #3 0x080056a8 in interpreter () at Bios/interprt.c:624
  16. 624 case PORT_SCHREIBEN: Port_WR();

其中 n为整数,默认值为 1。该命令表示在当前栈帧编号(假设为 m)的基础上,选定 m+n为编号的栈帧作为新的当前栈帧。

相对地,down 命令的语法格式为:

  1. (gdb) down n
  2. (gdb) bt
  3. #0 0x0800d636 in Get_Portproperties (channel=3 '\003',
  4. port_isvalid_mask=0x20007f80, port_isgpio_mask=0x20007f7c)
  5. at Bios/port.c:100
  6. #1 0x0800de10 in Port_WR_32bit () at Bios/port.c:619
  7. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  8. #3 0x080056a8 in interpreter () at Bios/interprt.c:624
  9. #4 0x080079a4 in msgPoll (broadcast=true) at Bios/comm_mbc.c:1719
  10. #5 0x0801119a in main () at App/main.c:87
  11. (gdb) frame
  12. #2 0x0800d8b8 in Port_WR () at Bios/port.c:285
  13. 285 Port_WR_32bit();
  14. (gdb) down 1
  15. #1 0x0800de10 in Port_WR_32bit () at Bios/port.c:619
  16. 619 if (!Get_Portproperties (channel, &port_isvalid_mask, &port_isgpio_mask))
  17. (gdb)

其中n为整数,默认值为 1。该命令表示在当前栈帧编号(假设为 m)的基础上,选定m-n 为编号的栈帧作为新的当前栈帧。

借助如下命令,我们可以查看当前栈帧中存储的信息:

  1. (gdb) info frame
  2. Reading 64 bytes @ address 0x0800D840
  3. Read 4 bytes @ address 0x0800DA4E (Data = 0xB5802000)
  4. Reading register (MSP = 0x20007F58)
  5. Reading register (PSP = 0x 0)
  6. Reading register (PRIMASK = 0x 0)
  7. Reading register (BASEPRI = 0x 0)
  8. Reading register (FAULTMASK = 0x 0)
  9. Reading register (CONTROL = 0x 0)
  10. Stack level 2, frame at 0x20007fc8:
  11. pc = 0x800d8b8 in Port_WR (port.c:285); saved pc = 0x80056a8
  12. called by frame at 0x20007fd0, caller of frame at 0x20007fa8
  13. source language c.
  14. Arglist at 0x20007fa8, args:
  15. Locals at 0x20007fa8, Previous frame's sp is 0x20007fc8
  16. Saved registers:
  17. r7 at 0x20007fc0, lr at 0x20007fc4
  18. (gdb)

该命令会依次打印出当前栈帧的如下信息:

  • 当前栈帧的编号,以及栈帧的地址;
  • 当前栈帧对应函数的存储地址,以及该函数被调用时的代码存储的地址
  • 当前函数的调用者,对应的栈帧的地址;
  • 编写此栈帧所用的编程语言;
  • 函数参数的存储地址以及值;
  • 函数中局部变量的存储地址;
  • 栈帧中存储的寄存器变量,例如指令寄存器(64位环境中用 rip 表示,32为环境中用eip 表示)、堆栈基指针寄存器(64位环境用 rbp表示,32位环境用 ebp表示)等。

除此之外,还可以使用info args命令查看当前函数各个参数的值;使用info locals命令查看当前函数中各局部变量的值。

  1. (gdb) l Port_WR
  2. 255 //* Quality : (x) not tested ( ) partly tested ( ) fully tested *
  3. 256 //****************************************************************************
  4. 257
  5. 258 #if (CP_PORT_RW == 2)
  6. 259 void Port_WR (void)
  7. 260 {
  8. 261 //*--------------------------------------------------------------------------*
  9. 262 //* Local variables *
  10. 263 //*--------------------------------------------------------------------------*
  11. 264
  12. (gdb) l
  13. 265 uint8_t channel_old_command;
  14. 266 uint8_t channel_new_command;
  15. 267 uint32_t channel_shift;
  16. 268 uint8_t command;
  17. 269 uint32_t param1, param2;
  18. 270 uint32_t port_isvalid_mask;
  19. 271 uint32_t port_isgpio_mask;
  20. 272
  21. (gdb) info locals # 查看当前函数各局部变量的值
  22. Read 4 bytes @ address 0x080056A8 (Data = 0xF007E027)
  23. Reading 64 bytes @ address 0x20007F80
  24. channel_old_command = 32 ' '
  25. channel_new_command = 13 '\r'
  26. channel_shift = 0
  27. command = 0 '\000'
  28. param1 = 536874464
  29. param2 = 0
  30. port_isvalid_mask = 536878716
  31. port_isgpio_mask = 0

参考文献:

Linux Tutorial - GNU GDB Debugger Command Cheat Sheet (yolinux.com)
GDB调试命令详解
宋宝华的Linux gdb调试器用法全面解析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/260654
推荐阅读
  

闽ICP备14008679号