问题
Let's say i have this file:
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 line\n");
}
xb@dnxb:/tmp/c$ cat main.c
#include <stdio.h>
#include "helloworld.h"
int
main(void) {
hello();
return 0;
}
And compiled with:
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
Then debug with 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");
At this point, repeatedly pressing Enter (equivalent to type s
and press Enter repeatedly):
(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)
What if i only care about helloworld.c
without further step into printf()
's ioputs.c
above ?
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)
This is what i want, but it requires me to manually spot I'm in helloworld.c
and it's the time to type n
accordingly. My desired is:
(gdb) s
hello () at helloworld.c:3
3 printf("Hello world!\n");
Press Enter will skip step-in of custom filename, e.g. helloworld.c
in this case, and direct skip to printf("Next line\n");
:
(gdb)
Hello world!
4 printf("Next line\n");
(gdb)
The benefit is I don't have to spot where should i stop s
and change to n
, especially if the code hierarchy is big and i might step into helloworld.c
for many time. I just have to repeatedly pressing Enter and skip unwanted depth/level.
How should i do that ?
回答1:
[Code]
I wrote this code in my gdb startup file ~/.gdbinit
(The first 6 lines is my existing lines before i wrote this code):
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]\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
[Explanation]
[1]
The basic idea is do n
instead of s
when encounter file(s) fullpath which i wanted to skip stepping.
[2]
The "AAAAA..."(4096 chars) string is the only way i can found which can reserved the memory $fpath
for full file path which require dynamically update afterward before the program is running. It might have better way to handle it, kindly comment if you know the better way.
[3]
My 1st problem is parse the full filepath which was mixed inside info source
. I modified the gdb source code (gdb/source.c
's source_info
's s->filename
is the full filepath) and compile it. But failed, it shows puts
instead of _IO_puts
in the first stepping from printf
, and i can't recall what i did, now it change to libc.so.6
only:
(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.
But after that i realized i can simply saved output of info source
into /tmp/gdbFile
first(use set logging
hack). Now use gdb command shell
to parse the file with regular Unix tool(grep
/sed
) and reformat it into /tmp/gdbFile.sources
, then use gdb command source
to set the variable:
$ 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
is the example to shows it can disabled multiple+any filename. This file will called if i enabled step into printf
. (simply change the filename helloworld.c
to helloworld2.c
in my question to test)
[5]
This code tested with empty space in filepath, e.g. /tmp/c\ c/main
[6]
Quite hard to extend if i want to exclude a lot of file path because i have to manually insert the if-else-end
. Kindly comment if you know the better way. I also a bit worry about the recursion of if-esle-end
depth might cause problem (I'm not sure how gdb handle it internally), so i ensure n
or s
is the last instruction within condition.
[7]
Luckily the Enter doesn't change to s
/n
(last instruction of sn
) after i run sn
, i.e. repeatedly press Enter will keep acts as sn
), otherwise i have no idea how to assign it.
[Result]
Press Enter from printf
into helloworld.c
will change s
to n
automatically, then change back to s
after return from this file. Note that my custom function is called mystartup
(simply my
should work if no other command name starts with "my") and sn
(not replacing s
, so you can invoked s
in the middle of helloworld.c
to stepping :):
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 line\n");
(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)
...
回答2:
GDB's skip command lets you skip stepping into uninteresting functions or files. Its syntax is skip uninteresting_function or skip file uninteresting.file. (full documentation here)
In your case you should try skip file ioputs.c.
Gdb 7.12 introduced patterns on file and function names, so you should build/install that version if you want that. This version allows you to do (for example) skip file -gfi /lib/*, which skips any source files located in /lib/...
来源:https://stackoverflow.com/questions/40464485/gdb-skip-further-step-in-of-certain-file-by-predefined-rule