Introduction
gdb allows you to define your own commands which perform a sequence of actions. These can be useful for examining or dumping out complex data structures. This page has a few such commands which you might find useful.
Note that when dumping a large about of text, you may want to start gdb inside the script(1) command. Also, this gdb command turns off gdb's prompting for more output after every page of text:
set pagination off
Also if you're running gdb on one of the programs that uses the Boehm garbage collector, you probably want to let the signal used by the GC proceed unhindered. On Linux, the two signals normally used are SIGPWR and SIGXCPU, so in gdb you would use these commands.
handle SIGPWR pass nostop noprint handle SIGXCPU pass nostop noprint
In other contexts the garbage collector might use different signals.
Dump a Table
This can be used to print out all the entries in an instance of the Table::Default class from the generics library.
define dumpTable set $table = $arg0 set $bucket = 0 while $bucket < (1 << $table->logBuckets) printf "bucket %d\n", $bucket set $elist = $table->buckets[$bucket] while $elist != 0 print * $elist set $elist = $elist->tail end set $bucket = $bucket + 1 end end
Note that this takes a pointer to a Table as its argument. So in a case like this:
(gdb) print dsidTable $2 = (DirShortIdTable *) 0x5aa6310
You can pass the variable directly:
(gdb) dumpTable dsidTable bucket 0 bucket 1 bucket 2 $827 = {tail = 0x773bfa0, key = {sid = 1519249933}, val = {sp = 270537073}} $828 = {tail = 0x80990a0, key = {sid = 1416915778}, val = {sp = 514370065}} $829 = {tail = 0x0, key = {sid = 1595247962}, val = {sp = 786996209}} bucket 3 $830 = {tail = 0x0, key = {sid = 1939160287}, val = {sp = 121362745}} bucket 4 ...
However if the variable is an instance or a reference rather than a pointer you would need to take its address:
(gdb) dumpTable &vrtTable
Dump VDirChangeable blocks, entries
While they don't dump every piece of data you might be interested in, these can be useful for walking though a VDirChangeable block by block and entry by entry:
# Dump out useful information about a rep block define dumpRepBlock set $moreOrBase = (*((unsigned char *) $arg0) >> 2) & 3 if $moreOrBase == 1 printf "more block = " x/1wx $arg0 + 1 else printf "base block = " x/1wx $arg0 + 1 end printf "firstEntry = " output ((Bit8 *) ($arg0 + 29)) echo \n end # Dump out some useful information about a VDirChangeable entry define dumpEntry if (*((unsigned char *) $arg0)) == 0xff echo endMark (go to next rep block)\n else printf "type = %d\n", (((*($arg0)) >> 4) & 0xf) set $sameAsBase = (*($arg0)) & 8 if $sameAsBase printf "sameAsBase\n" end printf "value = " x/1wx $arg0 + 1 set $hasEFP = (*($arg0)) & 4 if $hasEFP set $arcLen = (*((unsigned char *) $arg0+25)) printf "arcLen = %d\n", $arcLen if $arcLen > 0 printf "arc = " output ((char *) ($arg0+26)) echo \n end printf "nextEntry = " output ((Bit8 *) ($arg0 + $arcLen + 26)) echo \n else set $arcLen = (*((unsigned char *) $arg0+9)) printf "arcLen = %d\n", $arcLen if $arcLen > 0 printf "arc = " output ((char *) ($arg0+10)) echo \n end printf "nextEntry = " output ((Bit8 *) ($arg0 + $arcLen + 10)) echo \n end end end # Get the next VDirChangeable entry define nextEntry set $hasEFP = (*($arg0)) & 4 if $hasEFP set $arcLen = (*((unsigned char *) $arg0+25)) print ((Bit8 *) ($arg0 + $arcLen + 26)) else set $arcLen = (*((unsigned char *) $arg0+9)) print ((Bit8 *) ($arg0 + $arcLen + 10)) end end
Evaluator Context
In the evaluator code the "Context" type is used for bindings and variables. It's stored as a linked list, and if you want to find a particular entry it can be annoying.
If you have a debugger for a running process, you can use this to search for a particular entry:
define searchContext set $context = $arg0 set $name = $arg1 set $pair = $context.list while $pair != 0 if strcmp($pair->first->name.s, $name) == 0 print *($pair->first) set $pair = 0 else set $pair = $pair->tail end end end
Suppose you're stopped in ApplicationFromCache (in ApplyCache.C) and you want to search through the function arguments for the value of ./foo/bar. You could use searchContext to do this:
(gdb) searchContext argsCon "." $92 = {name = {<Text> = {s = 0x2a95f85ea8 "."}, <No data fields>}, val = 0x2a98fa0e10} (gdb) print ((Binding) $92.val)->elems $93 = {list = 0x2a97c00730, last = 0x2a97c03080} (gdb) searchContext $93 "foo" $94 = {name = {<Text> = {s = 0x2a95f8e3b0 "foo"}, <No data fields>}, val = 0x2a98f93780} (gdb) print ((Binding) $94.val)->elems $95 = {list = 0x2a983ea990, last = 0x2a983ea830} (gdb) searchContext $95 "expert" $96 = {name = {<Text> = {s = 0x2a96ae2e68 "expert"}, <No data fields>}, val = 0x2a98f66cd0}
At this point $96.val is the pointer to the data structure for the value of ./foo/bar.
You can't use searchContext with a core dump though, since it calls strcmp. In that case you can still perform a search, but you'll need to know the pointer to the string you're looking for. Since Context elements use the Atom type, this isn't a huge burden. Here's an alternative that searches by string pointer:
define searchContext2 set $context = $arg0 set $name = $arg1 set $pair = $context.list while $pair != 0 if ($pair->first->name.s == $name) print *($pair->first) end set $pair = $pair->tail end end
This simpler sequence will tell you the length of a Context:
define contextLength set $context = $arg0 set $len = 0 set $pair = $context.list while $pair != 0 set $len = $len+1 set $pair = $pair->tail end print $len end
Here's an even simpler sequence to dump a context:
define dumpContext set $context = $arg0 set $pair = $context.list while $pair != 0 print *($pair->first) set $pair = $pair->tail end end
PrefixTbl
The evaluator and cache use the PrefixTbl class for compressed encodings of multiple paths with shared prefixes. If you need to find a particular entry in a PrefixTbl, this can be used to search by arc in the table:
define searchPrefixTbl set $tbl = $arg0 set $name = $arg1 set $i = 0 while $i < $tbl.numArcs if strcmp($tbl.arcArray[$i], $name) == 0 printf "%d\n", $i end set $i = $i + 1 end end
So if you're looking for the path "./foo/bar" in the PrefixTbl "names.tbl" you could use:
searchPrefixTbl names.tbl "bar"
Note that this calls strcmp so it won't work with a core file.