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
endSuppose 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
endThis 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
endHere'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
endSo 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.