第一章初涉调试会话

调试工具

  • GDB,Unix下最常用的调试工具
  • DDD,基于GUI的调试器,大多数工具都是GDB的GUI前端。
  • Eclipse,IDE也是一种调试工具

atoi( )把字符串变为整数,头文件是include<stdlib.h>

gcc -g -Wall -o insert_sort ins.c

-g选项可以让编译器将符号表(对应于程序的变量和代码行的内存地址列表)保存在生成的可执行文件里中。

这样才能在调试会话的过程中引用源代码中的变量和行号,比如“在第30行停止”或者“输出x的值”。

gdb insert_sort -tui可以在调试的时候显示源代码

可以用Ctrl+X+A来打开或者关闭源代码的窗口

run + 参数运行程序

Ctrl+C可以停止程序,开程序结束在那一行

然后continue,再看看程序结束在那一行

$1是GDB输出的第一个值,$2$3等表示的值统称为调试会话的值历史。

break 30 if num_y==1,设置条件断点

clear命令用来删除断点

clear 30

info break用来查找设置的端点

先设断点,再来为断点添加条件

break 36

cond 3 new_y==19

next和step都是单步调试,如果没有在函数中设置断点,next不会进入到函数中,而step会进入到函数中

第二章停下来环顾程序

gdb符号调试器,可以暂停程序的执行,暂停以后,调试器提供了变量检查、跟踪执行路径等机会。

暂停机制

断点:     breakpoint

监视点: hw watchpoint

捕获点: catch fork

一开始这三个都被称为断点

GDB中关于位置的含义非常灵活,它可以指各种源代码、代码地址、源代码文件中的行号或者函数的入口等。

GDB断点停止的那一行并不是最后执行的代码,而是将要执行的下一行的代码。

GDB工作针对的是机器语言指令,然而可以使用源代码行,是因为可执行文件包含了额外的信息。

跟踪断点

创建断点时GDB会告知你分配给该断点的编号。

info breakpoints可以查看断点

delete 1 3 4

可以删除断点1,监视点3及捕获点4

设置断点

break function,在函数function的入口,第一行可执行代码处设置断点

break line_number,在当前活动源代码文件的line_number处设置断点

break filename:line_number,如果filename不在当前工作目录中,则可以给出相对路径名

tbreak foo.c:10,这个设置的是临时断点

GDB设置的断点位置可能与请求将断点放置位置不同。

在调试完成之前永远不应当优化代码。

如果同一行源代码有多个断点时,只会有一个断点触发中断,而且出发中断的点将是标识符编号最小的点。

(gdb) break swapper.c:1

(gdb) break swapper.c:swap

(gdb) break swap

这三个做的都是同一件事,就是在swap( )的上方设置中断。

在任何给定的时间,GDB都有一个焦点,可以将它看作当前活动的文件。

除非对命令做了限定,否则都是在具有GDB的焦点的文件上执行命令。

转移焦点的方法:

对不同的源文件使用list命令

进入位于不同的源代码文件中的代码

当在不同的源代码文件中执行代码时遇到GDB断点

断点的持久性

在调试会话期间不应该退出GDB。例如,当发现并修复了一个程序的错误,但是其他程序错误仍然存在时,

不应当退出GDB然后重新进来使用程序的新版本。

这样做有些繁琐,而且还得重新设置断点。

如果在修改和重新编译代码时没有退出GDB,那么在下次执行GDB的run命令时,GDB会感知到代码已经被修改,并自动重新加载新版本。

断点是会移动的,如果断点设置的是在某一行停留,但是对代码修改后会造成原来断点这一行的代码不一样,但是断点仍是停留在这一行。

删除和禁用断点

delete breakpoint_list

delete: 删除所有断点

clear: 清除GDB将执行的下一个指令处的断点。

GDB中禁用断点

disable 3

enable 1 5

enable once breakpoint-list

在断点下次引起GDB暂停执行后被禁用,就是执行完这一次后就被禁用了,和tbreak有点像,但是tbreak是用完一次就删除。

浏览断点属性

每个断点都有属性,比如行号、加在断点上的条件(如果有的话)

创建的每个断点都被赋予唯一的整数标识符

info breakpoints

Num 标识符

Type 这个断点是断点、监视点还是捕获点

Disp 这个断点在在引起程序暂停后会发生什么

Enb 启用状态,这个断点当前是启用还是禁用

Address 在内存中设置断电的位置

What 显示断点所在的行号和文件名称

恢复执行

continue

next 单步调试,执行函数,但是不会在函数中暂停,而是在调用之后的第一条语句暂停,永远不会离开main,单步越过函数

step 单步调试,在函数中的第一个语句处暂停,单步进入函数

单步调试源代码是遇到函数调用,一般使用next比step好,在这种情况下使用next之后,立即要检查调用的结果是否正确

next可以节省调试每一行的精力和时间。

next和step后面可以接数字

continue 接数字代表忽略下面的几个断点

finish 简写fin,指示GDB恢复执行,直到恰好在当前栈帧完成之后为止。

也就是说如果你不是在main( )中,finish命令会导致GDB恢复执行,直到恰好在函数返回为止。

但是如果之间有断点,finish都会在断点处暂停。

finish不会进一步咱函数中暂停(除非有断点在里面)。

until命令,简写为u,通常不会进一步在循环中暂停,除了循环中间的断点。

until执行程序,直到到达当前循环体外的下一行源代码。

until命令也可以接受源代码中的位置作为参数

条件断点

有时候需要告诉调试器,只有当符合条件是才在断点处停止。

break break-args if (condition)

例如:

break test.c:myfun if ! check_variable_sanity(i)

break 44 if strlen(mystring)==0

可以对正常断点设置条件以将它们转变为条件断点。

比如设置了断点3作为无条件断点,但是系在系统加入条件3,只要键入:

(gdb) cond 3 i==3

如果以后要删除条件,但是要保持该断点,只要键入

(gdb) cond 3

断点命令列表

当GDB遇到断点时,几乎总是要查看变量,如果反复遇到同一断点,将反复查看相同的便两个,让GDB在每次达到某个断点时自动执行一组命令,从而自动完成这一过程

使用commands命令设置命令列表

commands breakpoint-number

...

commands

...

end

如果感觉系统给的提示太多了,可以使用silent命令,它必须是命令列表里面的第一个命令,是GDB安静地出发断点。

如果命令列表最后一个命令式continue,GDB将在完成命令列表的命令后继续自动执行程序

在GDB中还可以使用define命令创建宏。

show user可以得到所有宏的列表

GDB命令与表达式很丰富,可以使用自定义的函数,只要它们被链接到执行文件中即可

可以使用它们的返回值,只要它们的返回值类型为int。

监视点

监视点是一种特殊的断点,其特点在于不是在固定的某一行暂停,而是监视某个变量或表达式的值是否发生改变

如果改变了就会暂停

该表达式可以非常简单:

(gdb) watch i

没当改变i的值时就会暂停,表达式也可以非常复杂

(gdb) watch ( i | j > 12) && i > 24 && strlen(name) > 6

断点与源代码的一个位置关联,但是c语言有严格的作用域规则,所以只能监视存在且在作用域内的变量,一旦变量不再存在与调用栈的任何帧当中,

GDB会自动的删除监视点。

设置监视点:

当var存在且在作用域中时,

watch var

这个命令会导致每次var改变值时GDB都中断,监视点简单方便

GDB实际上是在var的内存位置改变值时中断,一般情况下,是否使用监视点监视变量或变量的地址并没有关系

但是在处理指向指针的指针时很重要。

硬件监视点

虚拟内存监视点

软件自身监视点

表达式

GDB中的表达式包含很多内容:

GDB方便变量

程序中的任何在作用域内的变量

任何种类的字符串、数值或字符常量

预处理器宏

条件、函数调用、类型强制转换和所用语言定义的运算符

第三章 检查和设置变量

仅仅用print来显示变量的值有些过于简单了

变量的高级检查和设置

如果用print来打印结构体:

(gdb) p tmp->val

(gdb) p tmp->left

(gdb) p tmp->right

左指针的实际值,即实际内存地址,但是指针是非0或0这一实时很重要。

输出完整结构

(gdb) p *tmp

由于tmp指向该结构,因此*tmp是这个结构本身

display则要求每次暂停时就输出指定条目,比如:

(gdb) dispay *tmp

使用GDB的commands命令

如果希望在给定节点上查看子节点的值:

(gdb) commands 1

> p tmp->val

> if (tmp->left != 0)

> p tmp->left->val

> else

> printf "%s\n", "none"

> end

> if ( tmp->right != 0)

> p tmp->right->val

> else

> printf "%s\n" "none"

> end

> end

printf( )命令也很强大,跟C里面对应的命令类似

使用call命令

GDB里面也可以用call来调用源代码里面的函数

(gdb) cmmands 2

> printf "*********** current tree ************"

> call printtree(root)

> end

此外可以动态修改断点的命令集,或者简单地通过定义一个空集合来取消该命令。

GDB中打印动态数组

对于静态数组,GDB可以用:

print x

来打印整个数组,但是对用malloc或者new创建的动态数组,则只会打印地址,

print *x也只会打印数组的第一的元素

p *pointer@number_of_elements

p (int [25]) *x

类型强制转换

监视局部变量

info locals命令可以得到当前栈帧中所有局部变量的值列表

直接检查内存

执行显示格式

(gdb) p/x y

临时禁用某个显示项

(gdb) dis disp 1

显示项可以用info disp查看

重新启用则可以用:

(gdb) enable disp 1

要完全删除显示的条目,可以用undisplay,

(gdb) undisp 1

设置变量值

set x=12

会将x的当前值改成12

可以通过set args设置程序的命令行参数

(gdb) set args 1 52 19 11

并不会立即将argv[1]改成1,argv[2]改成52,而是在下次run的时候生效

检查当前函数参数的命令:

info args

GDB自己的变量

使用历史值,比如$1,$2等

print *$

这是一个特殊的历史变量

方便变量

假设有个指针变量p,在不同的时候表示链表中不同的节点,可能在调试的时候希望记录特定的节点的历史

(gdb) set $q=p

(gdb) p *$q

这里的变量$q称为方便变量

待续......

第4章 程序崩溃处理

第5章 多活动上下文中的调试

第6章 特殊主题

第7章 其他工具

利用GDB对程序进行调试的更多相关文章

  1. 3、利用GDB进行程序调试

    本文将用一个实际例子讲解如何通过GDB进行程序调试. 首先,我们需要理解的是GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,其产生和调试的目的是让调试者知道,程序在执行时内部发生了什么 ...

  2. 学习4412开发板gdb和gdbserver的调试

    因为有很多的小伙伴是从单片机转过来的,用惯了单片机上的JLINK调试程序,换到Linux上非常的不习惯.确实,如果能设置断点,单步调试,查看变量,那确实是太爽了,那么在我们的Linux可以做到吗,答案 ...

  3. 20145311利用gdb调试汇编代码

    利用GDB调试汇编代码 首先编写c语言原代码,我使用的是同学分析过的代码 #include<stdio.h>short addend1 = 1;static int addend2 = 2 ...

  4. 利用GDB在远程开发机进行调试

    由于一些环境的制约,很多同学都可能需要在开发机上进行调试,但由于开发机资源的限制,在开发机上直接进行本地的GDB环境配置就成了难题,这个时候其实我们可以利用GDB中自带的gdbserver工具就可以进 ...

  5. 利用GDB进行多线程调试

    一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...

  6. 利用QEMU+GDB搭建Linux内核调试环境

    前言 对用户态进程,利用gdb调试代码是很方便的手段.而对于内核态的问题,可以利用crash等工具基于coredump文件进行调试. 其实我们也可以利用一些手段对Linux内核代码进行gdb调试,qe ...

  7. C++雾中风景番外篇3:GDB与Valgrind ,调试代码内存的工具

    写 C++的同学想必有太多和内存打交道的血泪经验了,常常被 C++的内存问题搅的焦头烂额.(写 core 的经验了)有很多同学一见到 core 就两眼一抹黑,不知所措了.笔者 入"坑&quo ...

  8. 调试多线程 & 查死锁的bug & gcore命令 & gdb对多线程的调试 & gcore & pstack & 调试常用命令

    gdb thread apply all bt 如果你发现有那么几个栈停在 pthread_wait 或者类似调用上,大致就可以得出结论:就是它们几个儿女情长,耽误了整个进程. 注意gdb的版本要高于 ...

  9. MATLAB调用C程序、调试和LDPC译码

    MATLAB是一个很好用的工具.利用MATLAB脚本进行科学计算也特别方便快捷.但是代码存在较多循环时,MATLAB运行速度极慢.如果不想放弃MATLAB中大量方便使用的库,又希望代码能迅速快捷的运行 ...

随机推荐

  1. 如何在Win8中设置虚拟热点共享上网(转)

    摘自:http://www.enet.com.cn/article/2013/0408/A20130408273749.shtml 在Windows 7中,我们可以通过网络与共享中心的“设置新的连接和 ...

  2. PHP API中,MYSQL与MYSQLI的持久连接区别

    转载自:http://www.cnxct.com/some-differences-between-mysql-and-mysqli-of-persistent-connection/ 很久很久以前, ...

  3. eclipse 在Servers窗口创建一个Tomcat 6.0 Server失败

    web项目部署到tomcat除了用eclipse插件,eclipse也有一个Servers窗口来部署.   问题背景:Servers窗口,我之前创建过一个Tomcat v6.0 Server,后来我把 ...

  4. 【java设计模式】之 代理(Proxy)模式

    代理模式的核心作用就是通过代理,控制对对象的访问.这跟实际中是一样的,比如说明星都有经纪人,这就是一个代理,比如有人要找某明星拍戏,那么首先处理这事的是他的经纪人,虽然拍戏需要自己拍,但是拍戏前后的一 ...

  5. vsftp添加用户及测试

    上一篇我们讲了vsftp安装以及配置,这篇我们讲下如何添加用户,然后我们测试一下,看看是否成功. 首先说下添加用户,如图执行命令即可: 这里简单解释一下:第一条命令是添加用户,第二条命令是设置用户密码 ...

  6. wap站、手机APP 接入支付宝、微信、银联支付。

    一.wap站 ①.支付宝接入 1.开发前准备:申请一个通过实名认证的企业支付宝账号,并申请开通手机WAP支付功能. 2.流程 参数准备: 企业支付宝账号的PID(也叫ParnerID)和KEY,如果使 ...

  7. Oracle 11g的Deferred Segment Creation

    本篇主要介绍Oracle 11g中推出的“延迟段创建”(Deferred Segment Creation)特性,以及当我们使用这种特性时,需要注意的问题. 1)Deferred Segment Cr ...

  8. Js操作Select大全(取值、设置选中等等)

    jquery操作select(取值,设置选中) 每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了. 比如<select class="selecto ...

  9. jquery中 $ 和 jQuery 及 $() 的区别

    用过jquery的人都知道,jquery有两种用法,一种是$,还有一种是jQuery,那么这两种方式在使用上有什么区别呢? 答案是这两种用法没什么区别,只是别名而已,用$要比jQuery简短一些.方便 ...

  10. Python学习笔记011——内置函数exec()

    1 描述 把一个字符串当成语句执行 exec()  执行储存在字符串或文件中的 Python 语句,相比于  eval() , exec() 可以执行更复杂的 Python 代码. exec函数和ev ...