GDB抓蟲之旅(上篇)

本文來自網易雲社區。html


做者:盛國存linux


前言

問: gdb是什麼?
答: 強大的UNIX下命令行調試工具。

問: gdb能幹什麼?
答: 讓你爲所欲爲的駕馭你的程序;Start、Stop、Examine、Change。

問: 咱們爲何要學習gdb?
答: 欲善其事,必先利其器;利用gdb進一步的定位程序異常。

問: 本次分享的宗旨?
答: gdb的介紹和使用入門,爲你們抓蟲多提供一個選擇。


抓蟲從0開始

前期準備

1.包含有調試信息的可執行文件ios

2.編譯時加-g選項便可,不建議開優化選項c++

GDB的啓動

gdb <program>gdb <program> coregdb <program> <PID>
(gdb) file <program>

抓蟲流程

實戰1 :  GDB基礎命令的使用


1.一、示例程序(example_1.cpp)算法

#include <iostream>#include <string>using namespace std;int foo(int m, int n){    return 1;
}int foo(int n){    int result=0;    for (int i=0;i<=n;i++)
    {
        result+=n;
    }    return result;
}int main(){    string s1="dafdf";    char * s2;//  s1=s2;

    int sum =0;    for (int i=1;i<=100;i++)
    {
        sum+=i;
    }

    cout<<"result[1-100]="<<sum<<endl;
    cout<<"result[1-250]="<<foo(250)<<endl;    return 0;
}


1.二、調試準備 編譯命令:g++ -g -Wall -o example_1 example_1.cppshell


1.三、啓動gdb多線程

$ gdb example_1
GNU gdb Red Hat Linux (6.3.0.0-1.96rh)
Copyright 2004 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 "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".


1.四、輔助性命令架構

(gdb) cd ..
Working directory /home/work/testers/sgc.
(gdb) shell ls
autotest  client  Makefile  spanti  spantispam_if.h  study(gdb) cd study/
Working directory /home/work/testers/sgc/study.
(gdb) pwd
Working directory /home/work/testers/sgc/study.
(gdb) help run
Start debugged program.  You may specify arguments to give it.
Args may include "*", or "[...]"; they are expanded using "sh".
Input and output redirection with ">", "<", or ">>" are also allowed.

With no arguments, uses arguments last specified (with "run" or "set args").
To cancel previous arguments and run with no arguments,use "set args" without arguments.


1.五、設置斷點命令app

//查看源代碼信息(gdb) l17                      result+=n;18              }19              return result;2021      }2223      int main()24      {2526              string s1="dafdf";
(gdb) l 11       #include <iostream>2       #include <string>345       using namespace std;6       int foo(int m, int n)7       {89               return 1;10(gdb) l example_1.cpp:1611      }12      int foo(int n)13      {14              int result=0;15              for (int i=0;i<=n;i++)16              {17                      result+=n;18              }19              return result;20(gdb) l foo(int)8
9               return 1;1011      }12      int foo(int n)13      {14              int result=0;15              for (int i=0;i<=n;i++)16              {17                      result+=n;
//設置斷點(gdb) b 17Breakpoint 1 at 0x400c07: file example_1.cpp, line 17.(gdb) b main
Breakpoint 2 at 0x400c27: file example_1.cpp, line 26.(gdb) info br
Num Type           Disp Enb Address            What1   breakpoint     keep y   0x0000000000400c07 in foo(int) at example_1.cpp:17
2   breakpoint     keep y   0x0000000000400c27 in main at example_1.cpp:26


1.六、執行控制命令分佈式

(gdb) r
Starting program: /home/work/testers/sgc/study/example_1 

Breakpoint 2, main () at example_1.cpp:2626              string s1="dafdf";
(gdb) c
Continuing.
result[1-100]=5050Breakpoint 1, foo (n=250) at example_1.cpp:1717                      result+=n;
(gdb) n   
15              for (int i=0;i<=n;i++)


1.七、程序信息查看命令

//查看變量信息
(gdb) p result$1 = 250(gdb) p s1$2 = 1431655765
 (gdb) disp result1: result = 250(gdb) c
Continuing.

Breakpoint 1, foo (n=250) at example_1.cpp:1717                      result+=n;1: result = 250(gdb) info locals 
i = 1result = 250//查看棧信息
(gdb) bt#0  foo (n=250) at example_1.cpp:17#1  0x0000000000400cc1 in main () at example_1.cpp:38(gdb) info f
Stack level 0, frame at 0x7fbffff8a0:
 rip = 0x400c07 in foo(int) (example_1.cpp:17); saved rip 0x400cc1
 called by frame at 0x7fbffff910 source language c++.
 Arglist at 0x7fbffff890, args: n=250
 Locals at 0x7fbffff890, Previous frame's sp is 0x7fbffff8a0
 Saved registers:
  rbp at 0x7fbffff890, rip at 0x7fbffff898
(gdb) f 0
#0  foo (n=250) at example_1.cpp:17
17                      result+=n;


1.八、修改環境命令

(gdb) set var i=97(gdb) p i
$5 = 97(gdb) print i=98$6 = 98(gdb) ignore 1 300Will ignore next 300 crossings of breakpoint 1.(gdb) finish
Run till exit from #0  foo (n=250) at example_1.cpp:170x0000000000400cc1 in main () at example_1.cpp:3838              cout<<"result[1-250]="<<foo(250)<<endl;Value returned is $8 = 38500
(gdb) quit
The program is running.  Exit anyway? (y or n) y


不要放過core文件

問 :Core文件是什麼?
答 :a disk file containing an image of the process's memory at the time of termination

問 :Core的做用?
答 :
  一、讓你在調試時,不用花費大量等待程序出錯;
  二、讓你避免了單步調試的煩惱
  三、讓你定位錯誤所在

啓動方式

$ gdb <program> core

查看程序信息的經常使用命令

一、查看棧信息:bt, f n, up/down,info frame

二、查看變量信息:info args|locals


實戰2 :  core文件調試

2.一、示例程序(crash2.c)

#include <string.h>void Strcpy(char *to , char *from){
    strcpy(to , from);
}int main(){    char *s = NULL;
    Strcpy(s, "abcdefg");    return 0;
}


2.二、查看信息

$ gdb ./crash2 core.19562 GNU gdb Red Hat Linux (6.3.0.0-1.96rh)Copyright 2004 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 "x86_64-redhat-linux-gnu"...Using host libthread_db library "/lib64/tls/libthread_db.so.1".

Core was generated by `./crash2'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib64/tls/libc.so.6...done.
Loaded symbols for /lib64/tls/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
#0  0x000000302af6f9a4 in strcpy () from /lib64/tls/libc.so.6(gdb) bt
#0  0x000000302af6f9a4 in strcpy () from /lib64/tls/libc.so.6
#1  0x00000000004004c5 in Strcpy (to=0x0, from=0x4005dc "abcdefg") at crash2.c:5
#2  0x00000000004004e5 in main () at crash2.c:10(gdb) f 0
#0  0x000000302af6f9a4 in strcpy () from /lib64/tls/libc.so.6(gdb) up
#1  0x00000000004004c5 in Strcpy (to=0x0, from=0x4005dc "abcdefg") at crash2.c:5
5                       strcpy(to , from);
(gdb) info args
to = 0x0from = 0x4005dc "abcdefg"//至此,已經清楚的發現了問題所在,to指針爲空


進階之多線程程序調試

多線程調試經常使用命令

$ info <...>  // 強大的查看命令,如info threads
$ attach/detach <pid> // 掛載到進程
$ thread <thread_no> // 切換到線程
$ thread apply <thread_no_list> <cmd>
     // 對於list中的thread,執行cmd
$ break <linenum> thread <threadno> if ...


實戰3 :  多線程程序調試

3.一、正常的示例程序(good_thread.c)

#include <pthread.h>#include <stdio.h>#include <sys/time.h>#include <string.h>#define MAX 10pthread_t thread[2];
pthread_mutex_t mut;int number=0, i;void *thread1()
{        printf ("thread1 : I'm thread 1\n");        for (i = 0; i < MAX; i++)
        {                printf("thread1 : number = %d\n",number);
                pthread_mutex_lock(&mut);
                        number++;
                pthread_mutex_unlock(&mut);
                sleep(2);
        }        printf("thread1 :主函數在等我完成任務嗎?\n");
        pthread_exit(NULL);
}void *thread2()
{        printf("thread2 : I'm thread 2\n");        for (i = 0; i < MAX; i++)
        {                printf("thread2 : number = %d\n",number);
                pthread_mutex_lock(&mut);
                        number++;
                 pthread_mutex_unlock(&mut);
                sleep(3);
        }        printf("thread2 :主函數在等我完成任務嗎?\n");
        pthread_exit(NULL);
}void thread_create(void)
{        int temp;        memset(&thread, 0, sizeof(thread));          //comment1
       /*建立線程*/
        if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0)       //comment2
                printf("線程1建立失敗!\n");        else
                printf("線程1被建立\n");        if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) //comment3
                printf("線程2建立失敗");        else
                printf("線程2被建立\n");
}void thread_wait(void)
{        /*等待線程結束*/
        if(thread[0] !=0) {                   //comment4
                pthread_join(thread[0],NULL);                printf("線程1已經結束\n");
        }        if(thread[1] !=0) {                //comment5
                pthread_join(thread[1],NULL);                printf("線程2已經結束\n");
        }
}int main()
{        /*用默認屬性初始化互斥鎖*/
        pthread_mutex_init(&mut,NULL);        printf("我是主函數哦,我正在建立線程,呵呵\n");
        thread_create();        printf("我是主函數哦,我正在等待線程完成任務阿,呵呵\n");
        thread_wait();        return 0;
}



網易雲免費體驗館,0成本體驗20+款雲產品!

更多網易研發、產品、運營經驗分享請訪問網易雲社區


相關文章:
【推薦】 最小化局部邊際的合併聚類算法(中篇)
【推薦】 網易美學-系統架構系列1-分佈式與服務化
【推薦】 Android模擬器下載、編譯及調試

相關文章
相關標籤/搜索