常用的 gdb调试命令
gdb调试core文件:
gdb -c core a.out
编译生成调试文件:
gcc -o test test.cpp -g
[count]: 表示可选, count为行数
l [linenum] : list linenum行的代码;
l [+/-offset] : list当前行向下/向上offset行代码;
l [filename:linenum] : list filenmae文件linenum行代码;
l function: function函数
s[count]: step单行运行,有函数则进入函数;
info locals 打印当前变量
n[count]: next运行后面几行命令;
b <[linenum] 或 class::func>: 在linenum行或class::func函数处打断点;
delete [n]: 清除第n个断点;
clear: 清除刚才的断点;
disable breakpoints Num:关闭断点“Num”,使其无效,其中“Num”为 info breakpoints 中显示的对应值
enable breakpoints Num:打开断点“Num”,使其重新生效
bt: 栈;
frame n 调到n号栈
up/down [n] : 转到当前栈的上/下 n层栈;
info args: 当参数变量
info locals: 当前局部变量;
disassemble [func]: 输出当前[指定func]的汇编代码;
u: until 退出当前循环;
查看变量
p var: print打印var;
print var=10 : 修改值
指针处理
一般的指针直接用*解引用,但如果是stl这样的且包含自定义类型则必须把类型加上, 如下面:
// ObjIfno {Code c; Obj* obj;}是自定义类型 // 对于Obj* pObj; 这样的指针, 查看值如下: p *(pObj) // 可以直接解引用 // // // 如对于set<ObjInfo>::iterator itr 迭代器则该如下处理: p *itr // 这里不是C++, 如果直接*itr 是会报错: // "Attemp to take address of value not located in memory", // 因为C++的*itr是调用了解引用操作函数, 这里这么做是错的 p itr // ⇒ {_M_node = 0x7ff...} 即是一个结构体,里面有一个node成员 p itr._M_node # ⇒ {std::_Rb_tree_tterator<ObjInfo>::_base_ptr} 0x7ff... , // 即_M_node是迭代器里的对象指针<ObjInfo>::_base_ptr, // 所以对该node解引用就可以得到对象 p *(itr._M_node) /*⇒ 而这样解引用操作得到的只是红黑树的结构 # {_M_color=std::_s_black, _M_parent=0x7ff..., _M_left=...,_M_right=...} 真正的解引用是加入对象类型*/ p *(ObjInfo*)itr._M_node #⇒ {c = .., obj=...} //同理得到Obj* set $r = *(*(ObjInfo*)itr._M_node) p $r.Obj // ⇒ Obj*
call func(参数):调用func,并传递“参数”,如:call gdb_test(55)
print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
layout:用于分割窗口,可以一边查看代码,一边测试:
layout src:显示源代码窗口
layout asm:显示反汇编窗口
layout regs:显示源代码/反汇编和CPU寄存器窗口
layout split:显示源代码和反汇编窗口
watch 表达式:设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
gdb初始化
如.vimrc文件一样在自己的主目录中加入.gdbinit文件,在该文件中加入一些初始化的命令:
# # C++ related beautifiers # set print pretty on set print object on set print static-members on set print vtbl on set print demangle on
下面的连接中是在.gdbinit文件中加入能打印stl元素的命令, 但我自己试了下好像没有用:
https://sourceware.org/ml/gdb/2008-02/msg00064/stl-views.gdb