The track
command allows you to track the data of gdb expressions on hitting breakpoints. While this module is active,
whenever a breakpoint is hit an internal callback will be called, this may be a performance issue for some. All
breakpoints that have a trackpoint attached will automatically continue when hit, making data collection an automated
task.
The (classic) quick way to use track is by using single breakpoints and/or attaching tracks to existing breakpoints. For more complex scenarios see the track set section later.
Shows the currently known breakpoints (similar to info break
) along with the information about registered tracking
information.
This will use gdbs existing breakpoint no num
and will execute expression
each time, recording the resulting string
along with a timestamp.
Instead of giving a number in num
you can also provide an expression that will then be given to gdb to create a new
breakpoint. This breakpoint however will remain active even after the trackpoint has been deleted. Be careful though
that you may end up with multiple breakpoints for the same address which may incur a performance hit. We try to filter
out by the location string you passed, but what gdb gives us may not always be the same you passed, thus we can not
distinguish.
See track expressions section later.
This shows a table with all the collected data. In (default) relative mode, all timestamps are relative to the first
recording. You can set vdb-track-time-relative
to disable this and use local timestamps instead (useful for long
running programs where the breakpoint is only hit occasionally). Note that this will display the string from the
expression per table entry without any further formatting, as such it is most wise to use expressions only that have
small outputs.
Setting vdb-track-clear-at-start
to off will disable the automated clearing of tracking data when (re)starting a
process.
If at a specific breakpoint an expression did not yield any output (or caused an exception) this field will remain empty.
This deletes a track entry by the number shown in track show
, just like del
does for breakpoints. You can specify
multiple trackpoints.
Clears the data cache displayed by track data
.
A track set is a bunch of more detailed track specifications that work together. There are a few predefined ones and then you can add your own. For most detail have a look at the ssl_set definition in track.py
ssl_set
ssl_set = {
"SSL_read" : # A function/location to set the breakpoint
[ # a list of "actions" with their parameters, a non matching "filter" will stop evaluation
( "filter", [ "map", "ssl_fd_filter", "s->rbio->num" ] ),
( "hex", [
( "buf", "$ret" ), # hex expects address and length
( "$rdi", "$ret" ) # only if the above doesn't work, try to fall back to these
]
),
],
"SSL_write" : [ ( "hex", [ ( "buf", "num" ), ( "$rdi", "$rsi" ) ] ) ],
"connect" : [
( "filter", [ "cmp", "{port}", "ntohs( ((uint16_t*)addr)[1] )/p" ] ),
( "filter", [ "cmp", "{ip}", "( ((sockaddr_in*)addr)->sin_addr)" ] ),
( "store", [ "fd", "ssl_fd_filter" ] )
],
"close" : [
( "delete", [ "fd", "ssl_fd_filter" ] )
]
}
A Set is a dict of breakpoint locations associated with a list of actions that may or may not work together. These
actions can have as parameters expressions that need to be evaluated. To define how to evaluate them, you can append a
/<epxression-specifieer
at the end. See track expressions section for details.
Each breakpoint location key has a list of tuples that each contain an action item. The first of the tuple is the name, the rest is depending on the action item type.
At certain points there is the possibility to use {name}
to request parameters. These must be specify in the form of
name=value
after the set enabling command.
Certain actions do support $ret
as the value. This is a special value that means the return value of the function the
breakpoint currently is in should be used.
Filters can abort the evaluation of the list of actions. The second parameter is a list of filter types. There are multiple types of filters:
cmp, <value>, <expression>
Compare the given value. Instead of a value you usually want to use{name}
to be able to specify that as a parameter when enabling the set.map, <mapname>, <expression>
Compare if the value of the expression is in a set previously filled by store actions.
To allow for multiple alternative syntaxes to access certain values, whenever a value of an expression is not available, the filter behaves as if the comparison yields true.
A store takes an expression and the name of a map. This name can be used in a map filter command. This is useful for when at a certain point your program maps something to an id but at the interesting points only the id is available for a filter. Multiple stores will store multiple values in a set.
The delete will delete the value from the set that is given by the mapname.
This action will output the given data as a hexdump. Instead of just a pair/tuple of buffer/size, this will take a list
of tuples. The first one that yields a result will be used to hexdump. Supports $ret
as an expression.
Takes a list of expressions (supports $ret
too ) that will then be filled into the internal track data store and are
available via track data
The following sets and their purpose are predefined
ssl
Hooks intoSSL_read
andSSL_write
and can filter by port and IP, and will display buffers as hexdumps.
Normally the expression is one that is evaluated by gdb to lead a gdb value of a variable by the given name.
There are various ways where you can append a single letter to a specification (Either track/x
for single tracks, or
at the end of an expression in track sets).
The meaning of the letters is as follows:
v
Query the currently selected frame (in the breakpoint) for a variable with that name. This is usually the default.x
Usegdb.execute()
on the expression and use the result (ususally a string).X
Usegdb.execute()
on the expression, but then usegdb.parse_and_eval("$")
to get the gdb.Value of that result.E
Use pythonseval()
to run the expression as python code. For convenience$()
is synonymous withgdb.parse_and_eval()
.p
Callgdb.parse_and_eval()
and use the result (usually gdb.Value).
Depending on the context where these values are being used, they can be subject to conversion to other types.