提交 49598f5b 编写于 作者: C Cleber Rosa

Merge remote-tracking branch 'ldoktor/documentation2'

......@@ -16,13 +16,70 @@ remote protocol for interaction with a remote target.
Please refer to :mod:`avocado.gdb` for more information.
Example
~~~~~~~
Take a look at ``examples/tests/modify_variable.py`` test::
def action(self):
"""
Execute 'print_variable'.
"""
path = os.path.join(self.srcdir, 'print_variable')
app = gdb.GDB()
app.set_file(path)
app.set_break(6)
app.run()
self.log.info("\n".join(app.read_until_break()))
app.cmd("set variable a = 0xff")
app.cmd("c")
out = "\n".join(app.read_until_break())
self.log.info(out)
app.exit()
self.assertIn("MY VARIABLE 'A' IS: ff", out)
You can see that instead of running the binary using ``process.run`` we invoke
``gdb.GDB``. This allows us to automate the interaction with the GDB in means
of setting breakpoints, executing commands and querying for output.
When you check the output (``--show-job-log``) you can see that despite
declaring the variable as 0, ff is injected and printed instead.
Transparent Debugging Usage
---------------------------
This feature is implemented as a plugin, that adds the `--gdb-run-bin` option
to the avocado `run` command. For a detailed explanation please consult the
avocado man page.
This feature is implemented as a plugin, that adds the ``--gdb-run-bin``
option to the avocado ``run`` command.
Example
~~~~~~~
The simplest way is to just run
``avocado run --gdb-run-bin=doublefree examples/tests/doublefree.py``, which
wraps each executed binary with name ``doublefree`` inside GDB server and
stops at the binary entry point.
Optionally you can specify single breakpoint using
``--gdb-run-bin=doublefree:$breakpoint`` (eg: ``doublefree:1``) or just
``doublefree:`` to stop only when an interruption happens (eg: SIGABRT).
It's worth mentioning that when breakpoint is not reached, the test finishes
without any interruption. This is helpful when you identify regions where you
should never get in your code, or places which interests you and you can run
your code in production and gdb variants. If after a long time you get to this
place, the test notifies you and you can investigate the problem. This is
demonstrated in ``examples/tests/doublefree_nasty.py`` test. To unveil the
power of Avocadu, run this test using
``avocado run --gdb-run-bin=doublefree: examples/tests/doublefree_nasty.py --gdb-prerun-commands examples/tests/doublefree_nasty.py.data/gdb_pre --multiplex examples/tests/doublefree_nasty.py.data/iterations.yaml``,
which executes 100 iterations of this test while setting all breakpoints from
the ``examples/tests/doublefree_nasty.py.data/gdb_pre`` file (you can specify
whatever GDB supports, not only breakpoints).
As you can see this test usually passes, but once in a while it gets into
the problematic area. Imagine this is very hard to spot (dependent on HW
registers, ...) and this is one way to combine regular testing and the
possibility of debugging hard-to-get parts of your code.
Caveats
~~~~~~~
......
#!/usr/bin/python
import os
import shutil
from avocado import job
from avocado import test
from avocado.utils import build
from avocado.utils import process
class DoubleFreeTest(test.Test):
"""
10% chance to execute double free exception.
"""
default_params = {'source': 'doublefree.c'}
__binary = None # filename of the compiled program
def setup(self):
"""
Build 'doublefree'.
"""
c_file = self.get_data_path(self.params.source)
shutil.copy(c_file, self.srcdir)
self.__binary = self.params['source'].rsplit('.', 1)[0]
build.make(self.srcdir,
env={'CFLAGS': '-g -O0'},
extra_args=self.__binary)
def action(self):
"""
Execute 'doublefree'.
"""
cmd = os.path.join(self.srcdir, self.__binary)
cmd_result = process.run(cmd)
self.log.info(cmd_result)
if __name__ == "__main__":
job.main()
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void handle_exception() {
void *p = malloc(1024);
free(p);
free(p);
}
int main(int argc, char *argv[])
{
int num;
srand(time(NULL));
num = rand();
if (num < (RAND_MAX / 10)) {
handle_exception();
}
return 0;
}
iterations:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
#!/usr/bin/python
import os
import shutil
from avocado import gdb
from avocado import job
from avocado import test
from avocado.utils import build
class PrintVariableTest(test.Test):
"""
This demonstrates the GDB API
1) it executes C program which prints MY VARIABLE 'A' IS: 0
2) using GDB it modifies the variable to ff
3) checks the output
"""
default_params = {'source': 'print_variable.c'}
__binary = None # filename of the compiled program
def setup(self):
"""
Build 'print_variable'.
"""
c_file = self.get_data_path(self.params.source)
shutil.copy(c_file, self.srcdir)
self.__binary = self.params['source'].rsplit('.', 1)[0]
build.make(self.srcdir,
env={'CFLAGS': '-g -O0'},
extra_args=self.__binary)
def action(self):
"""
Execute 'print_variable'.
"""
path = os.path.join(self.srcdir, self.__binary)
app = gdb.GDB()
app.set_file(path)
app.set_break(6)
app.run()
self.log.info("\n".join(app.read_until_break()))
app.cmd("set variable a = 0xff")
app.cmd("c")
out = "\n".join(app.read_until_break())
self.log.info(out)
app.exit()
self.assertIn("MY VARIABLE 'A' IS: ff", out)
if __name__ == "__main__":
job.main()
#include <stdio.h>
int main(int argc, char *argv[])
{
int a = 0;
printf("MY VARIABLE 'A' IS: %x\n", a);
return 0;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册