GDB调试

调试前准备

获取进程的内核转储(core dump)

why:最大好处是,其保存了问题发生时的状态。记录进程当前状态。

步入正题:

启动内核转储,查看当前内核转储功能是否有效,结果为0表示内核转储无效

$ ulimit -c

那么,则需要开启内核转储,该命令不限制转储文件大小。亦可设置为有限上限1G,ulimit -c 1073741842。

$ ulimit -c  unlimited

$ ./a.out    生成转储文件

查看生成的转储文件

$ file core*

GDB启动,使用转储文件

$ gdb -c core.xxx   ./a.out

 

一、GDB调试前问题汇总

1.编译出现undefined reference to 'pthread_create'

编译加上参数   -lpthread

2.apue.h找不到

导入src.3e.tar.gz 中apue/include/apue.h  到 /usr/include

3.err_sys未定义

关于err_sys未定义错误解决方法

二、GDB例子(切入)

一个调试示例

——————

源程序:tst.c

#include <stdio.h>

int func(int n){

int sum = 0,i;

for(i=0; i<7;i++){

sum += i; } return sum;}

main(){

int i;

long result = 0;

for(i=1;i<=100;i++){

result += i;}

printf("result[1-100]= %d/n",result);

printf("result[1-250]= %d/n",func(250));

}

编译生成执行文件:(Linux下)

hchen/test> cc -g tst.c -o tst

使用GDB调试:

hchen/test> gdb tst  <---------- 启动GDB

GNU gdb 5.1.1

Copyright 2002 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-suse-linux"...

(gdb) l     <-------------------- l命令相当于list,从第一行开始例出原码。

1        #include

2

3        int func(int n)

4        {

5                int sum=0,i;

6                for(i=0; i

7                {

8                        sum+=i;

9                }

10               return sum;

(gdb)       <-------------------- 直接回车表示,重复上一次命令

11       }

12

13

14       main()

15       {

16               int i;

17               long result = 0;

18               for(i=1; i<=100; i++)

19               {

20                       result += i;

(gdb) break 16    <-------------------- 设置断点,在源程序第16行处。

Breakpoint 1 at 0x8048496: file tst.c, line 16.

(gdb) break func  <-------------------- 设置断点,在函数func()入口处。

Breakpoint 2 at 0x8048456: file tst.c, line 5.

(gdb) info break  <-------------------- 查看断点信息。

Num Type           Disp Enb Address    What

1   breakpoint     keep y   0x08048496 in main at tst.c:16

2   breakpoint     keep y   0x08048456 in func at tst.c:5

(gdb) r           <--------------------- 运行程序,run命令简写

Starting program: /home/hchen/test/tst

Breakpoint 1, main () at tst.c:17    <---------- 在断点处停住。

17               long result = 0;

(gdb) n          <--------------------- 单条语句执行,next命令简写。

18               for(i=1; i<=100; i++)

(gdb) n

20                       result += i;

(gdb) n

18               for(i=1; i<=100; i++)

(gdb) n

20                       result += i;

(gdb) c          <--------------------- 继续运行程序,continue命令简写。

Continuing.

result[1-100] = 5050       <----------程序输出。

Breakpoint 2, func (n=250) at tst.c:5

5                int sum=0,i;

(gdb) n

6                for(i=1; i<=n; i++)

(gdb) p i        <--------------------- 打印变量i的值,print命令简写。

$1 = 134513808

(gdb) n

8                        sum+=i;

(gdb) n

6                for(i=1; i<=n; i++)

(gdb) p sum

$2 = 1

(gdb) n

8                        sum+=i;

(gdb) p i

$3 = 2

(gdb) n

6                for(i=1; i<=n; i++)

(gdb) p sum

$4 = 3

(gdb) bt        <--------------------- 查看函数堆栈。

#0  func (n=250) at tst.c:5

#1  0x080484e4 in main () at tst.c:24

#2  0x400409ed in __libc_start_main () from /lib/libc.so.6

(gdb) finish    <--------------------- 退出函数。

Run till exit from #0  func (n=250) at tst.c:5

0x080484e4 in main () at tst.c:24

24              printf("result[1-250] = %d /n", func(250) );

Value returned is $6 = 31375

(gdb) c     <--------------------- 继续运行。

Continuing.

result[1-250] = 31375    <----------程序输出。

Program exited with code 027. <--------程序退出,调试结束。

(gdb) q     <--------------------- 退出gdb。

hchen/test>

好了,有了以上的感性认识,还是让我们来系统地认识一下gdb吧。

三、adb + GDB用法

3.1 静态调试

(1)通过命令ulimit -c unlimited设置系统生成Core

 Dump文件

gdb+ 带符号表的可执行文件+Core Dump文件

该方式可以直接定位到错误发生的地方。

(2)直接gdb+ 带符号表的可执行文件

该方式需要启动之后运行run命令才能执行调试。

3.2 动态调试

就是用attach的方式连接到正在运行中的进程上面去,进行调试,下面是利用PC机动态调试手机上面的进程的操作步骤。

編譯小程序:

arm-none-linux-gnueabi-gcc -static HelloWorld.c -o HelloWorld

在android運行軟件-小程序

<1>adb shell ps -elf                                                  查看所需要调试程序的进程号

<2>adb shell gdbserver :5039 --attach PID          attach到对应进程号上面

<3>打开另一个终端,adb forward tcp:5039 tcp:5039

<4>運行arm-eabi-gdb

路径:

/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-gdb

<5>set solib-absolute-prefix + 符号表文件路径

<6>set  solib-search-path + 带符号表可执行文件路径:动态共享库文件路径:....

<7>鏈接遠端程序target  remote:5039  進行調試 

四、GDB 命令(一)

gcc -g main.c  -o  xxxxx   //在目标文件加入源代码的信息

gdb a.out     

(gdb) start                        //开始调试

(gdb) n                            //一条一条执行

(gdb) step/s                        //执行下一条,如果函数进入函数

(gdb) backtrace/bt                  //查看函数调用栈帧

(gdb) info/i locals                //查看当前栈帧局部变量

(gdb) frame/f                      //选择栈帧,再查看局部变量

(gdb) print/p                      //打印变量的值

(gdb) finish                        //运行到当前函数返回

(gdb) set var sum=0                //修改变量值

(gdb) list/l 行号或函数名            //列出源码

(gdb) display/undisplay sum        //每次停下显示变量的值/取消跟踪

(gdb) break/b  行号或函数名          //设置断点

(gdb) continue/c                    //连续运行

(gdb) info/i breakpoints            //查看已经设置的断点

(gdb) delete breakpoints 2          //删除某个断点

(gdb) disable/enable breakpoints 3  //禁用/启用某个断点

(gdb) break 9 if sum != 0          //满足条件才激活断点

(gdb) run/r                        //重新从程序开头连续执行

(gdb) watch input[4]                //设置观察点

(gdb) info/i watchpoints            //查看设置的观察点

(gdb) x/7b input                    //打印存储器内容,b--每个字节一组,7--7组

(gdb) disassemble                  //反汇编当前函数或指定函数

(gdb) si                                  // 一条指令一条指令调试 而 s 是一行一行代码

(gdb) info registers                // 显示所有寄存器的当前值

(gdb) x/20 $esp                    //查看内存中开始的20个数

(gdb) i   threads                      //查看threads

(gdb) t    x                             //切换至x线程下调试

(gdb) i     r                              //查看寄存器状态

(gdb) i proc m                      //(info proc mappings 的简写)核查Mapped address

(gdb) i  signals                    //查看所有信号量的设置情况。

(gdb) p $eax                        //查看eax寄存器的内容。

(gdb) generate-core-file        //生成转储文件

(gdb) i  p                                //info proc  查看进程信息

(未完待续)

四、GDB 命令(二)

attach 到进程

调试守护进程等已经启动的进程,或是调试陷入死循环而无法返回的进程时使用。

attach pid

以sleep命令为举例:

ps aux| grep sleep  查看sleep进程ID  若为17606

(gdb) attach 17606



五、GDB原理及调试实例参考

GDB原理及调试实例(推荐)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 程序调试的基本思想是“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环过程,根据现象如何假设错误原...
    Manfred_Zone阅读 16,593评论 0 26
  • 版权声明:本文为 cdeveloper 原创文章,可以随意转载,但必须在明确位置注明出处! gdb 简介 gdb ...
    登龙zZ阅读 7,581评论 1 15
  • 在花开的日子,曾从百花丛中走过,看尽缤纷花朵娇艳盛开;叶落的时候,曾踩着红黄斑驳的记忆,找寻逝去的时光。 君子兰 ...
    第8日蝉阅读 1,051评论 0 0
  • 生存还是死亡?这是多年以来一直笼罩在地方网站头顶上的巨大阴影。 灭亡说这样认为,随着BAT的触角越来越深,随着垂直...
    李光春阅读 212评论 0 1
  • 好久没来这里了,今天是小雪节气,心里也是一阵阵寒意,见过太多失败的婚姻都源自于根本的不欣赏不理解,我和他现在大概就...
    此处有危险请远离阅读 258评论 0 0