c - gdb - 通过预定义规则跳过某些文件的进一步步骤?

标签 c gdb step-into

假设我有这个文件:

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;
}

并编译:

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)

好处是我不必确定我应该在哪里停止 s 并更改为 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 = "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

[解释]

[1]

基本思想是在遇到我想跳过的文件完整路径时执行 n 而不是 s

[2]

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

[3]

我的第一个问题是解析混合在 info source 中的完整文件路径。我修改了 gdb 源代码(gdb/source.csource_infos->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 into printf,将调用此文件。 (只需将我的问题中的文件名 helloworld.c 更改为 helloworld2.c 即可测试)

[5]

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

[6]

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

[7]

幸运的是 Enter 在我之后没有变成 s/n(sn 的最后一条指令)运行 sn,即重复按 Enter 将保持作为 sn),否则我不知道如何分配它。

[结果]

Enterprintf 进入 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 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) 
...

关于c - gdb - 通过预定义规则跳过某些文件的进一步步骤?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40464485/

相关文章:

c - 通过指针从 C 和 C++ 中的函数返回本地数据

c - 为什么我的位微运算构造在 C 中不起作用

c - 如何用 C 检测 Linux 上 exec'ed 子进程的文件事件?

c++ - 如何为实例变量设置观察点?

c++ - 特定线程上的 gdb nostop SIGSEGV

c++ - 进入带有并行for循环的编译指示(C++,OpenMP,Nsight Eclipse IDE)

c - 需要了解 printf 的行为

linux - Linux 系统有 gdb 的替代品吗?

ios - 每次我按下调试线调用 NSMakeRange 的单步执行按钮时,都会进入 NSMakeRange