GDB技巧整理

https://blog.atime.me/note/gdb-tricks.html

整理常用的gdb技巧。

常用命令

常用的gdb命令...

启动gdb

  1. 直接运行

    gdb --args prog arg1 arg2
    
  2. 运行gdb后使用run命令
    gdb prog
    run arg1 arg2
    
  3. attach到已运行的程序
    gdb --pid ${PID_OF_PROG}
    

ptype

ptype用于显示Symbol的类型,示例源码为:

struct ABC {
    int val;
}

int main() {
    ABC abc;
    return 0;
}

运行gdb:

(gdb) b 7
(gdb) r
(gdb) ptype abc

type = struct XXX {
    int val;
}

ptype可以输出表达式的返回类型,具体介绍可参考Examining the Symbol Table

print {type} variable

print(p)可以按照某种类型输出变量的值,示例源码如下:

struct ABC {
    double val;
    int val2;
}

int main() {
    ABC abc;
    abc.val = 1.5;
    abc.val2 = 10;

    void *pAbc = &abc;

    return 0;
}

运行gdb:

(gdb) b 13
(gdb) r

(gdb) p pAbc
$1 = (void *) 0x7fffffffe710

(gdb) p {ABC} 0x7fffffffe710
$2 = {val = 1.5, val2 = 10}

(gdb) p {ABC} pAbc
$3 = {val = 1.5, val2 = 10}

(gdb) p * (ABC*) pAbc
$4 = {val = 1.5, val2 = 10}

(gdb) p {double} pAbc
$5 = 1.5

(gdb) p * (double*) pAbc
$6 = 1.5

(gdb) p {int} (pAbc + sizeof (double))
$7 = 10

(gdb) p * (int*) (pAbc + sizeof (double))
$8 = 10

有时候,如果字符串太长,gdb可能只打印一部分,这时候如下设置来打印全部内容:

(gdb) set print elements 0

examine

examine(x)可以按照一定的格式打印内存地址处的数据,详细文档可参考这里

(gdb) x/{COUNT}{FMT}{SIZE} {ADDRESS}
  • {COUNT}: 打印的数目,默认为1。
  • {FMT}: 打印的格式1,默认为上次使用的{FMT}:
    • o(octal): 8进制整数
    • x(hex): 16进制整数
    • d(decimal): 10进制整数
    • u(unsigned decimal): 10进制非负整数
    • t(binary): 2进制整数
    • f(float): 浮点数
    • a(address): 输出相对于前面最近的符号的偏移
    • i(instruction): 输出地址处的汇编指令
    • c(char): 字符
    • s(string): c字符串(null-terminated string)
    • z(hex, zero padded on the left): 见说明
  • {SIZE}: 打印的字节数目,默认为上次使用的{SIZE}:
    • b(byte): 1个字节
    • h(halfword): 2个字节
    • w(word): 4个字节
    • g(giant, 8 bytes): 8个字节
  • {ADDRESS}: 目标地址

几个例子:

(gdb) x/a 0x401419
0x401419 <main()+113>:  0x55c3c900000000b8

(gdb) x/i 0x40138d
=> 0x40138d <crash(int, double)+41>:    mov    -0x10(%rbp),%eax

(gdb) x/1fg 140737488346064
0x7fffffffdbd0: 10.125

设置源码目录

参考Specifying Source Directories,使用dir /path/to/your/sources可在调试时添加一个源码目录。

设置字符编码

gdb默认使用utf-8编码,可以使用如下命令修改编码。

set charset GBK

也可直接在~/.gdbinit里设置。

线程相关的命令

下面是一些调试多线程程序时常用的命令:

  • info threads: 查看线程列表
  • thread 2: 切换到2号线程,线程编号可由info threads得知
  • thread apply all bt: 打印所有线程的堆栈

高级技巧

一些不太广为人知的技巧...

加载独立的调试信息

gdb调试的时候可以从单独的符号文件中加载调试信息。

(gdb) exec-file test
(gdb) symbol-file test.debug

test是移除了调试信息的可执行文件, test.debug是被移除后单独存储的调试信息。参考stackoverflow上的一个问题,可以如下分离调试信息:

# 编译程序,带调试信息(-g)
gcc -g -o test main.c

# 拷贝调试信息到test.debug
objcopy --only-keep-debug test test.debug

# 移除test中的调试信息
strip --strip-debug --strip-unneeded test

# 然后启动gdb
gdb -s test.debug -e test

# 或这样启动gdb
gdb
(gdb) exec-file test
(gdb) symbol-file test.debug

分离出的调试信息test.debug还可以链接回可执行文件test中

objcopy --add-gnu-debuglink test.debug test

然后就可以正常用addr2line等需要读取调试信息的程序了

addr2line -e test 0x401c23

更多内容可阅读GDB: Debugging Information in Separate Files

在内存和文件系统之间拷贝数据

  1. 将内存数据拷贝到文件里

    dump binary value file_name variable_name
    dump binary memory file_name begin_addr end_addr
    
  2. 改变内存数据

    使用set命令

执行gdb脚本

常用的gdb操作,比如打断点等可以放在一个gdb脚本里,然后使用时导入即可。例如:

b main.cpp:15
b test.cpp:18

gdb运行时,使用source命令即可导入

(gdb) source /path/to/breakpoints.txt

或gdb运行时导入

gdb -x /path/to/breakpoints.txt prog

对于每次gdb运行都要调用的脚本,比如设置字符集等,可以放在~/.gdbinit初始文件里,这样每次gdb启动时都会自动调用。

输出到文件

可以通过set logging on将命令的输出保存到默认的gdb.txt文件中。当然也可以通过set logging file my_log.txt来设置输出文件的路径。

执行命令并退出

有时候需要gdb执行若干条命令后就立即退出,而不是进入交互界面,这时可以使用-batch选项。

gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid

上面的命令打印$pid进程所有线程的堆栈并退出。

自定义命令

参考gdb/Define,可以在gdb中自定义命令,比如:

(gdb) define hello
(gdb) print "welcome"
(gdb) print "hello $arg0"
(gdb) end

然后如此调用

(gdb) hello world

即可输出

(gdb) $1 = "welcome"
(gdb) $2 = "hello world"

条件断点

在条件断点里可以调用标准库的函数,比如下面这个:

# 如果strA == strB,则在断点处暂停
(gdb) b main.cpp:255 if strcmp(strA.c_str(), strB.c_str()) == 0

# 还是上面的场景,直接用string类的compare函数
(gdb) b main.cpp:255 if strA.compare(strB) != 0

捕获exception

gdb遇到未处理的exception时,并不会捕获处理。但是参考Set Catchpoints,可以使用catch catch命令来捕获exception。

阅读资料

  1. Copy between memory and a file
  2. HowTo: Writing into process memory with GDB
  3. Specifying Source Directories
  4. Examining the Symbol Table
时间: 2024-11-10 07:47:24

GDB技巧整理的相关文章

sqlmap常用技巧整理

言 通过在乌云网上出现的很多SQL注入漏洞,因此来总结一下,大致使用SQLMAP所遇到的参数. 基本结构 基本SQLMAP的使用方式就如下所示,使用参数式的方式,按需求添加. 12 sqlmap.py -u "http:// *" --data="a=b" -p a --level 3 --random-agent --referer="a" --technique T --dbms=mysql --cookie="cookie&quo

javascript 最常用的技巧整理

1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键<table border oncontextmenu=return(false)><td>no</table> 可用于Table 2. <body onselectstart="return false"> 取消选取.防止复制 3. onpaste="return false" 不

gdb调试整理

调试环境:linux调试工具:gdb 调试类别 1.调试core文件  gdb 应用程序名 core文件名2.调试正在执行的程序 gdb 应用程序名 pid 3.gdb 应用程序名         4.gdb --args 应用程序名 应用程序的运行参数 常用命令 * list 显示程序中的代码,常用使用格式有 l (+/-)n* break :在程序中设置断点,当程序运行到指定行上时,会暂停执行.使用格式:break 要设置断点的行号* clear :和break相反,clear用于清除断点.

sql事务的使用及其技巧整理

sql事务的使用及其技巧整理 概述: 在实际项目开发中,为了确保数据操作结果的一致性等要求,事务是一个必不可少的解决利器. 根据SQLSERVER实现原理,其实,SQLSERVER的每一条执行语句都是一个事务操作,也就是说每一个SQL语句要么操作都成功,要么操作都失败:比如,更新语句,同时更新多个字段,不会出现有的字段更新成功,有的字段更新失败. 但是,我们平时在开发过程过程中,说的事务:其实是指的一组有序的SQL集合,通过事务确保这一组SQL集合执行结果的一致性. 事务特性:  事务的主要特性

Linux/Mac OS 个人常用Terminal技巧整理

刚开始接触linux有些不适应,走了不少弯路,一直没有系统的学过linux应用,基本都是零零散散Google出来的知识,在这里做个整理: Vi/Vim 基本操作: 刚开始接触linux时,不懂vi吃了不少亏.在命令行状态下,一旦用vi打开了文本只能通过重启来退出. vi/vim 分三种模式: 指令模式,编辑模式,选择模式. 只有在编辑模式下才能进行输入(不是绝对). 默认是"指令模式", 这个模式只支持vi/vim的指令, 在敲键盘时只会滴滴响. 不知道有多少人被这种方式搞晕过(晕不晕

IE和Firefox浏览器CSS兼容性技巧整理

转自:http://homepage.yesky.com/185/11484185all.shtml#p11484185 CSS兼容常用技巧(1) 更多精彩相关文章推荐: 各大浏览器 CSS3 和 HTML5 兼容速查表 IE6/IE7/IE8三个版本的CSS兼容速查手册 CSS hack定义技巧浏览器兼容一览表 XHTML+CSS兼容性解决方案 CSS样式表对浏览器的兼容性问题有时让人很头疼,不过当我们了解了其中的原理与技巧,就会觉得轻松一些.本文收集整理了IE7,6与Fireofx的兼CSS

CSS对浏览器的兼容性(IE和Firefox)技巧整理

CSS对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了IE7,6与Fireofx的兼容性处理技巧并整理了一下.对于web2.0的过度,请尽量用xhtml格式写代码,而且DOCTYPE 影响 CSS 处理,作为W3C的标准,一定要加 DOCTYPE声明. CSS技巧 1.div的垂直居中问题 vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字,就垂直居中了.缺点是要控制内容不

Linux下gdb使用整理记录

1.创建cpp文件:vim sourcefile.cpp 2.生成可执行文件:g++ -g sourcefile.cpp -o exename ------据说是要必须加上-g参数,否则不可调试 3.启动调试:输入gdb(滚蛋吧)进入gdb环境 4.输入 file exename   (告诉gdb要调试了) 5.输入 l (list)查看代码,回车重复上一条命令 6.断点设置:b main   在main函数入口加一个断点 -------break  5  :在第5行设置断点: i b  (in

sqlmap 技巧整理

收集了一些利用Sqlmap做注入测试的TIPS,其中也包含一点绕WAF的技巧,便于大家集中查阅,欢迎接楼补充.分享. TIP1 当我们注射的时候,判断注入 http://site/script?id=10 http://site/script?id=11-1 # 相当于 id=10 http://site/script?id=(select 10) # 相当于 id=10 http://site/script?id=10 and 1=1 #失败 通过判断可发现and和or被过滤 http://s