日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用GDB调试C库

發布時間:2023/12/2 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用GDB调试C库 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

用gdb調試程序時,一般的函數都可以step進去,可是C庫函數卻直接跳過了。

網上找了些資料,記錄一下!

1.安裝C庫的debug版本

[plain]?view plaincopy print?
  • sudo?apt-get?install?libc6-dbg??
  • 安裝完后,在/usr/lib目錄下會多出一個debug目錄,里面有安裝的debug版c庫的動態鏈接文件


    2.編譯程序,使用debug版本C庫

    例如程序test.c,使用如下命令編譯。

    [html]?view plaincopy print?
  • gcc?-g?-Wall?test.c?-o?test?-Wl,-rpath=/usr/lib/debug??
  • 可以使用ldd test來查看是否使用了debug版c庫。我們可以比較前后的信息

    使用debug版C庫輸出的信息:

    [plain]?view plaincopy print?
  • linux-gate.so.1?=>??(0x00b65000)??
  • libc.so.6?=>?/lib/i386-linux-gnu/libc.so.6?(0x00c94000)??
  • /lib/ld-linux.so.2?(0x00872000)??
  • 未使用debug版C庫輸出的信息:
    [plain]?view plaincopy print?
  • linux-gate.so.1?=>??(0x00fa9000)??
  • libc.so.6?=>?/lib/i386-linux-gnu/libc.so.6?(0x001af000)??
  • /lib/ld-linux.so.2?(0x0054a000)??
  • 可以看出成功了!

    ?

    3.調試

    [plain]?view plaincopy print?
  • gdb?test??

  • ?

    進入gdb后在相應位置下斷點,運行到該位置后,使用s,發現能進入c庫,但是找不到c庫源碼,呵呵

    原來還要下載對應版本的c庫源碼。如何查看c庫版本呢? 使用如下命令:

    [plain]?view plaincopy print?
  • ll?/usr/lib/debug/i386-linux-gnu/libc*??

  • 知道了對應的版本后,去glibc官網去下載吧:http://ftp.gnu.org/gnu/glibc/

    ?

    有了源碼,在gdb中用directory命令指定對應文件所在目錄,調試時即可看到源碼。

    ?

    參考鏈接:?http://blog.csdn.net/summerhust/article/details/5966751


    時間: 2015-11-12 10:38:00

    最近在研究動態鏈接原理這塊,想通過GDB跟蹤動態鏈接器(ld-Linux.so.2)是如何工作的,發現Ubuntu提供的/usr/lib/debug并不能很好的工作,跟蹤進去后,發現源碼不是對不上,就是錯誤的,所以萌發了自己編譯C庫的想法,以下是我的操作記錄,歡迎指正。

    開始前,需要確保你的磁盤剩余空間不小于3G空間,你不會想到編譯調試版本的C庫需要這么大的磁盤空間。

    首先下載源碼,我的系統是Ubuntu 15.10,使用sudo apt-get source libc6-dbg下載的C庫版本是glibc-2.21。我的源碼目錄是~/libc-dbg/glibc-2.2.1。

    在INSTALL編譯安裝說明中說,C庫不能在源碼目錄安裝,所以我在home目錄下新建立了一個目錄用于編譯C庫,目錄為~/libc。又建立了一個~/lib目錄用于最后的C庫安裝目錄。

    好,進入~/libc,輸入../libc-dbg/glibc-2.21/configure --prefix=/home/astrol/lib CFLAGS="-O1 -g3 -ggdb" CXXFLAGS="-O1 -g3 -ggdb" --disable-werror

    注意,我為了調試,所以加了-g3 -ggdb調試選項,-Ox是必須得,因為C庫必須要指定,還有最后的--disable-werror也是必須得,否則會將編譯過程中的很多警告信息歸為錯誤,那么就沒法繼續編譯了。這里我只是根據我自身的要求加的幾個選項,你也可以根據自己的需求自行添加,參考../libc-dbg/glibc-2.21/configure --help的提示幫助。

    根據上面命令的結果提示,看能否通過,如果不行就盡量想辦法滿足它,比如在configure過程中提示我系統需要gawk,那么我就sudo apt-get install gawk來滿足它就OK了。

    到了這里,就開始編譯吧,鍵入make,接下來就等吧,要很久的。

    最后make install,就將編譯好的庫安裝到我指定的~/lib中。

    進入~/lib,哬,文件還真多,咦,怎么沒有生成的庫呢,仔細一看,原來所有的庫都在子目錄lib下:


    這些都是帶有符號信息的動態庫。 好了,我們寫個hello world看如何使用它們。

    gcc -g -o hello hello.c

    然后ldd hello,輸出如下

    ? ? ? ? linux-gate.so.1 => ?(0xb7732000)
    ? ? ? ? libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7563000)
    ? ? ? ? /lib/ld-linux.so.2 (0x80080000)

    看來這樣編譯不行,根本沒用上我編譯好的哪些庫,改變編譯參數 gcc -Wl,-rpath,/home/astrol/lib/lib -Wl,--dynamic-linker,/home/astrol/lib/lib/ld-linux.so.2?-g -o hello hello.c

    或者gcc?-Wl,-rpath=/home/astrol/lib/lib -Wl,--dynamic-linker=/home/astrol/lib/lib/ld-linux.so.2 -g -o hello hello.c,其實都是一樣的。

    再ldd hello,輸出如下:

    ? ? ? ? linux-gate.so.1 => ?(0xb7732000)
    ? ? ? ??libc.so.6 => /home/astrol/lib/lib/libc.so.6 (0xb758a000)
    ? ? ? ??/home/astrol/lib/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x8001d000)

    看來OK了,我們再使用readelf確認下,使用readelf --program-headers hello輸出:

    Elf file type is EXEC (Executable file)
    Entry point 0x8048340
    There are 9 program headers, starting at offset 52

    Program Headers:
    ? Type ? ? ? ? ? Offset ? VirtAddr ? PhysAddr ? FileSiz MemSiz ?Flg Align
    ? PHDR ? ? ? ? ? 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
    ? INTERP ? ? ? ? 0x000154 0x08048154 0x08048154 0x00023 0x00023 R ? 0x1
    ? ? ??[Requesting program interpreter: /home/astrol/lib/lib/ld-linux.so.2]
    ? LOAD ? ? ? ? ? 0x000000 0x08048000 0x08048000 0x005f4 0x005f4 R E 0x1000
    ? LOAD ? ? ? ? ? 0x000f00 0x08049f00 0x08049f00 0x00120 0x00124 RW ?0x1000

    看來都可以了。

    現在使用gdb調試我們的hello。gdb hello -q進入調試。使用set verbose on打開gdb信息打印,可以更好的看到調試信息。

    astrol@astrol:~/test$ gdb hello -q
    Reading symbols from hello...done.
    (gdb) set verbose on
    (gdb) start
    Temporary breakpoint 1 at 0x804843c: file hello.c, line 5.
    Starting program: /home/astrol/test/hello
    Reading symbols from /home/astrol/lib/lib/ld-linux.so.2...done.
    Reading symbols from system-supplied DSO at 0xb7fdd000...(no debugging symbols found)...done.
    Reading in symbols for dl-debug.c...done.
    Reading in symbols for rtld.c...done.
    Reading symbols from /home/astrol/lib/lib/libc.so.6...done.

    Temporary breakpoint 1, main () at hello.c:5
    5 ? ? ? ? ? ? ? printf("hello world\n");
    (gdb)

    gdb成功加載了兩個庫和它們的符號信息。那么接下來的調試就能很好的繼續了。這里我演示下printf的工作過程,觀察下PLT的大致工作過程。

    (gdb) disassemble /m
    Dump of assembler code for function main:
    4 ? ? ? {
    ? ?0x0804842b <+0>: ? ? lea ? ?0x4(%esp),%ecx
    ? ?0x0804842f <+4>: ? ? and ? ?$0xfffffff0,%esp
    ? ?0x08048432 <+7>: ? ? pushl ?-0x4(%ecx)
    ? ?0x08048435 <+10>: ? ?push ? %ebp
    ? ?0x08048436 <+11>: ? ?mov ? ?%esp,%ebp
    ? ?0x08048438 <+13>: ? ?push ? %ecx
    ? ?0x08048439 <+14>: ? ?sub ? ?$0x4,%esp


    5 ? ? ? ? ? ? ? printf("hello world\n");
    => 0x0804843c <+17>: ? ?sub ? ?$0xc,%esp
    ? ?0x0804843f <+20>: ? ?push ? $0x80484e0
    ? ?0x08048444 <+25>: ? ?call ??0x8048300?<puts@plt>
    ? ?0x08048449 <+30>: ? ?add ? ?$0x10,%esp


    6 ? ? ? ? ? ? ? return 0;
    ? ?0x0804844c <+33>: ? ?mov ? ?$0x0,%eax


    7 ? ? ? }
    ? ?0x08048451 <+38>: ? ?mov ? ?-0x4(%ebp),%ecx
    ? ?0x08048454 <+41>: ? ?leave
    ? ?0x08048455 <+42>: ? ?lea ? ?-0x4(%ecx),%esp
    ? ?0x08048458 <+45>: ? ?ret

    End of assembler dump.

    地址0x8048300就是puts的PLT入口處。跟蹤進去

    (gdb) disassemble /m 0x8048300
    Dump of assembler code for function puts@plt:
    ? ?0x08048300 <+0>: ? ? jmp ? ?*0x804a00c
    ? ?0x08048306 <+6>: ? ? push ? $0x0
    ? ?0x0804830b <+11>: ? ?jmp ? ?0x80482f0
    End of assembler dump.

    繼續跟進,最后jmp到0x80482f0,可以通過x命令看到0x80482f0處的指令如下:

    (gdb) x/3i $eip
    => 0x80482f0: ? pushl ?0x804a004
    ? ?0x80482f6: ? jmp ? ?*0x804a008
    ? ?0x80482fc: ? add ? ?%al,(%eax)

    繼續jmp到*0x804a008,這就是_dl_runtime_resolve函數的地址,它是最終進入_dl_fixup函數的“跳板”。繼續跟進,看最后進入_dl_fixup函數后效果如何。

    最終進入_dl_fixup函數后,發現是很正常的,gdb能很好的進行源碼級調試,不會出現Ubuntu提供的/usr/lib/debug出現的哪些情況了,即行號和源碼是一一對應的。

    好了,本文就到此結束吧。

    總結

    以上是生活随笔為你收集整理的使用GDB调试C库的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。