183 lines
7.1 KiB
Markdown
183 lines
7.1 KiB
Markdown
---
|
|
date: 2012-10-27T00:00:00-05:00
|
|
title: "GDB and SystemTap Probes -- part 2"
|
|
tags: [en_us, gdb, systemtap, howto, fedora-planet, free-software]
|
|
---
|
|
|
|
I tell you this: it is depressing when you realize that you spent more
|
|
time struggling with blog engines than writing posts on your blog!
|
|
|
|
It's been a long time since I wrote
|
|
the
|
|
[first post]({filename}/2012-03-29-gdb-and-systemtap-probes-part-1.md) about
|
|
this subject, and since then the patches have been accepted upstream,
|
|
and [GDB 7.5](http://www.gnu.org/software/gdb/download/ANNOUNCEMENT)
|
|
now has official support for userspace SystemTap probes :-). Yay!
|
|
|
|
Well, but enough of cheap talk, let's get to the business!
|
|
|
|
Errata for my last post
|
|
-----------------------
|
|
|
|
[Frank Ch. Eigler](http://web.elastic.org/~fche/blog2/), one of
|
|
SystemTap's maintainers, kindly mentioned something that I should say
|
|
about SystemTap userspace probes.
|
|
|
|
Basically, it should be clear that `SDT` probes are not the only kind of
|
|
userspace probing one can do with SystemTap. There is yet another kind
|
|
of probe (maybe even more powerful, depending on the goals):
|
|
**DWARF-based function/statement probes**. SystemTap supports this kind
|
|
of probing mechanism for quite a while now.
|
|
|
|
It is not the goal of this post to explain it in detail, but you might
|
|
want to give it a try by compiling your binary with debuginfo support
|
|
(use the `-g` flag on `GCC`), and do something like:
|
|
|
|
#!bash
|
|
$ stap -e 'probe process("/bin/foo").function("name") { log($$parms) }' -c /bin/foo
|
|
$ stap -e 'probe process("/bin/foo").statement("*@file.c:443") { log($$vars) }' -c /bin/foo
|
|
|
|
And that's it. You can read SystemTap's documentation, or
|
|
[this](http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps)
|
|
guide to learn how to add userspace probes.
|
|
|
|
Using GDB with SystemTap SDT Probes
|
|
-----------------------------------
|
|
|
|
Well, now let's get to the interesting part. It is time to make `GDB`
|
|
work with the `SDT` probe that we have put in our example code. Let's
|
|
remember it:
|
|
|
|
#!c
|
|
#include <sys/sdt.h>
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int a = 10;
|
|
|
|
STAP_PROBE1 (test_program, my_probe, a);
|
|
|
|
return 0;
|
|
}
|
|
|
|
It is a very simple example, and we will have to extend it later in
|
|
order to show more features. But for now, it will do.
|
|
|
|
The first thing to do is to open `GDB` (with SystemTap support, of
|
|
course!), and check to see if it can actually see probe inserted in our
|
|
example.
|
|
|
|
#!bash
|
|
$ gdb ./test_program
|
|
GNU gdb (GDB) 7.5.50.20121014-cvs
|
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
|
...
|
|
(gdb) info probes
|
|
Provider Name Where Semaphore Object
|
|
test_program my_probe 0x00000000004004ae /home/sergio/work/src/git/build/gdb/test_program
|
|
|
|
Wow, it actually works! :-)
|
|
|
|
If you have seen something like the above, it means your `GDB` is
|
|
correctly recognizing `SDT` probes. If you see an error, or if your
|
|
`GDB` doesn't have the `info probes` command, then you'd better make
|
|
sure you have a recent version of `GDB` otherwise you won't be able to
|
|
use the `SDT` support.
|
|
|
|
### Putting breakpoints in the code
|
|
|
|
Anyway, now it is time to start using this support. The first thing I
|
|
want to show you is how to put a breakpoint in a probe.
|
|
|
|
#!bash
|
|
(gdb) break -probe-stap my_probe
|
|
Breakpoint 1 at 0x4004ae
|
|
|
|
That's all! We have chosen to extend the `break` command in order to
|
|
support the new `-probe-stap` parameter. If you're wondering *... why
|
|
the -probe prefix?*, it is because I was asked to implement a complete
|
|
abstraction layer inside `GDB` in order to allow more types of probes to
|
|
be added in the future. So, for example, if someone implements support
|
|
for an hypothetical type of probe called `xyz`, you would have
|
|
`break -probe-xyz`. It took me a little more time to implement this
|
|
layer, but it is worth the effort.
|
|
|
|
Anyway, as you have see above, `GDB` recognize the probe's name and
|
|
correctly put a breakpoint in it. You can also confirm that it has done
|
|
the right thing by matching the address reported by `info probes` with
|
|
the one reported by `break`: they should be the same.
|
|
|
|
Ok, so now, with our `breakpoint` in place, let's run the program and
|
|
see what happens.
|
|
|
|
#!bash
|
|
(gdb) run
|
|
Starting program: /home/sergio/work/src/git/build/gdb/test_program
|
|
|
|
Breakpoint 1, main (argc=1, argv=0x7fffffffdf68) at /tmp/example-stap.c:8
|
|
8 STAP_PROBE1 (test_program, my_probe, a);
|
|
|
|
As you can see, `GDB` stopped at the exact location of the probe.
|
|
Therefore, you are now able to put marks (i.e., probes) in your source
|
|
code which are **location-independent**. It means that it doesn't really
|
|
matter where in the source code your probe is, and it also doesn't
|
|
matter if you change the code around it, changing the line numbers, or
|
|
even moving it to another file. `GDB` will always find your probe, and
|
|
always stop at the right location. Neat!
|
|
|
|
### Examining probes' arguments
|
|
|
|
But wait, there's more! Remember when I told you that you could also
|
|
inspect the probe's arguments? Yes, let's do it now!
|
|
|
|
Just remember that, in `SDT`'s parlance, the current probe's argument is
|
|
`a`. So let's print its value.
|
|
|
|
#!bash
|
|
(gdb) p $_probe_arg0
|
|
$1 = 10
|
|
(gdb) p a
|
|
$2 = 10
|
|
|
|
*"Hey, captain, it seems the boat really floats!"*
|
|
|
|
Check the source code above, and convince yourself that `a`'s value is
|
|
`10` :-). As you might have seen, I have used a fairly strange way of
|
|
printing it. It is because the probe's arguments are available inside
|
|
`GDB` by means of **convenience variables**. You can see a list of them
|
|
[here](http://sourceware.org/gdb/current/onlinedocs/gdb/Convenience-Vars.html#Convenience-Vars).
|
|
|
|
Since `SDT` probes can have up to 12 arguments (i.e., you can use
|
|
`STAP_PROBE1` ... `STAP_PROBE12`), we have created inside `GDB` 12
|
|
convenience variables, named `$_probe_arg0` until `$_probe_arg11`. I
|
|
know, it is not an easy name to remember, and even the relation between
|
|
`SDT` naming and `GDB` naming is not direct (i.e., you have to subtract
|
|
1 from the `SDT` probe number). If you are not satisfied with this,
|
|
please open a bug in our [bugzilla](http://sourceware.org/bugzilla/) and
|
|
I promise we will discuss other options.
|
|
|
|
I would like to emphasize something here: just as you don't need
|
|
debuginfo support for dealing with probes inside `GDB`, you also don't
|
|
need debuginfo support for dealing with their arguments as well. It
|
|
means that you can actually compile your code without debuginfo support,
|
|
but still have access to some important variables/expressions when
|
|
debugging it. Depending on how `GCC` optimizes your code, you may
|
|
experience some difficulties with argument printing, but so far I
|
|
haven't heard of anything like that.
|
|
|
|
More to come
|
|
------------
|
|
|
|
Ok, now we have covered more things about the `SDT` probe support inside
|
|
`GDB`, and I hope you understood all the concepts. It is not hard to get
|
|
things going with this, specially because you don't need extra libraries
|
|
to make it work.
|
|
|
|
In the next post, I intend to finish this series by explaining how to
|
|
use `tracepoints` with `SDT` probes. Also, as I said in the previous
|
|
post of this series, maybe I will talk a little bit about how the `SDT`
|
|
probes are organized within the binary.
|
|
|
|
See you soon!
|