gdb – 按预定义规则跳过某个文件的进一步步骤?

假设我有这个文件:

xb@dnxb:/tmp/c$ cat helloworld.h void hello(); xb@dnxb:/tmp/c$ cat helloworld.c #include  void hello() { printf("Hello world!\n"); printf("Next line\n"); } xb@dnxb:/tmp/c$ cat main.c #include  #include "helloworld.h" int main(void) { hello(); return 0; } 

并编译:

 xb@dnxb:/tmp/c$ gcc -g3 -shared -o libhello.so -fPIC helloworld.c -std=c11 xb@dnxb:/tmp/c$ gcc -g3 main.c -o main -Wl,-rpath,"$PWD" -L. -lhello 

然后用gdb调试:

 xb@dnxb:/tmp/c$ gdb -q -n ./main Reading symbols from ./main...done. (gdb) b main Breakpoint 1 at 0x40062a: file main.c, line 5. (gdb) r Starting program: /tmp/c/main Breakpoint 1, main () at main.c:5 5 hello(); (gdb) s hello () at helloworld.c:3 3 printf("Hello world!\n"); 

此时,反复按Enter键 (相当于键入s并反复按Enter键 ):

 (gdb) _IO_puts (str=0x7ffff7bd9689 "Hello world!") at ioputs.c:33 33 ioputs.c: No such file or directory. (gdb) 35 in ioputs.c (gdb) strlen () at ../sysdeps/x86_64/strlen.S:66 66 ../sysdeps/x86_64/strlen.S: No such file or directory. (gdb) 

如果我只关心helloworld.c而没有进一步进入上面的printf()ioputs.c怎么办?

 xb@dnxb:/tmp/c$ gdb -q -n ./main Reading symbols from ./main...done. (gdb) b main Breakpoint 1 at 0x40062a: file main.c, line 5. (gdb) r Starting program: /tmp/c/main Breakpoint 1, main () at main.c:5 5 hello(); (gdb) s hello () at helloworld.c:3 3 printf("Hello world!\n"); (gdb) n Hello world! 4 printf("Next line\n"); (gdb) 

这就是我想要的,但它需要我手动发现我在helloworld.c ,因此是时候输入n 。 我的期望是:

 (gdb) s hello () at helloworld.c:3 3 printf("Hello world!\n"); 

Enter将跳过自定义文件名的步入,例如helloworld.c在这种情况下直接跳到printf("Next line\n");

 (gdb) Hello world! 4 printf("Next line\n"); (gdb) 

好处是我不必发现我应该在哪里停止并更改为n ,特别是如果代码层次结构很大并且我可能会多次进入helloworld.c 。 我只需要反复按Enter键并跳过不想要的深度/水平。

我该怎么做?

[码]

我在我的gdb启动文件~/.gdbinit编写了这段代码(在编写此代码之前,前6行是我现有的行):

 set environment HISTSIZE 10000000 set history filename ~/.gdb_history set history save on set history size 10000000 set history expansion on show history #compile/make gdb failed #rf: http://stackoverflow.com/a/33663513/1074998 #use `make install` #rf: http://stackoverflow.com/a/15306144/1074998 #for step into strcpy(), memcpy() #gcc -fno-builtin -g foo.c #other rf: https://ubuntuforums.org/showthread.php?t=1572766 #rf: https://codywu2010.wordpress.com/2014/09/13/why-is-my-gdb-step-command-behavior-changed/ # printf step into 1st instruction is: _IO_puts (kali default gdb) vs puts (self-compile gdb) #rf: http://stackoverflow.com/a/31076131/1074998 #nosharedlibrary, sharedlibrary #rf: http://www.sourceware.org/gdb/onlinedocs/gdb/Source-Path.html #dir #rf2: https://www.chemie.fu-berlin.de/chemnet/use/info/gdb/gdb_8.html #dir #rf: http://stackoverflow.com/a/20116541/1074998 #`apt-get source libc6` and put the path of stdio-common (use `find . -name '*stdio-common*'` to find out) dir '/home/xiaobai/note/src/gdb-7.11.1/glibc-2.24/stdio-common' #rf: http://stackoverflow.com/a/29956038/1074998 dir '/usr/src/glibc/glibc-2.24/malloc' set step-mode on #rf: https://sourceware.org/gdb/onlinedocs/gdb/Define.html #set max-user-call-depth 100000000 #type alias 'my' enough, nod ni type `mystart` define mystart #reset to fix "Value can't be converted to integer." #initialized with enough buffer to fix "Too many array elements" #`set {char [4096]}$fpath = 0` failed #rf1: http://reverseengineering.stackexchange.com/a/2216/15176 #rf2: http://stackoverflow.com/a/30955291/1074998 #rf3: http://serverfault.com/a/306726/210566 ,and http://stackoverflow.com/a/14508945/1074998 #max file fullpath is 4096 set $fpath = "" set $dindex = 0 set $excludeFile="/tmp/cc/helloworld2.c" set $excludeFile2="/home/xiaobai/note/src/gdb-7.11.1/glibc-2.24/sysdeps/x86_64/strchr.S" #to ensure `set $fpath = $mallocFile` later will not truncate buffer set $mallocFile = $fpath #set it to "mallo.c" if not do `sudo apt-get install glibc-source`, `cd /usr/src/glibc`, `sudo tar xvf glibc-N.NN.tar.xz`, and put `dir '/usr/src/glibc/glibc-N.NN/malloc'` on top of this file, rf: http://stackoverflow.com/a/29956038/1074998 set $mallocFile = "/usr/src/glibc/glibc-2.24/malloc/malloc.c" b main r end #rf: http://stackoverflow.com/a/1530774/1074998 define pFullPathTitle printf "\n******************** %s ********************\n", $fpath end define pFilePathTitle printf "\n******************** <%s> ********************\n", $fpath end define sn set $dindex += 1 echo \n[customStepping]\n\n #rf: https://sourceware.org/gdb/onlinedocs/gdb/Logging-Output.html set logging off set logging file /tmp/gdbFile set logging redirect on set logging on #ensure put this after `set logging on` otherwise will not work set logging overwrite #http://stackoverflow.com/a/1907066/1074998 #info source #Bcareful might got extra headline "warning: Currently logging to /tmp/gdbFile. Turn the logging off and on to make the new setting effective." #and line "^Located in " will not exist at all if no full filepath which was so common info source set logging off #rf1: http://stackoverflow.com/a/6889615/1074998 #shell var to gdb #rf2: http://unix.stackexchange.com/a/151609/64403 #eval #rf3: http://www.delorie.com/gnu/docs/gdb/gdb_118.html #set var #rf4: https://sourceware.org/gdb/download/onlinedocs/gdb/Convenience-Vars.html #rf5: http://unix.stackexchange.com/a/320342/64403 #sed shell echo 'set $fpath = "'`cat /tmp/gdbFile | grep '^Located' | sed 's/^Located in //g'`'"' > /tmp/gdbFile.sources source /tmp/gdbFile.sources #rf: https://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html #if-else #rf2: https://blogs.oracle.com/ksplice/entry/8_gdb_tricks_you_should #if #rf: http://stackoverflow.com/a/7424716/1074998 #strcmp if strcmp($fpath, $excludeFile) == 0 pFullPathTitle echo File #1 [Stepping] Disabled \n n else if strcmp($fpath, $excludeFile2) == 0 pFullPathTitle echo File #2 [Stepping] Disabled \n n else if strcmp($fpath, $mallocFile) == 0 #due to gdb freeze at this point, so i disable it #manually run no such problem, weird # #2925 victim = _int_malloc (ar_ptr, bytes); set $fpath = $mallocFile pFullPathTitle echo [mallo.c] freeze and should come here [Stepping] N/A\n\n info source #rf1: http://stackoverflow.com/a/9220953/1074998 #rf2: http://stackoverflow.com/questions/39124817/gdb-freezes-in-malloc finish #n else if strcmp($fpath, "") == 0 #`info source`'s "Located in " line not even exist ! #get single filename and set it to $fpath, source it, then print the title with this filename shell echo 'set $fpath = "'`cat /tmp/gdbFile | grep '^Current source file is ' | sed 's/^Current source file is //g'`'"' > /tmp/gdbFile.sources source /tmp/gdbFile.sources pFilePathTitle s else pFullPathTitle s end end end end end 

[说明]

[1]

基本的想法是在遇到文件完整路径时做n而不是s ,我想跳过踩踏步。

[2]

“AAAAA …”(4096个字符串)字符串是我能找到的唯一可以保留内存$fpath的完整文件路径的方法,它需要在程序运行之前进行动态更新。 它可能有更好的方法来处理它,如果你知道更好的方式,请善意评论。

[3]

我的第一个问题是解析info source中混合的完整文件路径。 我修改了gdb源代码( gdb/source.csource_infos->filename是完整的s->filename路径)并编译它。 但是失败了,它在printf的第一个_IO_puts中显示了_IO_puts而不是_IO_puts ,我不记得我做了什么,现在它只改为libc.so.6

 (gdb) s hello () at helloworld.c:3 3 printf("Hello world!\n"); (gdb) 0x00007ffff788a160 in printf () from /lib/x86_64-linux-gnu/libc.so.6 (gdb) 0x00007ffff788a167 in printf () from /lib/x86_64-linux-gnu/libc.so.6 ... `s->filename` still give me /tmp/cc/helloworld.c which is not what i want. 

但之后我意识到我可以/tmp/gdbFile info source输出保存到/tmp/gdbFile (使用set logging hack)。 现在使用gdb命令shell用常规Unix工具( grep / sed )解析文件并将其重新格式化为/tmp/gdbFile.sources ,然后使用gdb命令source设置变量:

 $ cat /tmp/gdbFile warning: Currently logging to /tmp/gdbFile. Turn the logging off and on to make the new setting effective. Current source file is main.c Compilation directory is /tmp/cc Located in /tmp/cc/main.c Contains 7 lines. Source language is c. Producer is GNU C11 6.1.1 20160802 -mtune=generic -march=x86-64 -g3 -fno-builtin. Compiled with DWARF 2 debugging format. Includes preprocessor macro info. $ cat /tmp/gdbFile.sources set $fpath = "/usr/src/glibc/glibc-2.24/sysdeps/unix/sysv/linux/_exit.c" $ 

[4]

/home/xiaobai/note/src/gdb-7.11.1/glibc-2.24/sysdeps/x86_64/strchr.S是一个示例,显示它可以禁用多个+任何文件名。 如果我启用步骤到printf将调用此文件。 (在我的问题中只需将文件名helloworld.c更改为helloworld2.c即可测试)

[5]

此代码使用文件路径中的空白空间进行测试,例如/tmp/c\ c/main

[6]

如果我想排除很多文件路径,我很难扩展,因为我必须手动插入if-else-end 。 如果您知道更好的方式,请发表评论。 我也有点担心if-esle-end深度的递归可能会导致问题(我不确定gdb如何在内部处理它),所以我确保ns是条件中的最后一条指令。

[7]

幸运的是,在我运行sn之后, Enter不会更改为s / nsn最后一条指令),即重复按Enter键将保持行为为sn ),否则我不知道如何分配它。

[结果]

printfEnter键进入helloworld.c会自动将s更改为n ,然后从此文件返回后返回s 。 请注意,我的自定义函数名为mystartup (如果没有其他命令名称以“my”开头, my应该工作)和sn (不替换s ,所以你可以在helloworld.c调用s来踩踏:):

 xb@dnxb:/tmp/cc$ gdb -q /tmp/c\ c/main expansion: History expansion on command input is on. filename: The filename in which to record the command history is "/home/xiaobai/.gdb_history". remove-duplicates: The number of history entries to look back at for duplicates is 0. save: Saving of the history record on exit is on. size: The size of the command history is 10000000. Reading symbols from /tmp/cc/main...done. (gdb) my Breakpoint 1 at 0x40063a: file main.c, line 5. Breakpoint 1, main () at main.c:5 5 hello(); (gdb) sn [customStepping] ******************** /usr/src/glibc/glibc-2.24/sysdeps/unix/sysv/linux/_exit.c /tmp/cc/main.c ******************** hello () at helloworld.c:3 3 printf("Hello world!\n"); (gdb) [customStepping] ******************** /tmp/cc/helloworld.c ******************** File #1 [Stepping] Disabled Hello world! 4 printf("Next line\n"); (gdb) [customStepping] ******************** /tmp/cc/helloworld.c ******************** File #1 [Stepping] Disabled Next line 5 } (gdb) [customStepping] ******************** /tmp/cc/helloworld.c ******************** File #1 [Stepping] Disabled main () at main.c:6 6 return 0; (gdb) [customStepping] ******************** /tmp/cc/main.c ******************** 7 } (gdb) [customStepping] ******************** /tmp/cc/main.c ******************** __libc_start_main (main=0x400636 
, argc=1, argv=0x7fffffffd468, init=, fini=, rtld_fini=, stack_end=0x7fffffffd458) at ../csu/libc-start.c:325 325 exit (result); (gdb) ...

GDB的skip命令可以让您跳过不感兴趣的函数或文件。 它的语法是跳过uninteresting_function跳过文件uninteresting.file 。 ( 这里有完整的文档)

在您的情况下,您应该尝试跳过文件ioputs.c

Gdb 7.12在文件和函数名称上引入了模式,因此如果需要,您应该构建/安装该版本。 此版本允许您(例如) 跳过文件-gfi / lib / * ,它跳过位于/ lib /中的任何源文件…