首页 > 学院 > 操作系统 > 正文

我的日常工具——gdb篇

2024-06-28 13:26:51
字体:
来源:转载
供稿:网友
我的日常工具——gdb篇我的日常工具——gdb篇

03 APR 2014


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.fc20Copyright (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 fileTry: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/73/a4410588cf88e43ecdfa6825cd15160aa6ddc7Core was generated by `./struct_dump1'.Program terminated with signal SIGSEGV, Segmentation fault.#0  0x0000000000400544 in ?? ()(gdb) file struct_dump1Reading symbols from /home/henry/code/core/struct_dump1...done.(gdb) bt#0  0x0000000000400544 in main () at struct_dump1.c:12(gdb) disassemble mainDump 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*)0int 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.fc20Copyright (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) list1    #define NULL (void*)02    int main()3    {4      int *p1 = NULL;5      int *p2 = NULL;6      int *p3 = NULL;7      return 0;8    }(gdb) b 7Breakpoint 1 at 0x40050c: file null_point_test.c, line 7.(gdb) rStarting program: /home/henry/code/core/null_point_test Breakpoint 1, main () at null_point_test.c:77      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结束。

引用:

  1. 指针和数组的差别?

  2. 空指针保护政策?


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表