gdb调试时好用的命令

set print pretty

我们在gdb调试时经常需要利用p命令打印结构体数据信息。默认情况下,p命令会以顺序罗列出来,这会显得很拥挤,不便于阅读。下面以一个实例进行说明。

实例代码如下:

     1  #include <stdio.h>
     2  #include <stdlib.h>
     3  #include <string.h>
     4
     5  #define MAX_SENSOR_NAME_LEN     256
     6  #define MAX_DEV_NAME_LEN        256
     7  #define MAX_SENSOR_NUM          64
     8
     9  typedef struct tagSENSOR_INFO
    10  {
    11          unsigned char ucSensorType;
    12          unsigned char ucSensorNum;
    13          char          szSensorName[MAX_SENSOR_NAME_LEN];
    14  }SENSOR_INFO_S;
    15
    16  typedef struct tagDEVICE_CTL_INFO
    17  {
    18          unsigned char ucDevType;
    19          unsigned char ucDevNum;
    20          char          szDevName[MAX_DEV_NAME_LEN];
    21          SENSOR_INFO_S astSensorInfoTbl[MAX_SENSOR_NUM];
    22  }DEVICE_CTL_INFO_S;
    23
    24  DEVICE_CTL_INFO_S g_astDeviceCtlInfo[] =
    25  {
    26          {0x00, 0x00, "Switch", {0x00, 0x00, "Temperature_Sensor_1"}},
    27          {0x00, 0x01, "Switch", {0x00, 0x02, "Temperature_Sensor_2"}},
    28          {0x00, 0x00, "Router", {0x00, 0x00, "Voltage_Sensor_1"}},
    29          {0x00, 0x01, "Router", {0x00, 0x04, "Voltage_Sensor_2"}},
    30  };
    31
    32  void StartSendMessage(void)
    33  {
    34          int a                                   = 1;
    35          int b                                   = 3;
    36          int iRet                                = 0;
    37          unsigned int uiIndex                    = 0;
    38          DEVICE_CTL_INFO_S *pstDevCtlInfo        = NULL;
    39
    40          for (uiIndex = 0; uiIndex < sizeof(g_astDeviceCtlInfo) / sizeof(g_astDeviceCtlInfo[0]); uiIndex++)
    41          {
    42                  pstDevCtlInfo = &g_astDeviceCtlInfo[uiIndex];
    43                  iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
    44                  if (0 == iRet)
    45                  {
    46                          printf("This is switch device\n");
    47                  }
    48                  else
    49                  {
    50                          printf("This is router device.\n");
    51                  }
    52          }
    53
    54          printf("Start send message---%d.\n", a + b);
    55
    56          return;
    57  }

打必要的断点,利用p命令打印出全局结构体变量g_astDeviceCtlInfo信息。

(gdb) p g_astDeviceCtlInfo 
$3 = {{ucDevType = 0 '\000', ucDevNum = 0 '\000', szDevName = "Switch", '\000' <repeats 121 times>, astSensorInfoTbl = {{ucSensorType = 0 '\000', ucSensorNum = 0 '\000', 
        szSensorName = "Temperature_Sensor_1", '\000' <repeats 107 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {
        ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>}}}, {ucDevType = 0 '\000', ucDevNum = 1 '\001', szDevName = "Switch", '\000' <repeats 121 times>, astSensorInfoTbl = {{
        ucSensorType = 0 '\000', ucSensorNum = 2 '\002', szSensorName = "Temperature_Sensor_2", '\000' <repeats 107 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}}}, {ucDevType = 0 '\000', ucDevNum = 0 '\000', szDevName = "Router", '\000' <repeats 121 times>, 
    astSensorInfoTbl = {{ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = "Voltage_Sensor_1", '\000' <repeats 111 times>}, {ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {
        ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}}}, {ucDevType = 0 '\000', ucDevNum = 1 '\001', 
    szDevName = "Router", '\000' <repeats 121 times>, astSensorInfoTbl = {{ucSensorType = 0 '\000', ucSensorNum = 4 '\004', 
        szSensorName = "Voltage_Sensor_2", '\000' <repeats 111 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {
        ucSensorType = 0 '\000', ucSensorNum = 0 '\000', szSensorName = '\000' <repeats 127 times>}, {ucSensorType = 0 '\000', ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>}}}}

set print pretty命令优雅地展开结构体信息

(gdb) set print pretty on
(gdb) p g_astDeviceCtlInfo 
$6 = {{
    ucDevType = 0 '\000', 
    ucDevNum = 0 '\000', 
    szDevName = "Switch", '\000' <repeats 121 times>, 
    astSensorInfoTbl = {{
        ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', 
        szSensorName = "Temperature_Sensor_1", '\000' <repeats 107 times>
      }, {
        ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>
      }, {
        ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>
      }, {
        ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', 
        szSensorName = '\000' <repeats 127 times>
      }}
  }, {
    ucDevType = 0 '\000', 
    ucDevNum = 1 '\001', 
    szDevName = "Switch", '\000' <repeats 121 times>, 
    astSensorInfoTbl = {{
        ucSensorType = 0 '\000', 
        ucSensorNum = 2 '\002', 
        szSensorName = "Temperature_Sensor_2", '\000' <repeats 107 times>
      }, {
        ucSensorType = 0 '\000', 
        ucSensorNum = 0 '\000', 

设置之后结构体信息展开后清晰易读,非常方便。

P

p命令经常用于打印调试过程中碰到的各种变量。下面介绍几种打印场景。

以指定类型打印指定地址内容

查看局部变量pstDevCtlInfo的地址为0xb7fd5040。

(gdb) p pstDevCtlInfo 
$14 = (DEVICE_CTL_INFO_S *) 0xb7fd5040 <g_astDeviceCtlInfo>

以结构体DEVICE_CTL_INFO_S形式展开地址0xb7fd5040处内容。

(gdb) p *(DEVICE_CTL_INFO_S *) 0xb7fd5040
$13 = {
  ucDevType = 0 '\000', 
  ucDevNum = 0 '\000', 
  szDevName = "Switch", '\000' <repeats 121 times>, 
  astSensorInfoTbl = {{
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = "Temperature_Sensor_1", '\000' <repeats 107 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }}
}

设置临时变量

查看全局结构体变量g_astDeviceCtlInfo成员大小。

(gdb) p /x sizeof(DEVICE_CTL_INFO_S)
$20 = 0x28a

创建临时变量pstDevice3指向g_astDeviceCtlInfo的第三个成员,即设备3。

(gdb) p $pstDevice3 = (DEVICE_CTL_INFO_S *)(0xb7fd5040 + 0x28a * 2)
$21 = (DEVICE_CTL_INFO_S *) 0xb7fd5554 <g_astDeviceCtlInfo+1300>

后面我们可以方便地使用临时设置的变量pstDevice3打印相关变量值了。(注意在使用过程中需要在pstDevice3临时变量名前加上$,否则会报查找不到符号告警

  • 如打印pstDevice3指向的结构体信息:
(gdb) p *(DEVICE_CTL_INFO_S *)$pstDevice3
$24 = {
  ucDevType = 0 '\000', 
  ucDevNum = 0 '\000', 
  szDevName = "Router", '\000' <repeats 121 times>, 
  astSensorInfoTbl = {{
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = "Voltage_Sensor_1", '\000' <repeats 111 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }, {
      ucSensorType = 0 '\000', 
      ucSensorNum = 0 '\000', 
      szSensorName = '\000' <repeats 127 times>
    }}
}
  • 打印pstDevice3指向的第一个astSensorInfoTbl的szSensorName值
(gdb) p $pstDevice3->astSensorInfoTbl
$26 = {{
    ucSensorType = 0 '\000', 
    ucSensorNum = 0 '\000', 
    szSensorName = "Voltage_Sensor_1", '\000' <repeats 111 times>
  }, {
    ucSensorType = 0 '\000', 
    ucSensorNum = 0 '\000', 
    szSensorName = '\000' <repeats 127 times>
  }, {
    ucSensorType = 0 '\000', 
    ucSensorNum = 0 '\000', 
    szSensorName = '\000' <repeats 127 times>
  }, {
    ucSensorType = 0 '\000', 
    ucSensorNum = 0 '\000', 
    szSensorName = '\000' <repeats 127 times>
  }}
(gdb) p $pstDevice3->astSensorInfoTbl[0]
$27 = {
  ucSensorType = 0 '\000', 
  ucSensorNum = 0 '\000', 
  szSensorName = "Voltage_Sensor_1", '\000' <repeats 111 times>
}
(gdb) p $pstDevice3->astSensorInfoTbl[0]->szSensorName 
$28 = "Voltage_Sensor_1", '\000' <repeats 111 times>
  • 对设置的临时变量再取多级临时变量

取pstDevice3指向的astSensorInfoTbl结构体数组的第一个成员设置临时变量pstSensorInfoTbl1。

(gdb) p $pstSensorInfoTbl1 = &($pstDevice3->astSensorInfoTbl[0])
$32 = (SENSOR_INFO_S *) 0xb7fd55d6 <g_astDeviceCtlInfo+1430>

取临时变量pstSensorInfoTbl1的szSensorName成员设置临时变量pcSensorName1,并打印出pcSensorName1变量值。

(gdb) p $pcSensorName1 = $pstSensorInfoTbl1->szSensorName 
$33 = 0xb7fd55d8 <g_astDeviceCtlInfo+1432> "Voltage_Sensor_1"
(gdb) p $pcSensorName1
$34 = 0xb7fd55d8 <g_astDeviceCtlInfo+1432> "Voltage_Sensor_1"

注意:为了多级取临时变量,上一步设置的临时变量值pstSensorInfoTbl1必须为指针,否则会报错提示使用未分配内存地址。也即在多级临时变量取值过程中,中间的临时变量必须为指针,这应该是因为gdb在调试过程中不会分配非基础类型变量内存原因。

(gdb) p $SensorInfoTbl1 = $pstDevice3->astSensorInfoTbl[0]
$29 = {
  ucSensorType = 0 '\000', 
  ucSensorNum = 0 '\000', 
  szSensorName = "Voltage_Sensor_1", '\000' <repeats 111 times>
}
(gdb) p $SensorName1 = $SensorInfoTbl1.szSensorName 
Attempt to take address of value not located in memory.

commands

commands命令用于自定义设置对应断点触发时需要执行的命令。

在SendMessage.c文件的43行设置断点。我们可能需要在那个时候查看pstDevCtlInfo->szDevName变量的值,这样能方便我们快速定位,这时候command命令将能完美满足我们需求。

  • 打断点情况
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0xb7fd35c2 in StartSendMessage at SendMessage.c:34
        breakpoint already hit 1 time
2       breakpoint     keep y   0xb7fd3602 in StartSendMessage at SendMessage.c:43
  • 利用commands命令在断点2处设置命令打印pstDevCtlInfo->szDevName值内容。(当commands不指定断点编号时,将默认设置断点为最近一次所设置的断点)
(gdb) commands 2
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>printf "Current device name:%s\n",pstDevCtlInfo->szDevName 
>end

上面采用printf命令打印字段“Current device name:设备名称”

  • 执行调试程序到断点2处
(gdb) n

Breakpoint 2, StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
Current device name:Switch

可以看出,顺利打印出pstDevCtlInfo->szDevName的数据为“Switch”,此次判断将成功。

commands命令介绍:

(gdb) help commands 
Set commands to be executed when a breakpoint is hit.
Give breakpoint number as argument after "commands".
With no argument, the targeted breakpoint is the last one set.
The commands themselves follow starting on the next line.
Type a line containing "end" to indicate the end of them.
Give "silent" as the first line to make the breakpoint silent;
then no output is printed when it is hit, except what the commands print.

 b

断点命令b是我们使用的较多的命令。常规功能这里就不介绍了,主要介绍几个比较特别且好用的功能。

条件断点

我们可以在断点命令b后面增加if条件设置只有当对应的条件成立时断点才停下来。断点的条件表达式比较灵活,可以判断变量值,也可以调用函数。下面举例用于判断只有对应的字符串为指定时断点才停下来。

  • 设置断点
(gdb) b SendMessage.c:43 if 0 == strcmp(pstDevCtlInfo->szDevName, "Switch")
No source file named SendMessage.c.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (SendMessage.c:43 if 0 == strcmp(pstDevCtlInfo->szDevName, "Switch")) pending.
  • r命令执行程序,c命令多次继续执行至下个断点。
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/TestDemon/test 
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
warning: Could not load shared library symbols for 2 libraries, e.g. /lib/i386-linux-gnu/libc.so.6.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
CreateMme piData:0x804b008

Breakpoint 1, StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p pstDevCtlInfo->szDevName 
$2 = "Switch", '\000' <repeats 121 times>
(gdb) c
Continuing.
This is switch device

Breakpoint 1, StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p pstDevCtlInfo->szDevName 
$3 = "Switch", '\000' <repeats 121 times>
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0xb7fd3602 in StartSendMessage at SendMessage.c:43
        stop only if 0 == strcmp(pstDevCtlInfo->szDevName, "Switch")
        breakpoint already hit 2 times
(gdb) c
Continuing.
This is switch device
This is router device.
This is router device.
Start send message---4.
^C
Program received signal SIGINT, Interrupt.
0xb7fdac31 in __kernel_vsyscall ()

从上图可知,断点1总共触发了两次,实际也是有两次循环中对应的pstDevCtlInfo->szDevName为“Switch”,符合预期。

watch

watch命令用于监控指定变量或者地址内容,其属于观察断点。当监控的变量或者地址内容发生变化时,程序将停止下来。

一、watch设置观察变量值

  • 先让程序运行到StartSendMessage函数开头处,再利用watch命令设置观察断点监控变量pstDevCtlInfo指针
(gdb) watch pstDevCtlInfo 
Hardware watchpoint 7: pstDevCtlInfo
  • c命令多次继续执行至函数结束
(gdb) c
Continuing.

Hardware watchpoint 7: pstDevCtlInfo

Old value = (DEVICE_CTL_INFO_S *) 0x0
New value = (DEVICE_CTL_INFO_S *) 0xb7fd5040 <g_astDeviceCtlInfo>
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) c
Continuing.
This is switch device

Hardware watchpoint 7: pstDevCtlInfo

Old value = (DEVICE_CTL_INFO_S *) 0xb7fd5040 <g_astDeviceCtlInfo>
New value = (DEVICE_CTL_INFO_S *) 0xb7fd52ca <g_astDeviceCtlInfo+650>
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) c
Continuing.
This is switch device

Hardware watchpoint 7: pstDevCtlInfo

Old value = (DEVICE_CTL_INFO_S *) 0xb7fd52ca <g_astDeviceCtlInfo+650>
New value = (DEVICE_CTL_INFO_S *) 0xb7fd5554 <g_astDeviceCtlInfo+1300>
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) c
Continuing.
This is router device.

Hardware watchpoint 7: pstDevCtlInfo

Old value = (DEVICE_CTL_INFO_S *) 0xb7fd5554 <g_astDeviceCtlInfo+1300>
New value = (DEVICE_CTL_INFO_S *) 0xb7fd57de <g_astDeviceCtlInfo+1950>
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) c
Continuing.
This is router device.
Start send message---4.

Watchpoint 7 deleted because the program has left the block in
which its expression is valid.
main () at main.c:28
28                      sleep(50);

从上图可知,观察断点总共触发了4次,程序停下来了4次,且每次停下来均会打印出监控对应之前的值(Old value)和最新的值(New value)。该循环总共有4次,符合预期。

二、watch设置观察内存地址内容

  • 先让程序运行到StartSendMessage函数开头处,然后利用p命令查看局部变量pstDevCtlInfo的地址
(gdb) p &pstDevCtlInfo 
$40 = (DEVICE_CTL_INFO_S **) 0xbffff67c
  •  利用watch命令观察上一步获取的pstDevCtlInfo变量地址中内存的值
(gdb) watch *(unsigned long *)0xbffff67c
Hardware watchpoint 11: *(unsigned long *)0xbffff67c
  •  多次调用c命令持续执行程序,直到函数结束。
(gdb) c
Continuing.

Hardware watchpoint 11: *(unsigned long *)0xbffff67c

Old value = 0
New value = 3086831680
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p pstDevCtlInfo 
$42 = (DEVICE_CTL_INFO_S *) 0xb7fd5040 <g_astDeviceCtlInfo>
(gdb) p /x 3086831680
$43 = 0xb7fd5040
(gdb) c
Continuing.
This is switch device

Hardware watchpoint 11: *(unsigned long *)0xbffff67c

Old value = 3086831680
New value = 3086832330
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p /x 3086831680
$44 = 0xb7fd5040
(gdb) p /x 3086832330
$45 = 0xb7fd52ca
(gdb) p pstDevCtlInfo 
$46 = (DEVICE_CTL_INFO_S *) 0xb7fd52ca <g_astDeviceCtlInfo+650>
(gdb) c
Continuing.
This is switch device

Hardware watchpoint 11: *(unsigned long *)0xbffff67c

Old value = 3086832330
New value = 3086832980
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p /x 3086832980
$47 = 0xb7fd5554
(gdb) p pstDevCtlInfo 
$48 = (DEVICE_CTL_INFO_S *) 0xb7fd5554 <g_astDeviceCtlInfo+1300>
(gdb) c
Continuing.
This is router device.

Hardware watchpoint 11: *(unsigned long *)0xbffff67c

Old value = 3086832980
New value = 3086833630
StartSendMessage () at SendMessage.c:43
43                      iRet = strcmp(pstDevCtlInfo->szDevName, "Switch");
(gdb) p /x 3086833630
$49 = 0xb7fd57de
(gdb) p pstDevCtlInfo 
$50 = (DEVICE_CTL_INFO_S *) 0xb7fd57de <g_astDeviceCtlInfo+1950>
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0xb7fd35c2 in StartSendMessage at SendMessage.c:34
        breakpoint already hit 1 time
11      hw watchpoint  keep y              *(unsigned long *)0xbffff67c
        breakpoint already hit 4 times
(gdb) c
Continuing.
This is router device.
Start send message---4.

 这期间可以看到4次触发了断点(除了初始化变量pstDevCtlInfo那次)。每次暂停时,均打印出了监控内存中变化前和变化后的值,且和直接打印pstDevCtlInfo数值一致。这符合预期,且和第一种方法监控变量pstDevCtlInfo效果一样。

保存和读取断点信息

我们在调试的过程中经常需要打很多断点,但当我们在调试过程中发现程序可能存在的问题后需要修改程序以便再次调试。这样我们之前设置的断点信息就不存在了,需要重新设置,这影响了我们的调试效率。因此,我们有必要在调试时保存断点信息,然后下次调试时再读取该断点信息继续调试。

保存断点信息

我们可以通过save breakpoints命令保存当前已设置的断点信息。

# 保存当前设置的断点信息到test.bp文件
save breakpoints test.bp

读取断点信息

读取刚刚保存的断点信息有两种方式。具体如下:

1. 启动gdb时利用-x命令读取

gdb ./test -x test.bp

2. 启动gdb后利用source命令读取

source test.bp

 disassemble

disassemble命令可以对指定函数/地址进行反汇编。这里主要介绍其中几个有特色的好用功能。

一、逐行反汇编

我们可以利用disassemble /m命令对指定地址/函数按照逐行c语言进行反汇编。如对如下main函数进行操作。

main函数:

    88  int main(void)
    89  {
    90          int returnSize = 0;
    91          int nums[] = {-4,-1,0,3,10};
    92
    93          CreateMem();
    94
    95          (void)sortedSquares(nums, 5, &returnSize);
    96
    97          StartSendMessage();
    98
    99          while (1)
   100          {
   101                  sleep(50);
   102          }
   103
   104          return 0;
   105  }

 逐行反汇编命令:

disassemble /m main

 效果如下:

(gdb) disassemble /m main
Dump of assembler code for function main:
89      {
   0x080488ab <+0>:     lea    0x4(%esp),%ecx
   0x080488af <+4>:     and    $0xfffffff0,%esp
   0x080488b2 <+7>:     pushl  -0x4(%ecx)
   0x080488b5 <+10>:    push   %ebp
   0x080488b6 <+11>:    mov    %esp,%ebp
   0x080488b8 <+13>:    push   %ecx
   0x080488b9 <+14>:    sub    $0x24,%esp
   0x080488bc <+17>:    mov    %gs:0x14,%eax
   0x080488c2 <+23>:    mov    %eax,-0xc(%ebp)
   0x080488c5 <+26>:    xor    %eax,%eax

90              int returnSize = 0;
   0x080488c7 <+28>:    movl   $0x0,-0x24(%ebp)

91              int nums[] = {-4,-1,0,3,10};
   0x080488ce <+35>:    movl   $0xfffffffc,-0x20(%ebp)
   0x080488d5 <+42>:    movl   $0xffffffff,-0x1c(%ebp)
   0x080488dc <+49>:    movl   $0x0,-0x18(%ebp)
   0x080488e3 <+56>:    movl   $0x3,-0x14(%ebp)
   0x080488ea <+63>:    movl   $0xa,-0x10(%ebp)

92
93              CreateMem();
   0x080488f1 <+70>:    call   0x804860b <CreateMem>

---Type <return> to continue, or q <return> to quit---
94
95              (void)sortedSquares(nums, 5, &returnSize);
   0x080488f6 <+75>:    sub    $0x4,%esp
   0x080488f9 <+78>:    lea    -0x24(%ebp),%eax
   0x080488fc <+81>:    push   %eax
   0x080488fd <+82>:    push   $0x5
   0x080488ff <+84>:    lea    -0x20(%ebp),%eax
   0x08048902 <+87>:    push   %eax
   0x08048903 <+88>:    call   0x804864a <sortedSquares>
   0x08048908 <+93>:    add    $0x10,%esp

96
97              StartSendMessage();
   0x0804890b <+96>:    call   0x80484a0 <StartSendMessage@plt>

98
99              while (1)
100             {
101                     sleep(50);
   0x08048910 <+101>:   sub    $0xc,%esp
   0x08048913 <+104>:   push   $0x32
   0x08048915 <+106>:   call   0x80484c0 <sleep@plt>
   0x0804891a <+111>:   add    $0x10,%esp

102             }
   0x0804891d <+114>:   jmp    0x8048910 <main+101>

---Type <return> to continue, or q <return> to quit---
End of assembler dump.

 从上图可知,该命令对每一行c语言代码进行了反汇编,且把每一行c语言代码和它对应的反汇编代码放在了一起。这在我们调试时非常有用,特别是当函数较长,一时无法分析出问题汇编代码对应的具体c语言代码位置时能帮助我们快速结合代码解决问题。

thread

我们有时候在调试时需要查看当前进程下各个线程是否存在可能交集以致破坏了全局变量、线程锁等信息,这是我们就可以使用如下“thread apply all bt”命令查看进程下所有线程栈回溯信息。

(gdb) thread apply all bt

Thread 1 (process 15215):
#0  SigInt (iSigNum=2) at SendMessage.c:35
#1  <signal handler called>
#2  StartSendMessage () at SendMessage.c:69
#3  0x08048910 in main () at main.c:97

 从上图可知,我们可以清晰地知道当前各个线程执行的位置,快速比较定位问题。

平常我们在gdb调试时对任何命令有疑问均可以使用help command格式获取对应的命令详细说明。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值