gdb - skip further step in of certain file by predefined rule?

假装没事ソ 提交于 2019-12-25 08:16:43

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!