linux下GDB調試

  linux下GDB是一個很是強大的調試工具,可是他不像vs同樣具備強大的圖形界面,基本都靠命令來進行調試,對於新手來講也算是個坎。下面就跟你們一塊兒探究一下gdb這個強大的調試工具。html

1.開啓core

1.1 查看core是否開啓

$ulimit -c
0

  0:表示關閉,不會生成core文件;不然此值說明core文件的最大限制;linux

1.2 打開開啓core

  打開/etc/profileredis

$sudo gedit /etc/profile

  在文件末尾加上:ubuntu

ulimit -S -c unlimited > /dev/null 2>&1

  wq!保存退出。而後讓設置當即生效:sass

$source /etc/profile

  而後輸入命令:函數

$ulimit -c
unlimited

  core文件已經開啓。unlimited爲不限制core文件大小。工具

1.3 設置保存core文件的路徑和命名方式

$sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t

  /tmp目錄爲core文件的保存路徑,core文件命名格式爲:ui

%%:至關於%
%p:至關於<pid>
%u:至關於<uid>
%g:至關於<gid>
%s:至關於致使dump的信號的數字
%t:至關於dump的時間
%e:至關於執行文件的名稱
%h:至關於hostname

2.編譯

2.1 先準備一份簡單的源碼:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include<pthread.h>

void printinfo(const char* pstr)
{
    printf("%s\n", pstr);
}
void* threadproc1(void* arg)
{
    int i = 0;
    while(i < 20)//
    {
    printf("I am threadproc1, tid:%u, i:%d\n", pthread_self(), i++);
    sleep(1);
    }

    return NULL;
}

void* threadproc2(void* arg)
{
    int i = 0;
    while(i < 20)//
    {
    printf("I am threadproc2, tid:%u, i:%d\n", pthread_self(), i++);
    sleep(1);
    }

    return NULL;
}

int main(int narg, const char** args)
{
    const char* pstr = args[1];
    printinfo(pstr);

    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,threadproc1,NULL);//建立線程1
    pthread_create(&tid2,NULL,threadproc2,NULL);//建立線程2
    pthread_join(tid1,NULL);//等待線程1
    printf("thread1 joined\n");
    pthread_join(tid2,NULL);//等待線程2 
    printf("thread2 joined\n");
    free((void*)pstr);
    char* pend = "main end\n";
    printf(pend);
    free(pend);
    return 0;
}

2.2 編譯源碼

  將主程序命名爲gdbtest.cpp,使用g++進行編譯:線程

$g++ -g -c gdbtest.cpp
$g++ -o gdbtest gdbtest.o -lpthread

  注意,編譯時須要添加-g選項,通知編譯器生成gdb調試信息。代碼編譯完成後,將在當前目錄下生成gdbtest可執行程序。debug

3 gdb調試

3.1 gdb調試經常使用命令說明

  1.gdb $(filename)
  啓動gdb調試,$(filename)也可使用file命令指定;

  2.file $(filename)
  設置gdb調試的文件名

  3. set args $(arg1) $(arg2) $(arg3) ...
  設置main函數輸入參數

  4.b/break linenum
  設置斷點,linenum爲行號

  5.r/run $(arg1) $(arg2) $(arg3) ...
  開始運行gdb調試,參數若是沒有或者已經設置,能夠不輸入

  6.p/print $(var)
  打印變量

  7.display $(var)
  顯示變量

  8.n/next
  單步執行

  9.bt
  顯示棧幀以及局部變量

  10.s/step
  進入子函數

  11.up
  退出當前函數,返回上一級堆棧

  12.c/continue
  繼續執行

  13.list
  輸出從上次調用list命令開始日後的10行程序代碼

  14.info threads
  線程信息

  15.thread id
  切換調試線程

  16.tbreak/tb
  設置臨時斷點,只生效一次。

  16.info break/i b
  顯示全部斷點信息

3.2 gdb調試

  使用GDB運行gdbtest

$gdb gdbtest

  在37(const char* pstr = args[1];)行設置斷點

(gdb)b 37
Breakpoint 1 at 0x40090c: file gdbtest.cpp, line 37.

  gdb調試運行,"hello, welcome to gdb debug world!"爲運行參數

(gdb) run "hello, welcome to gdb debug world!"
Starting program: /home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest "hello, welcome to gdb debug world!"
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (narg=2, args=0x7fffffffdf08) at         gdbtest.cpp:37
37        const char* pstr = args[1];

  程序運行後,中止在37行斷點處。
  p/print:打印args[0]變量:

(gdb) p args[0]
$3 = 0x7fffffffe278 "/home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest"

  display:打印變量

(gdb) display args[1]
1: args[1] = 0x7fffffffe2b0 "hello, welcome to gdb debug world!"

  n/next:執行單步調試

(gdb) n
38        printinfo(pstr);

  s/step:進入子函數

(gdb) s
printinfo (pstr=0x7fffffffe2b0 "hello, welcome to gdb debug world!")
at gdbtest.cpp:9
9        printf(pstr);

  up:退出當前函數,返回上一級堆棧:

(gdb) up
#1  0x0000000000400924 in main (narg=2, args=0x7fffffffdf08) at gdbtest.cpp:38
38        printinfo(pstr);
(gdb) n
main (narg=2, args=0x7fffffffdf08) at gdbtest.cpp:41
41        pthread_create(&tid1,NULL,threadproc1,NULL);//建立線程1
1: args[1] = 0x7fffffffe2b0 "hello, welcome to gdb debug world!"

  list:輸出從上次調用list命令開始日後的10行程序代碼

(gdb) list
36    {
37        const char* pstr = args[1];
38        printinfo(pstr);
39    
40        pthread_t tid1,tid2;
41        pthread_create(&tid1,NULL,threadproc1,NULL);//建立線程1
42        pthread_create(&tid2,NULL,threadproc2,NULL);//建立線程2
43        pthread_join(tid1,NULL);//等待線程1
44        printf("thread1 joined\n");
45        pthread_join(tid2,NULL);//等待線程2

  輸出線程信息:

(gdb) info threads
Id   Target Id         Frame 
* 1    Thread 0x7ffff7fdd700 (LWP 5045) "gdbtest" main (narg=2, 
args=0x7fffffffdf08) at gdbtest.cpp:42
2    Thread 0x7ffff77ef700 (LWP 5047) "gdbtest" clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:81

  bt full輸出調用棧信息
(gdb) bt full

0 main (narg=2, args=0x7fffffffdf08) at gdbtest.cpp:42

pstr = 0x7fffffffe2b0 "hello, welcome to gdb debug world!"
    tid1 = 140737345681152
    tid2 = 4196832
    pend = 0x7fffffffdf00 "\002"

  c/continue:繼續執行

(gdb) c
Continuing.
[New Thread 0x7ffff77ef700 (LWP 4517)]
hello, welcome to gdb debug world!
I am threadproc1, tid:4152293120, i:0
[New Thread 0x7ffff6fee700 (LWP 4518)]
I am threadproc2, tid:4143900416, i:0
...
I am threadproc1, tid:4152293120, i:19
I am threadproc2, tid:4143900416, i:19
[Thread 0x7ffff6fee700 (LWP 4518) exited]
thread1 joined
thread2 joined

  程序在50行free(pend)時崩潰,如下爲core dump信息:

*** Error in `/home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest': munmap_chunk(): invalid pointer: 0x00007fffffffe2b0 ***
[Thread 0x7ffff77ef700 (LWP 4517) exited]
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7ffff78677e5]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7ffff7874698]
/home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest[0x40099c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7ffff7810830]
/home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest[0x400759]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 950010                             /home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest
00600000-00601000 r--p 00000000 08:01 950010                             /home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest
00601000-00602000 rw-p 00001000 08:01 950010                             /home/zwu/Desktop/work/coding/transcode/gdbtest/gdbtest
00602000-00623000 rw-p 00000000 00:00 0                                  [heap]
7ffff65d8000-7ffff65ee000 r-xp 00000000 08:01 1054507                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff65ee000-7ffff67ed000 ---p 00016000 08:01 1054507                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff67ed000-7ffff67ee000 rw-p 00015000 08:01 1054507                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff67ee000-7ffff67ef000 ---p 00000000 00:00 0 
7ffff67ef000-7ffff6fef000 rw-p 00000000 00:00 0 
7ffff6fef000-7ffff6ff0000 ---p 00000000 00:00 0 
7ffff6ff0000-7ffff77f0000 rw-p 00000000 00:00 0 
7ffff77f0000-7ffff79b0000 r-xp 00000000 08:01 1054469                    /lib/x86_64-linux-gnu/libc-2.23.so
7ffff79b0000-7ffff7bb0000 ---p 001c0000 08:01 1054469                    /lib/x86_64-linux-gnu/libc-2.23.so
7ffff7bb0000-7ffff7bb4000 r--p 001c0000 08:01 1054469                    /lib/x86_64-linux-gnu/libc-2.23.so
7ffff7bb4000-7ffff7bb6000 rw-p 001c4000 08:01 1054469                    /lib/x86_64-linux-gnu/libc-2.23.so
7ffff7bb6000-7ffff7bba000 rw-p 00000000 00:00 0 
7ffff7bba000-7ffff7bd2000 r-xp 00000000 08:01 1054615                    /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7bd2000-7ffff7dd1000 ---p 00018000 08:01 1054615                    /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd1000-7ffff7dd2000 r--p 00017000 08:01 1054615                    /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd2000-7ffff7dd3000 rw-p 00018000 08:01 1054615                    /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 
7ffff7dd7000-7ffff7dfd000 r-xp 00000000 08:01 1054441                    /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7fdc000-7ffff7fe0000 rw-p 00000000 00:00 0 
7ffff7ff6000-7ffff7ff7000 rw-p 00000000 00:00 0 
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00025000 08:01 1054441                    /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffd000-7ffff7ffe000 rw-p 00026000 08:01 1054441                    /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Thread 1 "gdbtest" received signal SIGABRT, Aborted.
0x00007ffff7825428 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
54    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.

  注:gdb調試時,遇到coredump將直接輸出coredump信息,不會生成core文件。

4.coredump文件調試

  退出gdb,在terminal中直接運行:

$./gdbtest
*** Error in `./gdbtest': free(): invalid pointer: 0x0000000000400ac6 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f83f713e7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f83f714737a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f83f714b53c]
./gdbtest[0x4009c1]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f83f70e7830]
./gdbtest[0x400759]

  程序崩潰,並在/tmp目錄下產生core-gdbtest..ubuntu.的core dump文件,若是想要解析該文件,只需輸入gdb $(program) $(coredump)

$gdb gdbtest core-gdbtest.*.ubuntu.*
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 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-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 gdbtest...done.
[New LWP 5183]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./gdbtest'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f83f70fc428 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
    54    ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.

  輸入bt,查看崩潰程序的調用棧

(gdb) bt
#0  0x00007f83f70fc428 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f83f70fe02a in __GI_abort () at abort.c:89
#2  0x00007f83f713e7ea in __libc_message (do_abort=do_abort@entry=2, 
    fmt=fmt@entry=0x7f83f7257ed8 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f83f714737a in malloc_printerr (ar_ptr=<optimized out>, 
    ptr=<optimized out>, str=0x7f83f7254caf "free(): invalid pointer", 
    action=3) at malloc.c:5006
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0)
    at malloc.c:3867
#5  0x00007f83f714b53c in __GI___libc_free (mem=<optimized out>)
    at malloc.c:2968
#6  0x00000000004009c1 in main (narg=1, args=0x7fff510a3d48) at gdbtest.cpp:50

  在沒有調試信息的狀況下,打開coredump堆棧,並不會直接顯示core的代碼行,這時可使用disassemble打開該幀函數的反彙編代碼,而後使用匯編代碼來判斷程序崩潰的地方:

(gdb) disassemble

Dump of assembler code for function __GI_raise: 0x00007f83f70fc3f0 <+0>: mov %fs:0x2d4,%ecx 0x00007f83f70fc3f8 <+8>: mov %fs:0x2d0,%eax 0x00007f83f70fc400 <+16>: movslq %eax,%rsi 0x00007f83f70fc403 <+19>: test %esi,%esi 0x00007f83f70fc405 <+21>: jne 0x7f83f70fc438 <__GI_raise+72> 0x00007f83f70fc407 <+23>: mov $0xba,%eax 0x00007f83f70fc40c <+28>: syscall 0x00007f83f70fc40e <+30>: mov %eax,%ecx 0x00007f83f70fc410 <+32>: mov %eax,%fs:0x2d0 0x00007f83f70fc418 <+40>: movslq %eax,%rsi 0x00007f83f70fc41b <+43>: movslq %edi,%rdx 0x00007f83f70fc41e <+46>: mov $0xea,%eax 0x00007f83f70fc423 <+51>: movslq %ecx,%rdi 0x00007f83f70fc426 <+54>: syscall => 0x00007f83f70fc428 <+56>: cmp $0xfffffffffffff000,%rax 0x00007f83f70fc42e <+62>: ja 0x7f83f70fc450 <__GI_raise+96> 0x00007f83f70fc430 <+64>: repz retq 0x00007f83f70fc432 <+66>: nopw 0x0(%rax,%rax,1) 0x00007f83f70fc438 <+72>: test %ecx,%ecx 0x00007f83f70fc43a <+74>: jg 0x7f83f70fc41b <__GI_raise+43> 0x00007f83f70fc43c <+76>: mov %ecx,%edx 0x00007f83f70fc43e <+78>: neg %edx---Type <return> to continue, or q <return> to quit---

相關文章
相關標籤/搜索