linux gdb自动测试

来源:互联网 发布:信仰是什么 知乎 编辑:程序博客网 时间:2024/05/24 15:41
0. set height 0 设置屏幕打印不受限制,不然gdb一直要手动的按enter确认
0. set logging on
  set logging file filename设置gdb的log文件输出,屏幕可看的东西太少,还是输出到文件爽
1. 先b file:line打断点,gdb打印出断点号n
2. command n
  printf "x is %d\n",x
  c
  end
  设置运行到断点n时的要看的内容,
  如果command后面没有参数n,则命令被赋给最后一个breakpoint,这其实是说b和command连在一起用,在脚本里用就非常方便了
3. run


4. 在gdb里每次输同样的command还比较麻烦,可替代的方法是把这些命令(如上面的breakpoint,custom command等)都写在一个文件里,
作为gdb的命令脚本文件用source -v file来执行,-v参数指示gdb在执行这些命令时打印出命令本身信息。
在脚本文件里可以用if,else, while,end,loop_break, loop_continue这些条件语句,相当强大
5. 如果已经在gdb里设置了很多breakpoint和相应的command,则可以用save breakpoints filename把设置的breakpoint和命令保存到文件中,
保存的文件忽略了在此gdb实例中的breakpoint number。
6.在脚本中可能会用到的几个命令有:
1)改变变量的值: print x=4,意思为把4赋值给x,然后再打印出表达式的值(这里就是等号右边的4)
       set var width=47,把47赋值给width,
       set {int}0x83040 = 4把内存地址0x83040强制转换成int,并赋值
2)改变执行顺序: jump linespec or jump location  这个指令不改变stack frame,stack pointer,memory location,仅仅改变program counter,
所以一般只在同一个函数内才使用这个指令,可以向前向后jump,向后jump一般就是仔细检查已经执行过的代码是否有错
3)发送信号signal signalno,向程序发送一个signalno信号
4)set confirm off指明gdb所有要确认的地方全部为yes
set breakpoint pending on 让打在so里的断点自动在pending状态
5)call express 调用一个函数
6) return or return express,从一个函数返回
7) print的格式符
 print [/f ] [expr]
 p [/f ] [expr]
 show value of expr [or last value $]
 according to format f:
 x hexadecimal
 d signed decimal
 u unsigned decimal
 o octal
 t binary
 a address, absolute and relative
 c character
 f floating point
 
7.info address symbol:查询symbol的地址,一般symbol为局部变量,则为在stack上的offset。
info symbol addr:查询在addr或附近对应的symbol
例子:(gdb) info symbol 0x54320
_initialize_vx + 396 in section .text
whatis [arg]: 打印arg的数据类型,arg可以为表达式或一个数据类型
ptype [arg]:打印arg的详细数据类型
例子:对于数据结构struct complex {double real; double imag;} v;
(gdb) whatis v
type = struct complex
(gdb) ptype v
type = struct complex {
double real;
double imag;
}
8.info types regexp
info types:打印符合正则表达式regexp的所有类型的数据类型
info scope location:列出在一个作用范围内的所有局部变量,location可以是函数,代码行,或内存地址(加×号)
List all the variables local to a particular scope. This command accepts a
location argument—a function name, a source line, or an address preceded by
a ‘*’, and prints all the variables local to the scope defined by that location.
例子:
(gdb) info scope command line handler
Scope for command_line_handler:
Symbol rl is an argument at stack/frame offset 8, length 4.
Symbol linebuffer is in static storage at address 0x150a18, length 4.
Symbol linelength is in static storage at address 0x150a1c, length 4.
Symbol p is a local variable in register $esi, length 4.
Symbol p1 is a local variable in register $ebx, length 4.
Symbol nline is a local variable in register $edx, length 4.
Symbol repeat is a local variable at frame offset -8, length 4.


info functions regexp:打印符合正则regexp的所有函数的函数名和数据类型


9.maint print symbols filename
maint print psymbols filename
maint print msymbols filename:把debugging符号数据dump到一个文件里
Write a dump of debugging symbol data into the file filename. These commands
are used to debug the gdb symbol-reading code


10.set sysroot path:设置根目录,一般在host调试target代码时可用到,此时target链接的库一般不在/usr/lib目录下
Use path as the system root for the program being debugged.
If path starts with the sequence ‘remote:’, gdb will retrieve the target libraries
from the remote system.
The set solib-absolute-prefix command is an alias for set sysroot.
set solib-search-path path
If this variable is set, path is a colon-separated list of directories to search for
shared libraries. ‘solib-search-path’ is used after ‘sysroot’ fails to locate the
library, or if the path to the library is relative instead of absolute.
 
11.set debug-file-directory directories:设置debug文件查找目录,一般在exe文件和debug 符号文件分开储存时使用
用下面的两个命令可从elf格式exe文件分离debug symbol
objcopy --only-keep-debug foo foo.debug
strip -g foo
用下面的debug 文件链接指令
objcopy --add-gnu-debuglink=foo.debug foo 或build Id指令
Build ID gets embedded into the main executable using ld --build-id or the gcc
counterpart gcc -Wl,--build-id.


12.用户自定义命令
用户自定义命令是由一序列gdb命令组成的一个命令,可以向他传递参数,参数用$0 - $9访问。
A user-defined command is a sequence of gdb commands to which you assign a new name
as a command. This is done with the define command. User commands may accept up to
10 arguments separated by whitespace. Arguments are accessed within the user command
via $arg0...$arg9.
例子:
define adder
print $arg0 + $arg1 + $arg2
end
12.1 dont-repeat:在自定义命令里使用,告诉gdb用户按回车键不用重复上一个命令。
12.2 可以定义命令的hook,在执行命令前或命令后执行hook命令,hook形式为hook-func,hookpost-func。
在hook里可以调用自己hook的命令,这时就不会再执行命令的hook了,防止无限循环。
例子:
define hook-echo
echo <<<---
end
define hookpost-echo
echo --->>>\n
end
(gdb) echo Hello World
<<<---Hello World--->>>
(gdb)
You can hook a multi-word command by adding hook- or hookpost- to the last word
of the command, e.g. ‘define target hook-remote’ to add a hook to ‘target remote’.


13.set detach-on-fork mode off: 在debug父子进程时,parent和child都被gdb控制,当一个在debug时,另外一个suspend起来
Both processes will be held under the control of gdb. One process
(child or parent, depending on the value of follow-fork-mode) is
debugged as usual, while the other is held suspended.
 
14. gdb可以保存某一个时间点的program状态或者说是process映像,并且稍后又可以返回到这个状态。这个技术叫checkpoint。
每个checkpoint是process的一个copy,这样当一个bug很难重现,而又担心调试过头了又要从头开始重现时,可以在估计要重现这个bug之前,
做一个checkpoint,这样即使debug过头了,也可以从这个checkpoint开始,而不用restart整个program。
但是每个checkpoint有一个唯一的process id,这个pid与original pid不同,如果程序用来pid的信息就要考虑了。
gdb is able to save a snapshot of a program’s state, called
a checkpoint, and come back to it later.
Each checkpoint will have a unique process id
(or pid), and each will be different from the program’s original pid.
A checkpoint, however, is an identical copy of a process. Therefore if you create a
checkpoint at (eg.) the start of main, and simply return to that checkpoint instead of
restarting the process, you can avoid the effects of address randomization and your symbols
will all stay in the same place.
 
15.rbreak regex:用正则表达式regexp打断点,正则表达式与grep所用的规则一样
Set breakpoints on all functions matching the regular expression regex
rbreak file:regex:只在某个文件里应用正则表达式regexp打断点
If rbreak is called with a filename qualification, it limits the search for functions
matching the given regular expression to the specified file.
The syntax of the regular expression is the standard one used with tools like
‘grep’.
 
16。在gdb里可以设置一个watchpoint开观察某个express的值是否被改变。express可以是某个变量或被cast到一个数据类型的内存地址。
watchpoint在你对bug无从下手的时候非常有用。如果是用software形式实现watchpoint,会严重降低program的速度。
在多线程环境中,watchpoint的作用非常有限,因为gdb的software watchpoint只能在一个线程里观察express。
You can use a watchpoint to stop execution whenever the value of an expression changes,
without having to predict a particular place where this may happen.
The expression may be:
A reference to the value of a single variable.
An address cast to an appropriate data type. For example, ‘*(int *)0x12345678’ will
watch a 4-byte region at the specified address (assuming an int occupies 4 bytes).
An arbitrarily complex expression, such as ‘a*b + c/d’. The expression can use any operators
valid in the program’s native language.
Depending on your system, watchpoints may be implemented in software or hardware.
gdb does software watchpointing by single-stepping your program and testing the variable’s
value each time, which is hundreds of times slower than normal execution.
watch expr [thread threadnum]:当express被改写时
Set a watchpoint for an expression. gdb will break when the expression expr
is written into by the program and its value changes.
rwatch expr [thread threadnum]:当express被读取时
Set a watchpoint that will break when the value of expr is read by the program.
awatch expr [thread threadnum]:当express被读写时
Set a watchpoint that will break when expr is either read from or written into
by the program.
 
Warning: In multi-threaded programs, software watchpoints have only limited
usefulness. If gdb creates a software watchpoint, it can only watch the value
of an expression in a single thread.
 
17. gdb可以用catchpoint开捕获event,如throw,catch,syscall等事件
You can use catchpoints to cause the debugger to stop for certain kinds of program events,
such as C++ exceptions or the loading of a shared library. Use the catch command to set
a catchpoint.
catch event
Stop when event occurs. event can be any of the following:
throw The throwing of a C++ exception.
catch The catching of a C++ exception.
exception
An Ada exception being raised. If an exception name is specified
at the end of the command (eg catch exception Program_Error),
the debugger will stop only when this specific exception is raised.
Otherwise, the debugger stops execution when any Ada exception
is raised.
When inserting an exception catchpoint on a user-defined exception
whose name is identical to one of the exceptions defined by the language,
the fully qualified name must be used as the exception name.
Otherwise, gdb will assume that it should stop on the pre-defined
exception rather than the user-defined one. For instance, assuming
an exception called Constraint_Error is defined in package
Pck, then the command to use to catch such exceptions is catch
exception Pck.Constraint_Error.
exception unhandled
An exception that was raised but is not handled by the program.
assert A failed Ada assertion.
exec A call to exec. This is currently only available for HP-UX and
gnu/Linux.
syscall
syscall [name | number] ...
A call to or return from a system call, a.k.a. syscall. A syscall is a
mechanism for application programs to request a service from the
operating system (OS) or one of the OS system services. gdb can
catch some or all of the syscalls issued by the debuggee, and show
the related information for each syscall. If no argument is specified,
calls to and returns from all system calls will be caught.
name can be any system call name that is valid for the underlying
OS. Just what syscalls are valid depends on the OS. On GNU and
Unix systems, you can find the full list of valid syscall names on
‘/usr/include/asm/unistd.h’.
Normally, gdb knows in advance which syscalls are valid for each
OS, so you can use the gdb command-line completion facilities (see
Section 3.2 [command completion], page 19) to list the available
choices.
 
 
18.可以用if设置条件断点,之后还可以用condition来改变条件断点的条件
Break conditions can be specified when a breakpoint is set, by using ‘if’ in the arguments
to the break command. See Section 5.1.1 [Setting Breakpoints], page 44. They can also be
changed at any time with the condition command.
You can also use the if keyword with the watch command. The catch command does
not recognize the if keyword; condition is the only way to impose a further condition on
a catchpoint.
18.1condition bnum expression
Specify expression as the break condition for breakpoint, watchpoint, or catchpoint
number bnum. After you set a condition, breakpoint bnum stops your
program only if the value of expression is true
 
17.handle signal [keywords...]:设置signal的处理
Change the way gdb handles signal signal. signal can be the number of a
signal or its name (with or without the ‘SIG’ at the beginning); a list of signal
numbers of the form ‘low-high’; or the word ‘all’, meaning all the known signals.
The keywords allowed by the handle command can be abbreviated. Their full names
are:
nostop gdb should not stop your program when this signal happens. It may still print a message telling you that the signal has come in.
stop gdb should stop your program when this signal happens. This implies the print keyword as well.
print gdb should print a message when this signal happens.
noprint gdb should not mention the occurrence of the signal at all. This implies the nostop keyword as well.
pass noignore gdb should allow your program to see this signal; your program can handle the signal, or else it may terminate if the signal is fatal and not handled. pass and noignore are synonyms.
nopass ignore gdb should not allow your program to see this signal. nopass and ignore are synonyms.
 
18. gdb可以配置多线程环境的debug模式,当一个thread被debug时,其他thread是stop还是自由的run。gdb有all-stop和non-stop模式。
Stopping and Starting Multi-thread Programs
In all-stop mode, whenever your program stops under gdb for any reason, all threads of
execution stop, not just the current thread.
Non-Stop Mode:In non-stop mode, when a thread stops to report a debugging event, only that thread is stopped; gdb does not stop other threads as well.To stop the
whole program, use interrupt -a.
To enter non-stop mode, use this sequence of commands before you run or attach to
your program:
# Enable the async interface.
set target-async 1
# If using the CLI, pagination breaks non-stop.
set pagination off
# Finally, turn it on!
set non-stop on
 
19. 在某些平台,gdb可以record并replay整个debug过程
On some platforms, gdb provides a special process record and replay target that can record
a log of the process execution, and replay it later with both forward and reverse execution
commands.
target record
This command starts the process record and replay target. The process record
and replay target can only debug a process that is already running. Therefore,
you need first to start the process with the run or start commands, and then
start the recording with the target record command.
Both record and rec are aliases of target record.
record stop
Stop the process record and replay target.
record save filename
Save the execution log to a file ‘filename’.
record restore filename
restore the execution log from a file ‘filename’.
 
20.directory dirname ...
dir dirname ...
增加source 文件的搜索路径Add directory dirname to the front of the source path.


21. set substitute-path from to是指source文件的替换路径,当代码树被移动过非常有用
Define a source path substitution rule, and add it at the end of the current list
of existing substitution rules. If a rule with the same from was already defined,
then the old rule is also deleted.
 
22.display expr:增加自动显示变量
Add the expression expr to the list of expressions to display each time your
program stops.


23.generate-core-file [file]
gcore [file]
生成某个时刻program的core dump。
24.搜索内存
Memory can be searched for a particular sequence of bytes with the find command.
find [/sn] start_addr, +len, val1 [, val2, ...]
find [/sn] start_addr, end_addr, val1 [, val2, ...]
Search memory for the sequence of bytes specified by val1, val2, etc.
 
25. 当程序严重依赖real-time时,我们不想在debug时停止下来与用于交互,可以用trace 命令来跟踪一个express。
If the program’s
correctness depends on its real-time behavior, delays introduced by a debugger might cause
the program to change its behavior drastically, or perhaps fail, even when the code itself is
correct. It is useful to be able to observe the program’s behavior without interrupting it.
Using gdb’s trace and collect commands, you can specify locations in the program,
called tracepoints, and arbitrary expressions to evaluate when those tracepoints are reached.
trace location:要trace的地方
The trace command is very similar to the break command
actions [num]
collect expr1, expr2, ...
Collect values of the given expressions when the tracepoint is hit.
$regs Collect all registers.
$args Collect all function arguments.
$locals Collect all local variables.
$_sdata Collect static tracepoint marker specific data.
teval expr1, expr2, ...
Evaluate the given expressions when the tracepoint is hit.
while-stepping n
Perform n single-step instruction traces after the tracepoint, collecting new data
after each step.
set default-collect expr1, expr2, ...
This variable is a list of expressions to collect at each tracepoint hit.
tstart This command takes no arguments. It starts the trace experiment, and begins
collecting data.
tstop This command takes no arguments. It ends the trace experiment, and stops
collecting data.
tfind start
Find the first snapshot in the buffer.
tsave [ -r ] filename
Save the trace data to filename.
26. gdb打印命令
26.1 gdb操作符
gdb除了支持编程语言支持的操作符外,还支持@, ::, {type}addr形式的操作符。
26.2 @操作符:
一个二进制操作符,把一片内存当作array来处理。@的左操作数是内存地址,右操作数为array的长度.
如代码为int *array = (int *) malloc (len * sizeof (int));
则可以用(gdb) p *array@len
另外还可以用强制转换来生成一个artificial array,如:
(gdb) p/x (short[2])0x12345678
$1 = {0x1234, 0x5678}
有时光用artificial array还不够,因为在复杂数据结构里,想查看的element并不连续,如想看一个struct里的某个指针字段的值,
这时就要与convenience variables结合起来。例如想看一个
struct
{
int a;
int* fv;
int c;
}dtab[10];里的fv的值,就可以用下面的命令:
(gdb) set $i = 0
(gdb) p dtab[$i++]->fv
(gdb) RET
(gdb) RET
(gdb) ...
26.3 ::操作符
假如一个变量在多个文件中定义,为避免gdb解释歧义,可以用::操作符来限定,如:
(gdb) file::variable
(gdb) function::variable
(gdb) p ’f2.c’::x
26.4 {type} addr:
把address转换成type类型, address不必非在内存中。
26.5 examine memory
形式如:
x/nfu addr
x addr
x Use the x command to examine memory.
其中,x为examine memory命令, n为重复次数,f为格式,与print命令参数一样,u为长度,如b,h,w,g,分别是1,2,4,8字节。
26.6 convenience variables
gdb提供convenience variables,形式为$abc,任何name前加$就为convenience variables,以后可以随时引用他。
convenience variables保存在gdb里,不是program的一部分,不会影响程序的运行。convenience variables没有类型,在express中引用会自动变换成express需要的类型。


26.7 value history
gdb把每一个print打印的值都保存下来,组成一个value history,并给他分配一个编号,编号从1开始顺序增加,以后可以用$1,$2的形式引用这些value。
$为最近的value(倒数第一个),$$最近再之前的value(倒数第二个), $$n为倒数第n个value.
例如有一段代码:
struct AA
{
int a;
struct AA* next;
};
struct AA * a = new struct AA[100];
(gdb) p/x a
(gdb) *$
(gdb) p *$.next
(gdb) RET
(gdb) RET
...就可以一直打印出来。
value history一直保存在gdb里,直到重读或丢弃了符号表。
另外value history保存的是print express命令时express的值,而不是express本身。如:x的值为4,在用下面两个命令后
(gdb)print x
(gdb)set x=5
但是value history里保存的值还是4,而不是5,尽管x的值已经改变了。
26.8 一些print的config
set print array on
set print array-indexes on
set print pretty on
set print object on
set print vtbl on
以下为从gdb摘抄原文:
gdb supports these operators, in addition to those common to programming languages:
@ ‘@’ is a binary operator for treating parts of memory as arrays.
referring to a contiguous span of memory as an artificial array, using
the binary operator ‘@’. The left operand of ‘@’ should be the first element of the desired
array and be an individual object. The right operand should be the desired length of the
array.
If a program says
int *array = (int *) malloc (len * sizeof (int));
you can print the contents of array with
(gdb) p *array@len
The left operand of ‘@’ must reside in memory.
Another way to create an artificial array is to use a cast. This re-interprets a value as if
it were an array. The value need not be in memory:
(gdb) p/x (short[2])0x12345678
$1 = {0x1234, 0x5678}
Sometimes the artificial array mechanism is not quite enough; in moderately complex
data structures, the elements of interest may not actually be adjacent—for example, if you
are interested in the values of pointers in an array. One useful work-around in this situation
is to use a convenience variable (see Section 10.11 [Convenience Variables], page 111) as
a counter in an expression that prints the first interesting value, and then repeat that
expression via RET. For instance, suppose you have an array dtab of pointers to structures,
and you are interested in the values of a field fv in each structure. Here is an example of
what you might type:
(gdb) set $i = 0
(gdb) p dtab[$i++]->fv
(gdb) RET
(gdb) RET
(gdb) ...
:: ‘::’ allows you to specify a variable in terms of the file or function where it is
defined.
(gdb) file::variable
(gdb) function::variable
Here file or function is the name of the context for the static variable. In the case of file
names, you can use quotes to make sure gdb parses the file name as a single word.
(gdb) p ’f2.c’::x
{type} addr
Refers to an object of type type stored at address addr in memory. addr may
be any expression whose value is an integer or pointer (but parentheses are
required around binary operators, just as in a cast). This construct is allowed
regardless of what kind of data is normally supposed to reside at addr.


examine memory in any of several formats,
independently of your program’s data types.
x/nfu addr
x addr
x Use the x command to examine memory.
n, f, and u are all optional parameters that specify how much memory to display and how
to format it; addr is an expression giving the address where you want to start displaying
memory.


gdb provides convenience variables that you can use within gdb to hold on to a value
and refer to it later. These variables exist entirely within gdb; they are not part of your
program, and setting a convenience variable has no direct effect on further execution of your
program. That is why you can use them freely.
Convenience variables are prefixed with ‘$’. Any name preceded by ‘$’ can be used for a
convenience variable, unless it is one of the predefined machine-specific register names.


Values printed by the print command are saved in the gdb value history. This allows you
to refer to them in other expressions. Values are kept until the symbol table is re-read or
discarded.
The values printed are given history numbers by which you can refer to them. These
are successive integers starting with one. print shows you the history number assigned to
a value by printing ‘$num = ’ before the value; here num is the history number.
Just $ refers to the most recent value in the history, and $$ refers to the value before that. $$n refers to the nth value from
the end;
For example, suppose you have just printed a pointer to a structure and want to see the
contents of the structure. It suffices to type
p *$
If you have a chain of structures where the component next points to the next one, you
can print the contents of the next one with this:
p *$.next
You can print successive links in the chain by repeating this command—which you can do
by just typing RET.
Note that the history records values, not expressions. If the value of x is 4 and you type
these commands:
print x
set x=5
then the value recorded in the value history by the print command remains 4 even though
the value of x has changed.


For implementing pretty printers for new types you should read the Python API details.
set print array on
Pretty print arrays. This format is more convenient to read, but uses more
space. The default is off.
set print array-indexes on
Print the index of each element when displaying arrays. May be more convenient
to locate a given element in the array or quickly find the index of a given element
in that printed array. The default is off.
set print pretty on
Cause gdb to print structures in an indented format with one member per line,
like this:
$1 = {
next = 0x0,
flags = {
sweet = 1,
sour = 1
},
meat = 0x54 "Pork"
}
set print object off
Display only the declared type of objects, without reference to the virtual function
table. This is the default setting.
set print vtbl on
Pretty print C++ virtual function tables. The default is off. (The vtbl commands
do not work on programs compiled with the HP ANSI C++ compiler
(aCC).)
0 0