使用gdb调试程序,读写操作是很普遍的事情。其中,读操作包括:

  • 读取某个变量的值
  • 读取某个内存地址里的内容
  • 读取某个寄存器的值

对应地,写操作包括:

  • 修改某个变量的值
  • 修改某个内存地址里的内容
  • 修改某个寄存器的值

本文将首先简单介绍一下读操作,然后重点介绍一下写操作。

1. 读操作

  • 读取某个变量的值: p <var>
  • 读取某个内存地址里的内容: x /NFU <memaddr>
  • 读取某个寄存器的值: info r <register>

2. 写操作

先上个例子// foo.c

 #include <stdio.h>

 typedef enum {false, true} bool;

 static bool g_verbose = ;

 static void
dump(int a[], int n)
{
for (int i = ; i < n; i++)
printf("%-2d ", a[i]);
printf("\n");
} int main(int argc, char *argv[])
{
int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
int n = sizeof(a) / sizeof(int); if (g_verbose) {
printf("Now dump a[] ...\n");
dump(a, n);
} int m = ;
for (int i = ; i < n; i++)
m += a[i]; return m;
}

在上面的代码中,第5行我们定义了一个变量g_verbose, 其值为false。现在,我们将通过gdb在第20行将其修改为true,给出三种方法,贯穿了修改变量的值,修改内存地址内容和修改寄存器。

2.1 修改某个变量的值

set var <name> = <value>

e.g.

$ gcc -g -Wall -std=c99 -o foo foo.c

$ gdb foo
GNU gdb (Ubuntu ..-0ubuntu5~..) ..
...<snip>.......................................................................
(gdb) l main
printf("%-2d ", a[i]);
printf("\n");
} int main(int argc, char *argv[])
{
int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
int n = sizeof(a) / sizeof(int); if (g_verbose) {
(gdb) b
Breakpoint at 0x8048500: file foo.c, line .
(gdb) r
Starting program: /tmp/foo Breakpoint , main (argc=, argv=0xbffff054) at foo.c:
if (g_verbose) {
(gdb) p g_verbose
$ = false
(gdb) set var g_verbose = true
(gdb) p g_verbose
$ = true
(gdb) c
Continuing.
Now dump a[] ... [Inferior (process ) exited with code ]
(gdb)

2.2 修改某个内存地址里的内容

set *(unsigned char      *)<memaddr> = <value>  ; write 1 byte
set *(unsigned short *)<memaddr> = <value> ; write 2 bytes
set *(unsigned int *)<memaddr> = <value> ; write 4 bytes
set *(unsigned long long *)<memaddr> = <value> ; write 8 bytes or set *(char *)<memaddr> = <value> ; write 1 byte
set *(short *)<memaddr> = <value> ; write 2 bytes
set *(int *)<memaddr> = <value> ; write 4 bytes
set *(long long *)<memaddr> = <value> ; write 8 bytes

e.g.

$ gdb foo
GNU gdb (Ubuntu ..-0ubuntu5~..) ..
...<snip>.......................................................................
(gdb) l main
printf("%-2d ", a[i]);
printf("\n");
} int main(int argc, char *argv[])
{
int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
int n = sizeof(a) / sizeof(int); if (g_verbose) {
(gdb)
printf("Now dump a[] ...\n");
dump(a, n);
} int m = ;
for (int i = ; i < n; i++)
m += a[i]; return m;
}
(gdb) b
Breakpoint at 0x8048500: file foo.c, line .
(gdb) r
Starting program: /tmp/foo Breakpoint , main (argc=, argv=0xbffff054) at foo.c:
if (g_verbose) {
(gdb) #
(gdb)
(gdb) p &g_verbose
$ = (bool *) 0x804a02c <g_verbose>
(gdb) #
(gdb)
(gdb) x /x 0x804a02c
0x804a02c <g_verbose>: 0x00000000
(gdb) #
(gdb)
(gdb) set *(unsigned int *)0x804a02c = 0x1
(gdb) #
(gdb)
(gdb) x /x 0x804a02c
0x804a02c <g_verbose>: 0x00000001
(gdb) #
(gdb)
(gdb) c
Continuing.
Now dump a[] ... [Inferior (process ) exited with code ]
(gdb) q

2.3 修改某个寄存器的值

set $<register> = <value>

e.g.

$ gdb foo
GNU gdb (Ubuntu ..-0ubuntu5~..) ..
...<snip>.......................................................................
(gdb) display /i $eip
(gdb) set disassembly-flavor intel
(gdb) disas /m main
Dump of assembler code for function main:
{
0x080484c7 <+>: push ebp
0x080484c8 <+>: mov ebp,esp
0x080484ca <+>: and esp,0xfffffff0
0x080484cd <+>: sub esp,0x30 int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
0x080484d0 <+>: mov DWORD PTR [esp+0x1c],0x1
0x080484d8 <+>: mov DWORD PTR [esp+0x20],0x2
0x080484e0 <+>: mov DWORD PTR [esp+0x24],0x3
0x080484e8 <+>: mov DWORD PTR [esp+0x28],0x4
0x080484f0 <+>: mov DWORD PTR [esp+0x2c],0x5 int n = sizeof(a) / sizeof(int);
0x080484f8 <+>: mov DWORD PTR [esp+0x18],0x5 if (g_verbose) {
0x08048500 <+>: mov eax,ds:0x804a02c
0x08048505 <+>: test eax,eax
0x08048507 <+>: je 0x8048529 <main+> printf("Now dump a[] ...\n");
0x08048509 <+>: mov DWORD PTR [esp],0x80485f6
0x08048510 <+>: call 0x8048340 <puts@plt> dump(a, n);
0x08048515 <+>: mov eax,DWORD PTR [esp+0x18]
0x08048519 <+>: mov DWORD PTR [esp+0x4],eax
0x0804851d <+>: lea eax,[esp+0x1c]
0x08048521 <+>: mov DWORD PTR [esp],eax
0x08048524 <+>: call 0x804847d <dump>
} int m = ;
0x08048529 <+>: mov DWORD PTR [esp+0x10],0x0 for (int i = ; i < n; i++)
0x08048531 <+>: mov DWORD PTR [esp+0x14],0x0
0x08048539 <+>: jmp 0x804854c <main+>
0x08048547 <+>: add DWORD PTR [esp+0x14],0x1
0x0804854c <+>: mov eax,DWORD PTR [esp+0x14]
0x08048550 <+>: cmp eax,DWORD PTR [esp+0x18]
0x08048554 <+>: jl 0x804853b <main+> m += a[i];
0x0804853b <+>: mov eax,DWORD PTR [esp+0x14]
0x0804853f <+>: mov eax,DWORD PTR [esp+eax*+0x1c]
0x08048543 <+>: add DWORD PTR [esp+0x10],eax return m;
0x08048556 <+>: mov eax,DWORD PTR [esp+0x10] }
0x0804855a <+>: leave
0x0804855b <+>: ret End of assembler dump.
(gdb) b
Breakpoint at 0x8048500: file foo.c, line .
(gdb) r
Starting program: /tmp/foo Breakpoint , main (argc=, argv=0xbffff054) at foo.c:
if (g_verbose) {
: x/i $eip
=> 0x8048500 <main+>: mov eax,ds:0x804a02c
(gdb) #
(gdb)
(gdb) info r eax
eax 0x1
(gdb) ni
0x08048505 if (g_verbose) {
: x/i $eip
=> 0x8048505 <main+>: test eax,eax
(gdb) info r eax
eax 0x0
(gdb) #
(gdb) set $eax = 0x1
(gdb) #
(gdb)
(gdb) info r eax
eax 0x1
(gdb) c
Continuing.
Now dump a[] ... [Inferior (process ) exited with code ]
(gdb) q

总结: 熟练掌握了gdb的读写操作,对于调试那种release版本的程序bug是相当有帮助的。最近两天,我在一个测试环境中调试一个跟子网掩码有关的bug。TNND可执行程序的符号表已经被删除,而且测试环境中不能clone源代码进行修改后编译(因为源代码保护)。幸运地是,还可以自己安装gdb。 有了gdb, 通过修改某个寄存器的值快速地把debug信息打印了出来,从而有效地缩小了bug存在的代码范围。一句话,gdb很好使,你值得拥有!

使用gdb进行写操作的更多相关文章

  1. (数据科学学习手札143)为geopandas添加gdb文件写出功能

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,很多读者朋友跟随着我先前写作的 ...

  2. NoSQL生态系统——事务机制,行锁,LSM,缓存多次写操作,RWN

    13.2.4 事务机制 NoSQL系统通常注重性能和扩展性,而非事务机制. 传统的SQL数据库的事务通常都是支持ACID的强事务机制.要保证数据的一致性,通常多个事务是不可能交叉执行的,这样就导致了可 ...

  3. HDFS的工作原理(读和写操作)

    工作原理: NameNode和DateNode,NameNode相当于一个管理者,它管理集群内的DataNode,当客户发送请求过来后,NameNode会 根据情况指定存储到哪些DataNode上,而 ...

  4. SQL请求优化——请求次数统计,SQL写操作稀释

    引言 前几天做了这么一个东西:一个游戏中有个活动页面,活动页面有个商品,商品下面要显示该商品实浏览次数,就相当于是用户每出发一次请求这个浏览总次数都会添加一次,这个问题很简单,每次浏览的时候去数据库中 ...

  5. MongoDB—— 写操作 Core MongoDB Operations (CRUD)

    MongoDB使用BSON文件存储在collection中,本文主要介绍MongoDB中的写操作和优化策略. 主要有三种写操作:        Create        Update        ...

  6. phpexcel的写操作将数据库中的数据导入到excel中

    这个版本据说是可以支持excel2007,但是我使用2007编辑的xlsx是无法获得该库的支持.于是乎我就将它转化为2003.感觉支持地很好. 下面介绍一下具体的使用: require_once('. ...

  7. Java写操作

    //:ThinkingInJava/net.mindview.io/write2File.java package net.mindview.io; import java.io.BufferedRe ...

  8. TokuDB介绍——本质是分形树(一个叶子4MB)+缓存减少写操作

    其性能特点见:http://www.cnblogs.com/billyxp/p/3567421.html TokuDB 是一个高性能.支持事务处理的 MySQL 和 MariaDB 的存储引擎.Tok ...

  9. 怎样加快master数据库的写操作?分表原则!将表水平划分!或者添加写数据库的集群

    1.怎样加快master数据库的写操作?分表原则!将表水平划分!减少表的锁定时间!!! 或者或者添加写数据库的集群!!!或者添加写数据库的集群!!! 2.既然分表了,就一定要注意分表的规则!要在代码层 ...

随机推荐

  1. Android-HttpUtil工具类

    Http(Java 版 HttpURLConnection)请求的相关工具类 public class HttpUtil { private static final int TIMEOUT_IN_M ...

  2. Buffer Pool--内存总结1

    物理地址空间是处理器用来访问位于总线上的所有部件的集合.在32位处理器上,地址总线为32位,寻址空间为4GB.在使用PAE的32位服务器上,地址总线为36位,寻址空间为64GB.在64位的处理器上生产 ...

  3. XEvent--基础

    --SQL Server 扩展事件具有高度可伸缩且高度可配置的体系结构,--使用户能够按需收集解决性能问题或确定性能问题所需的信息.--1. 性能损耗小--2. 可配置性高--3. 可捕获底层事件 - ...

  4. 编译Hadoop1.0.2历程和解决问题记录

    1.安装eclipse3.6.2, 废止3.7, 这个有很多问题 2.安装eclipse插件ivy You can install Apache IvyDE plugins from the IvyD ...

  5. UWP开发入门(四)——自定义CommandBar

    各位好,再次回到UWP开发入门系列,刚回归可能有些不适应,所以今天我们讲个简单的,自定义CommandBar,说通俗点就是自定义类似AppBarButton的东西,然后扔到CommandBar中使用. ...

  6. await使用中的阻塞和并发(二)

    本文继续上篇未完成的讨论,通过将Lambda还原成最普通的代码段,来解释上篇提出的疑问.并更正上篇中一些不太正确的写法.最后会给出无需等待Async方法返回值时,对Async方法使用await的建议, ...

  7. API Test Postman接口测试之高级篇1

    API Test  Postman接口测试之高级篇1 一.postman中的请求参数简介: 1.请求参数简介: 点击params下面会出现key,value等信息,这里填写的会自动追加在url地址后面 ...

  8. mysql--mysql的安装与目录介绍

    一.mysql的下载安装 1.下载安装 1.windows10下安装 我们采用绿色免安装版, 打开你的mysql文件夹中的bin目录,我的是这个样子的 将这个路径添加入系统环境变量,首先右键此电脑-- ...

  9. soundPool的使用

    SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100); HashMap<Integer, Integer& ...

  10. “全栈2019”Java异常第八章:throw关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...