gdb 笔记

一些零散的 gdb 备忘都记录在这里。

gdb 前端

gdb 自带了一个 tui 的前端,使用 -tui 选项即可启动。tui 界面比较简单,上半部分是代码,下半部分是 gdb 命令窗口,而且代码也没有高亮。另外还有使用 vim 操作方式的 cgdb,以及有一个用 python 写的 web 前端 gdbgui。当然在 emacs 中也集成了一个叫 gud 的 debugger mode(参考资料 1)。

gdb 自定义命令

建立 ~/.gdbinit 文件,里面写上要定义的命令,gdb 启动的时候会读取这个文件里的命令,这样在调试过程中就可以使用这些自定义命令了。定义命令的方式为:

define mycmd
...
end

还可以为这条自定义的命令加上注释,这样当使用“help mycmd”的时候就会显示这些注释:

document mycmd
comments here ...
end

如果需要传递参数,可以使用 \$arg0,\$arg1, ...,\$arg9 等。例如:

define print_int
p $arg0
end

这样如果在 gdb 中使用“print_int a”时,就会打印整型 a 的值。

调试时动态添加打印命令

可以用 gdb 命令 dprintf 在调试过程中动态往程序中插入打印命令,而不用修改代码和重新编译。

例如测试程序 test.c:

int main(void) {
    int a = 1;
    a = a * 5;
    return 0;
}

调试的时候添加打印:

(gdb) dprintf 3, "from gdb: before a = %d\n", a
Dprintf 1 at 0x1138: file t.c, line 3.
(gdb) dprintf 4, "from gdb: after a = %d\n", a
Dprintf 2 at 0x1145: file t.c, line 4.
(gdb) r
from gdb: before a = 1
from gdb: after a = 5

dprintf 第一个参数是位置,可以是行号或者函数名等,后面的参数和 printf 一样。更多的用法可以查看参考资料 4。

emacs gud-gdb 设置

常用设置是

(setq gdb-many-windows t)

默认会打开若干个窗口,有命令窗口,输出窗口,代码浏览窗口,堆栈窗口及局部变量窗口,等等。我觉得窗口多了比较乱,一般都不启用这个选项,默认只有命令窗口,代码窗口和输出窗口 ,需要其它信息的时候直接在命令窗口敲指令。

gud 默认提供的按键绑定非常复杂,我对常用的按键做了自定义映射:

(global-set-key [S-f1] 'gud-step)
(global-set-key [S-f2] 'gud-next)
(global-set-key [S-f3] 'gud-finish)
(global-set-key [S-f4] 'gud-until) ;; Continue execution to the current line
(global-set-key [S-f5] 'gud-run)
(global-set-key [S-f6] 'gud-cont)
(global-set-key [S-f7] 'gud-break) ;; Add current to breakpoint
(global-set-key [S-f8] 'gud-remove) ;; Delete the breakpoint(s) on the current source line, if any

emacs 使用 gdb 时显示当前运行位置时并没有居中,google 得到解决方案(参考资料 2):

(defadvice gud-display-line (after gud-display-line-centered activate)
  "Center the line in the window"
  (when (and gud-overlay-arrow-position gdb-source-window)
    (with-selected-window gdb-source-window
      ;; (marker-buffer gud-overlay-arrow-position)
      (save-restriction
        (goto-line (ad-get-arg 1))
        (recenter)))))

高亮代码窗口当前行(参考资料 3):

;;Add color to the current GUD line (obrigado google)
(defvar gud-overlay
  (let* ((ov (make-overlay (point-min) (point-min))))
    (overlay-put ov 'face '(:background "#F6FECD")) ;; colors for Leuven theme
    ov)
  "Overlay variable for GUD highlighting.")

(defadvice gud-display-line (after my-gud-highlight act)
  "Highlight current line."
  (let* ((ov gud-overlay)
         (bf (gud-find-file true-file)))
    (save-excursion
      (set-buffer bf)
      (move-overlay ov (line-beginning-position) (line-end-position)
                    (current-buffer)))))

shell 快捷启动 emacs gdb

在 emacs 中使用 gdb 时访问的文件都会保留在 buffer list 中。为了减少正常编辑时 buffer 切换的负担,可以定义一个 bash 函数来启动一个新的 emacs 实例,并在其中运行 gdb,这样就不会影响正常的文件编辑:

function egdb() {
    initfile=`dirname $1`/init.gdb
    if [ -f "$initfile" ]; then
        emacs --eval "(gdb \"gdb -i=mi $1 -x $initfile\")"
    else
        emacs --eval "(gdb \"gdb -i=mi $1\")"
    fi
}
export -f egdb

这里用了 emacs 的 -x 的选项,表示启动 emacs 后立刻运行指定配置文件中的信息,这样方便在开始调试前做一些环境变量的设置,或者用 source 命令加载其它 gdb 脚本。在 initfile 中的都是 gdb 命令,一个命令一行。

使用时在命令行运行

egdb binary

即可。

参考资料

[1] 27.6.3 Commands of GUD

[2] How to tell emacs gdb to show current code line in the center of buffer?

[3] highlight the current line in gdb/emacs

[4] 5.1.8 Dynamic Printf

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注