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

发表回复

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