linenum>
清楚已定义的停止点
delete[breakpoints][ranga...]
删除指定的断点
5、恢复程序运行:
continue(c)
6、until和finish
until跳出循环比较有用
helpfinish
Executeuntilselectedstackframereturns.
Uponreturn,thevaluereturnedisprintedandputinthevaluehistory.
finish用来跳出函数比较有用。
helpuntil
Executeuntiltheprogramreachesasourcelinegreaterthanthecurrent
oraspecifiedlocation(sameargsasbreakcommand)withinthecurrentframe
1.3 GDB调试的实例叙述
1:
对于在应用程序中加入参数进行调试的方法:
直接用gdbapp-p1-p2这样进行调试是不行的。
需要像以下这样使用:
#gdbapp
(gdb)r-p1-p2
或者在运行run命令前使用setargs命令:
(gdb)setargsp1p2
可以用showargs命令来查看
2.加入断点:
break
break
break+offset
break-offset
(在当前行号的前面或后面的offset行停住。
)
breakfilename:
linenum
在源文件filename的linenum行处停住。
breakfilename:
function
在源文件filename的function函数的入口处停住。
break...if
.可以是上述的参数,condition表示条件,在条件成立时停住。
比如在循环境体中,可以设置breakifi=100,表示当i为100时停住程序。
3.查看运行时的堆栈:
使用bt命令
4.打印某个变量的值:
printval
5.单步:
n
继续运行:
c
step
单步跟踪,如果有函数调用,他会进入该函数。
next
同样单步跟踪,如果有函数调用,他不会进入该函数。
很像VC等工具中的stepover。
后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。
setstep-mode
setstep-modeon
打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。
这个参数有很利于查看机器码。
setstep-modoff
关闭step-mode模式。
finish
运行程序,直到当前函数完成返回。
并打印函数返回时的堆栈地址和返回值及参数值等信息。
until或u
当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
6.在GDB中执行shell命令:
在gdb环境中,你可以执行UNIX的shell的命令,使用gdb的shell命令来完成:
eg.shellmake
7.运行环境
可设定程序的运行路径。
showpaths查看程序的运行路径。
setenvironmentvarname[=value]设置环境变量。
如:
setenvUSER=hchen
showenvironment[varname]查看环境变量。
8.观察点(WatchPoint)
观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。
我们有下面的几种方法来设置观察点:
watch
为表达式(变量)expr设置一个观察点。
一量表达式值有变化时,马上停住程序。
rwatch
当表达式(变量)expr被读时,停住程序。
awatch
当表达式(变量)的值被读或被写时,停住程序。
infowatchpoints
列出当前所设置了的所有观察点。
9.维护breakpoint
clear
清除所有的已定义的停止点。
clearfunc
清除所有设置在函数上的停止点。
delete[breakpoints][range...]
删除指定的断点,breakpoints为断点号。
如果不指定断点号,则表示删除所有的断点。
range表示断点号的范围(如:
3-7)。
其简写命令为d。
比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好像回收站一样。
disable[breakpoints][range...]
disable所指定的停止点,breakpoints为停止点号。
如果什么都不指定,表示disable所有的停止点。
简写命令是dis.
enable[breakpoints][range...]
enable所指定的停止点,breakpoints为停止点号。
10、程序变量
查看文件中某变量的值:
file:
:
variable
function:
:
variable
可以通过这种形式指定你所想查看的变量,是哪个文件中的或是哪个函数中的。
例如,查看文件f2.c中的全局变量x的值:
gdb)p'f2.c':
:
x
查看数组的值
有时候,你需要查看一段连续的内存空间的值。
比如数组的一段,或是动态分配的数据的大小。
你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。
例如,你的程序中有这样的语句:
int*array=(int*)malloc(len*sizeof(int));
于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:
p*array@len
如果是静态数组的话,可以直接用print数组名,就可以显示数组中所有数据的内容了。
11.输出格式
一般来说,GDB会根据变量的类型输出变量的值。
但你也可以自定义GDB的输出的格式。
例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。
要做到这样,你可以使用GDB的数据显示格式:
x按十六进制格式显示变量。
d按十进制格式显示变量。
u按十六进制格式显示无符号整型。
o按八进制格式显示变量。
t按二进制格式显示变量。
a按十六进制格式显示变量。
c按字符格式显示变量。
f按浮点数格式显示变量。
(gdb)pi
$21=101
(gdb)p/ai
$22=0x65
(gdb)p/ci
$23=101'e'
(gdb)p/fi
$24=1.41531145e-43
(gdb)p/xi
$25=0x65
(gdb)p/ti
$26=1100101
2.进程间的通信
2.1进程间通信的概述
进程间的通信,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。
以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。
这样进程间的通信就不局限于单台计算机了,实现了网络通信。
进程的通信机制主要有:
管道、有名管道、消息队列、信号量、共享空间、信号、套接字。
2.2管道
它传递数据是单向性的,只能从一方流向另一方,也就是一种半双工的通信方式;只用于有亲缘关系的进程间的通信,亲缘关系也就是父子进程或兄弟进程;没有名字并且大小受限,传输的是无格式的流,所以两进程通信时必须约定好数据通信的格式。
管道它就像一个特殊的文件,但这个文件之存在于内存中,在创建管道时,系统为管道分配了一个页面作为数据缓冲区,进程对这个数据缓冲区进行读写,以此来完成通信。
其中一个进程只能读一个只能写,所以叫半双工通信,为什么一个只能读一个只能写呢?
因为写进程是在缓冲区的末尾写入,读进程是在缓冲区的头部读取,他们各自的数据结构不同,所以功能不同。
2.3消息队列
消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符标识,于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除一个消息队列,内核重启也就是系统重启,同样消息队列的大小也是受限制的。
2.4信号量
信号量也可以说是一个计数器,常用来处理进程或线程同步的问题,特别是对临界资源的访问同步问题。
临界资源:
为某一时刻只能由一个进程或线程操作的资源,当信号量的值大于或等于0时,表示可以供并发进程访问的临界资源数,当小于0时,表示正在等待使用临界资源的进程数。
更重要的是,信号量的值仅能由PV操作来改变。
2.5共享内存
共享内存就是分配一块能被其他进程访问的内存。
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。
首先说下在使用共享内存区前,必须通过系统函数将其附加到进程的地址空间或说为映射到进程空间。
两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。
进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:
一次从输入文件到共享内存区,另一次从共享内存区到输出文件。
实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。
而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。
共享内存中的内容往往是在解除映射时才写回文件的。
因此,采用共享内存的通信方式效率是非常高的。
2.6信号
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。
信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
信号事件的发生有两个来源:
硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源。
信号分为可靠信号和不可靠信号,实时信号和非实时信号。
进程有三种方式响应信号1.忽略信号2.捕捉信号3.执行缺省操作。
参考文献
[1] 《嵌入式软件调试技术》主编:
罗克露编著:
陈云川电子工业出版社
[2]《嵌入式LINUX内存使用与性能优化》编著:
史子旺叶超群蔡建宇机械工业出版社
致谢
本文是在许老师的热情关心和指导下完成的,并得到同学的帮助和支持