假设我有这样一个文件:
xb@dnxb:/tmp/c$ cat helloworld.h
void hello();
xb@dnxb:/tmp/c$ cat helloworld.c
#include <stdio.h>
void hello() {
printf("Hello world!n");
printf("Next linen");
}
xb@dnxb:/tmp/c$ cat main.c
#include <stdio.h>
#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 linen");
(gdb)
这就是我想要的,但它需要我手动发现我在helloworld.c
,现在是时候输入n
了。我的愿望是:
(gdb) s
hello () at helloworld.c:3
3 printf("Hello world!n");
按输入将跳过自定义文件名的步进,例如在本例中为helloworld.c
,并直接跳到printf("Next linen");
:
(gdb)
Hello world!
4 printf("Next linen");
(gdb)
这样做的好处是我不必发现应该在哪里停止s
并更改为n
,特别是如果代码层次结构很大,我可能会多次进入helloworld.c
。我只需要反复按输入并跳过不需要的深度/级别。
[Code]
我在我的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 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
set $dindex = 0
set $excludeFile="/tmp/c c/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]nn
#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/Ann
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
时遇到的文件(s)全路径,我想跳过步进。
[2]
"五星级…(4096字符)字符串是我能找到的唯一方法,它可以保留内存$fpath
为完整的文件路径,需要在程序运行之前动态更新。也许有更好的处理方法,如果你知道更好的方法,请告诉我。
[3]
我的第一个问题是解析info source
内混合的完整文件路径。我修改了gdb源代码(gdb/source.c
的source_info
的s->filename
是完整的文件路径)并编译它。但是失败了,它在printf
的第一步显示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/c c/helloworld.c which is not what i want.
但在那之后,我意识到我可以简单地将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/c c
Located in /tmp/c c/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
是一个例子,显示它可以禁用多个+任意文件名。如果我启用step进入printf
,这个文件将被调用。(只需更改文件名helloworld.c
到helloworld2.c
在我的问题测试)
[5]
此代码测试了文件路径中的空白,例如/tmp/c c/main
[6]
很难扩展,如果我想排除大量的文件路径,因为我必须手动插入if-else-end
。如果你知道更好的方法,请评论。我也有点担心if-esle-end
深度的递归可能会导致问题(我不确定gdb内部如何处理它),所以我确保n
或s
是条件内的最后一条指令。
[7]
幸运的是,在我运行sn
后,Enter不会更改为s
/n
(sn
的最后一条指令),即重复按Enter将保持sn
的行为),否则我不知道如何分配它。
按从printf
输入到helloworld.c
,将自动将s
变为n
,从该文件返回后再变为s
。请注意,我的自定义函数称为mystartup
(如果没有其他命令名以"my"开头,则简单地说my
应该可以工作)和sn
(不替换s
,因此您可以在helloworld.c
中间调用s
):
xb@dnxb:/tmp/c c$ 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/c c/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/c c/main.c ********************
hello () at helloworld.c:3
3 printf("Hello world!n");
(gdb)
[customStepping]
******************** /tmp/c c/helloworld.c ********************
File #1 [Stepping] Disabled
Hello world!
4 printf("Next linen");
(gdb)
[customStepping]
******************** /tmp/c c/helloworld.c ********************
File #1 [Stepping] Disabled
Next line
5 }
(gdb)
[customStepping]
******************** /tmp/c c/helloworld.c ********************
File #1 [Stepping] Disabled
main () at main.c:6
6 return 0;
(gdb)
[customStepping]
******************** /tmp/c c/main.c ********************
7 }
(gdb)
[customStepping]
******************** /tmp/c c/main.c ********************
__libc_start_main (main=0x400636 <main>, argc=1, argv=0x7fffffffd468, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffd458) at ../csu/libc-start.c:325
325 exit (result);
(gdb)
...
GDB的skip命令允许您跳过不感兴趣的函数或文件。其语法为skip uninteresting_function或skip file uninteresting_file 。(完整的文档在这里)
在您的情况下,您应该尝试跳过文件ioputs.c。
Gdb 7.12引入了文件和函数名的模式,所以如果你想要,你应该构建/安装那个版本。这个版本允许您执行(例如)跳过file -gfi/lib/*,它跳过位于/lib/…