gdb篇

简介: 转自:http://www.cnblogs.com/ypchenry/p/3668572.html 1.gdb的原理 熟悉linux的同学面试官会问你用过gdb么?那好用过,知道gdb是怎么工作的么?然后直接傻眼。

转自:http://www.cnblogs.com/ypchenry/p/3668572.html

1.gdb的原理

熟悉linux的同学面试官会问你用过gdb么?那好用过,知道gdb是怎么工作的么?然后直接傻眼。。。 gdb是怎么接管一个进程?并且能获取这个进程的变量、堆栈、寄存器、内存映像等信息的呢?还可以打断点执行?这些都是gdb一些基本的功能。 很简单,ptrace,好来看看manual上这个系统调用的定义。

#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,void *addr, 
                    void *data);

 

简单描述: ptrace系统调用提供一种方法使某一父进程(叫做"tracer")可以观察并控制另外一个进程(叫做"tracee")的执行,而且还可以检查并改变执行tracee进程时的内存映像和寄存器。这个系统调用主要用来实现断点调试和函数调用跟踪( It is primarily used to implement breakpoint debugging and system call tracing)。

2.gdb将高级语言转成汇编

对于c、c++这样的语言,如果不注意内存释放经常会出现“野指针”、“空指针”等,程序dump掉的时候要找清楚那地方crash了,汇编指令显的非常重要。 比如:

程序1:

复制代码
#include <stdio.h>
struct foo{
    int i;
    char a[0];
};
struct fool{
    struct foo *henry;
};
int main()
{
    struct fool test={0};
    if(test.henry->a)
        printf("%x\n",test.henry->a);
    return 0;
}
复制代码

 

程序2:

复制代码
#include <stdio.h>
struct foo{
    int i;
    char *a;
};
struct fool{
    struct foo *henry;
};
int main()
{
    struct fool test={0};
    if(test.henry->a)
        printf("%x\n",test.henry->a);
    return 0;
}
复制代码

 

第一个程序不会core dump,而第二个程序core dump掉了。原因在第12行程序1访问的a是数组的地址,而程序2访问的时指针a的内容,a为NULL指针,访问其内容当然时非法的。你可能要问了,你为什么知道程序1访问的是地址而程序2访问的是内容呢? 那就需要汇编指令帮忙了。

题外话:程序2dump会产生core文件,如果没有出现core文件,用ulimit -c unlimited命令产生。
复制代码
[henry@localhost core]$ gdb -c core.4340 
GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".

[New LWP 4340]
Missing separate debuginfo for the main executable file
Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/73/a4410588cf88e43ecdfa6825cd15160aa6ddc7
Core was generated by `./struct_dump1'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000000000400544 in ?? ()
(gdb) file struct_dump1
Reading symbols from /home/henry/code/core/struct_dump1...done.
(gdb) bt
#0  0x0000000000400544 in main () at struct_dump1.c:12
(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400530 <+0>:    push   %rbp
   0x0000000000400531 <+1>:    mov    %rsp,%rbp
   0x0000000000400534 <+4>:    sub    $0x10,%rsp
   0x0000000000400538 <+8>:    movq   $0x0,-0x10(%rbp)
   0x0000000000400540 <+16>:    mov    -0x10(%rbp),%rax
=> 0x0000000000400544 <+20>:    mov    0x8(%rax),%rax
   0x0000000000400548 <+24>:    test   %rax,%rax
   0x000000000040054b <+27>:    je     0x400567 <main+55>
   0x000000000040054d <+29>:    mov    -0x10(%rbp),%rax
   0x0000000000400551 <+33>:    mov    0x8(%rax),%rax
   0x0000000000400555 <+37>:    mov    %rax,%rsi
   0x0000000000400558 <+40>:    mov    $0x400600,%edi
   0x000000000040055d <+45>:    mov    $0x0,%eax
   0x0000000000400562 <+50>:    callq  0x400410 <printf@plt>
   0x0000000000400567 <+55>:    mov    $0x0,%eax
   0x000000000040056c <+60>:    leaveq 
   0x000000000040056d <+61>:    retq 
End of assembler dump.
复制代码

 

上面看到程序执行时用bt提示程序在12行dump掉了,然后转换成汇编代码可以看到12行执行的时mov指令。

  • 对于char a[0]来说,汇编代码用了lea指令,lea 0×8(%rax), %rax
  • 对于char *a来说,汇编代码用了mov指令,mov 0×8(%rax), %rax

lea指令是把地址放进去,而mov是把内容放进去,而NULL指针的内容是不能访问的。这就是前面提到的*a 和a[0]的不同。1

nisi是单步执行汇编命令,和nextstep一样,n表示在当前函数一步步执行,s代表跟踪函数,可以从当前函数跳到另一个函数。 display可以显示一些寄存器内容,如display /x $pc显示程序计数器。 info reg显示所有寄存器内容。

 

tips——关于NULL指针:

如果程序里有NULL指针,NULL指针会指向系统为程序分配的段地址的开始,系统为段开头64k做苛刻的规定。程序中(低访问权限)访问要求高访问权限的这64K内存被视作是不容许的,会引发Access Volitation 错误。64K内存是一块保留内存(即不能被程序动态内存分配器分配,不能被访问,也不能被使用),就是简单的保留,不作任何使用。2

下面的代码是对空指针的测试:

复制代码
#define NULL (void*)0
int main()
{
  int *p1 = NULL;
  int *p2 = NULL;
  int *p3 = NULL;
  return 0;
}
 

下面是用gdb测试:

[henry@localhost core]$ gcc -g null_point_test.c -o null_point_test
[henry@localhost core]$ gdb null_point_test 
GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
..
Reading symbols from /home/henry/code/core/null_point_test...done.
(gdb) list
1    #define NULL (void*)0
2    int main()
3    {
4      int *p1 = NULL;
5      int *p2 = NULL;
6      int *p3 = NULL;
7      return 0;
8    }
(gdb) b 7
Breakpoint 1 at 0x40050c: file null_point_test.c, line 7.
(gdb) r
Starting program: /home/henry/code/core/null_point_test 

Breakpoint 1, main () at null_point_test.c:7
7      return 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.18-12.fc20.x86_64
(gdb) p &p1
$1 = (int **) 0x7fffffffdf08
(gdb) p &p2
$2 = (int **) 0x7fffffffdf00
(gdb) p &p3
$3 = (int **) 0x7fffffffdef8
(gdb) p &p1
$4 = (int *) 0x0
(gdb) p &p2
$5 = (int *) 0x0
(gdb) p &p3
$6 = (int *) 0x0
(gdb) bt
#0  main () at null_point_test.c:7
(gdb) p main
$4 = {int ()} 0x4004f0 <main>
(gdb) 
复制代码

 

 

可以看出gdb测试结果p1 p2 p3的内容即null指针的地址都是

(int *) 0x0

正如上面多说空指针指向段首,并且都指向一个内存单元,null指针只有一个。

3.gdb调试core文件

gdb -c core文件命令调试core文件,调试过程种可能会总是一堆问号的问题,用symbol-file core文件对应的bin文件命令添加字符集即可。

4.gdb条件断点

已经有了断点break_num将其转化成条件断点:condition break_num(断点编号) cond(条件),当满足条件cond时,GDB才会在断点break_num处暂停程序的执行。

 break break_num if cond(条件)定义一个断点并使之成为条件断点。

 tbreak break_num临时断点,断点执行一次后此段点无效。

 commands breakpoint_number可以设置执行断点breakpoint_number时执行一段程序,有点批量执行的意思,以end结束。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
6月前
|
NoSQL Linux 文件存储
GDB学习入门之gdb准备2
GDB学习入门之gdb准备2
56 0
GDB学习入门之gdb准备2
|
6月前
|
NoSQL Shell Linux
GDB学习入门之gdb准备
GDB学习入门之gdb准备
59 0
|
4月前
|
NoSQL Java Linux
gdb使用
gdb使用
36 0
|
5月前
|
NoSQL Linux C语言
GDB:强大的GNU调试器
GDB:强大的GNU调试器
|
6月前
|
NoSQL Linux C语言
调试器gdb
调试器gdb
69 0
|
6月前
|
NoSQL 编译器 Linux
GDB 学习入门之GDB初识
GDB 学习入门之GDB初识
74 0
|
NoSQL Linux C语言
gcc 和gdb
恶补一下大学Linux C的常用操作
93 0
|
NoSQL Linux
GDB学习笔记
编译生成执行文件:(Linux下) g++ -std=c++11 -g tst.cpp -o tst   基本操作 $gdb $file 可执行文件名 $start //进入被调用的函数 $s //打印变量的值...
955 0
|
NoSQL 开发工具 git
GDB 配置
调试器 GDB 的配置
5579 0