gdb介绍和实战

      本文我将简单介绍gdb调试的原理和编译,和常见的应用场景,具体由以下四点展开。

一、gdb工作原理

      gdb:GNU debugger
      UNIX及UNIX-like下一个强大的命令行的调试工具

1.1、gdb整体架构

      gdb调试的整体架构如下图所示:
在这里插入图片描述
      可以发现gdb调试不管是本地调试还是远程调试,都是基于ptrace系统调用来实现的。

1.2、ptrace

      ptrace系统调用函数的原型:

long ptrace(enum __ptrace_request request,pid_t pid,void *addr,void *data);

      ptrace系统调用提供了一种方法,让父进程可以观察和控制其它进程的执行,检查和改变其核心映像及寄存器。主要用来实现断点调试和系统调用跟踪。
enum __ptrace_request request:指示了ptrace要执行的命令。
      pid_t pid: 指示ptrace要跟踪的进程。
      void *addr: 指示要监控的内存地址。
      void *data: 存放读取出的或者要写入的数据。
      request参数主要选项:
      PTRACE_TRACEME:由子进程调用,表示本进程将被其父进程跟踪,交付给这个进程的所有信号,即使信号是忽略处理的(除SIGKILL之外),都将使其停止,父进程将通过wait()获知这一情况。
      PTRACE_ATTACH:attach到一个指定的进程,使其成为当前进程跟踪的子进程,而子进程的行为等同于它进行了一次PTRACE_TRACEME操作。但是,需要注意的是,虽然当前进程成为被跟踪进程的父进程,但是子进程使用getppid()的到的仍将是其原始父进程的pid。
这下子gdb的attach功能也就明朗了。当你在gdb中使用attach命令来跟踪一个指定进程/线程的时候,gdb就自动成为该进程的父进程,而被跟踪的进程则使用了一次PTRACE_TRACEME,gdb也就顺理成章的接管了这个进程。
      PTRACE_CONT:继续运行之前停止的子进程。可同时向子进程交付指定的信号。

1.3、gdb三种调试方式

      1)、attach并调试一个已经运行的进程:
确定需要进行调试的进程id ;
运行gdb,输入attch pid,如:gdb 12345。gdb将对指定进行执行如下操作:ptrace(PTRACE_ATTACH,pid,0,0)
      2)、运行并调试一个新的进程
运行gdb,通过命令行参数或file指定目标调试程序,如gdb ./test ;
输入run命令,gdb执行下述操作:通过fork()系统调用创建一个新进程
在新创建的子进程中调用ptrace(PTRACE_TRACEME,0,0,0),在子进程中通过execv()系统调用加载用户指定的可执行文件。
      3)、远程调试目标主机上新创建的进程
gdb运行在调试机,gdbserver运行在目标机,通过二者之间定义的数据格式进行通信。

二、gdb源码编译

      由于在实际项目中我们经常会面对不同的芯片平台,如果遇到不同的编译器,难免我们需要重新交叉编译一下,因此,本章我们简单总结一下gdb交叉编译的步骤(以gdb-7.6和海思sdk为例)

2.1、下载gdb源码

      下载地址为:http://ftp.gnu.org/gnu/gdb/

2.2、解压

      tar xvfz gdb-7.6.tar.gz

2.3、进入该目录,进行配置(生成Makefile)
cd gdb-7../configure --target=arm-hisiv100nptl-linux --program-prefix=arm-hisiv100nptl-linux-  --prefix=/home/usr/gdb-build   

      :–target=arm-hisiv100nptl-linux意思是说目标平台是运行于ARM体系结构的linux内核;–program-prefix=arm-hisiv100nptl-linux是指生成的可执行文件的前缀,比如arm-hisiv100nptl-linux-gdb,–prefix是指生成的可执行文件安装在哪个目录,这个目录需要根据实际情况作选择。如果该目录不存在,会自动创建,当然,权限足够的话。

2.4、编译、安装
make ;make install 

      会在–prefix指定的目录下生成四个子目录:bin、lib、share、include我们需要的arm-linux-gdb就在其中的bin目录下。

三、gdb调试coredump

3.1、什么是coredump

      程序异常终止或奔溃时,系统将此刻内存中的内容dump出来,将一些调试信息写到一个core文件里,这个过程叫coredump.

3.2、什么时候产生core文件

(1)、内存访问越界
      a) 由于使用错误的下标,导致数组访问越界。
      b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
      c) 使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。
(2)、多线程程序使用了线程不安全的函数。
      应该使用可重入的函数,它们很容易被用错:如 ctime_r()\rand_r()等。
(3)、多线程读写的数据未加锁保护。
      对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成coredump。
(4)、非法指针
      a) 使用空指针
      b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump。
(5)、堆栈溢出
      不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。

3.3、什么时候不产生core文件

(1)、进程是设置-用户-ID,而且当前用户并非程序文件的所有者;
(2)、进程是设置-组-ID,而且当前用户并非该程序文件的组所有者;
(3)、用户没有写当前工作目录的许可权;
(4)、文件太大。Core文件的许可权(假定该文件在此之前不存在)通常是用户读/写,组读或其他读。

3.4、生成core文件的步骤

(1)、通过命令放开core的大小限制

ulimit –c unlimited (或者指定大小)

(2)、挂载目录
(3)、修改core文件的名字格式,以免多次被覆盖

 hik_echo “/mnt/nfs/core.%e.%p.%t.%s” > /proc/sys/kernel/core_pattern

(4)、关闭看门狗

hik_echo ‘C’ > /proc/OSAL/wdt

或者直接在代码里注释掉看门狗相关代码

3.5、gdb调试coredump实战

(1)、gdb调试数组越界导致的崩溃
      test.c
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
      注意:不要遗忘:①放开生成core文件限制;②先执行以下可执行文件test_debug,待崩溃后会自动生成core文件
      分析:
      对数组访问时下标越界,从而导致奔溃,用gdb调试core文件的调试信息中,打印出了奔溃时的错误信号,并打出具体函数名和行数。
(2)、gdb调试堆栈溢出造成的崩溃
      test1.c
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
      分析:
      由于局部变量分配的内存过大,导致程序运行时出现崩溃,从而产生core文件,通过bt打印栈帧信息,发现错误的函数名和代码行数。
(3)、gdb调试空指针引起的崩溃
在这里插入图片描述
在这里插入图片描述
      实际操作中,我们直接用gdb调试就已经能够定位出具体哪一行,查看代码发现和我们想要的结果一致(事先已经将指针赋值注释掉):
在这里插入图片描述
      补充:实际操作中,我们还有一种快速定位崩溃点的方法。
      在编译的时候,同时生成hicore_debug,放开设备内核打印,待设备死机时会有PC指针,通过将hicore_debug反汇编可以快速定位,(此方法针对hicore文件较小的情况,否则反汇编时间太长)
      命令:arm-hisiv500-linux-objdump -S hicore > hicore.txt

四、gdbserver 远程调试

4.1、gdbserver介绍

      gdbserver是一种远程调试工具,由目标板(嵌入式设备)和pc机组成,通过在设备端运行gdbserver,设置监听的IP和端口号,在pc端建立连接来监听设备端的运行。具体编译和gdb编译类似,可在编译gdb时一起编译出gdbserver,这里不再重复。

4.2、gdbserver的优点

(1)、与gdb工具调试命令相似,具有较好的兼容性
(2)、可以在不破坏环境的前提下进行调试(设备运行时就能使用)
(3)、针对死锁问题具有较好的定位效果

4.3、使用方式

(1)、将之前生成的gdbsrver 调试程序放在目标板(设备端)上或者通过nfs方式运行也可以.这样就可以用gdb和gdbserve 来调试开发板上的程序了。
(2)、要调试程序首先在目标板上运行gdbserver

./gdbserver 192.168.1.100:2345 test 

      192.168.1.100 为目标板ip地址,2345是开通目标板的这个端口号做为通信端口。
      test 是要调试的程序(编译 -g好的)
(3)、在PC上运行gdb程序

./arm-hisiv100nptl-linux-gdb test 

      进入gdb 调试状态后:
      输入target remote 192.168.1.100:2345
(4)、在pc端开始调试,与gdb调试命令一致,但需要注意的是,用“c”来执行命令运行,而不是run/r,因为程序已经在设备端由gdbserver启动了,打印信息在设备端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值