If we have a binary tree, how do we determine if a key is in the tree? Or another way, how do we know it was inserted correctly? We need to visit every node.
This is a recursive problem and hard to do in gdb. The convenience variables are very simple and we can not implement a stack with them. Since they are effectively global, we can not even hide them in stack frames. What we can do is use concatenation and a node-id to generate uniqe names.
Note that you have to do all variable name declarations before you do any recursion. That statement will make sense when you violate it and wonder why your output looks strange.
define indentby printf "%*c", $arg0+1, 0 end define walk_btree set $node_$arg0 = ($arg1) set $fnum_$arg0 = ($arg2) set $branch_$arg0 = ($arg3) set $space_$arg0 = ($arg4) set $leftid_$arg0 = $arg0 + 1 set $rightid_$arg0 = $arg0 + 2 indentby $space_$arg0 printf "%d %u (btree *)%p\n", $branch_$arg0, $node_$arg0->e_type[$fnum_$arg0].key, $node_$arg0 set $space_$arg0 = $space_$arg0 + 1 if $node_$arg0->e_type[$fnum_$arg0].left walk_btree $leftid_$arg0 $node_$arg0->e_type[$fnum_$arg0].left $fnum_$arg0 0 $space_$arg0 end if $node_$arg0->e_type[$fnum_$arg0].right walk_btree $rightid_$arg0 $node_$arg0->e_type[$fnum_$arg0].right $fnum_$arg0 1 $space_$arg0 end end document walk_btree NODE-ID NODE FNUM BRANCH INDENTBY Recursively walk the binary tree printing out the key for the fnum'ed entry end define start_walk_btree walk_btree 0 $arg0 $arg1 3 1 end document start_walk_btree NODE FNUM Recursively walk the binary tree printing out the key for the fnum'ed entry end
Contrast that against a very simple algorithm to find if the key is in the tree (with the assumption the tree is valid).
Recursion is not needed as we lop of a branch with each iteration.
define find_btree set $node = $arg0 set $fnum = $arg1 set $key = $arg2 set $process = 1 while $node && $process if $key == $node->e_type[$fnum].key set $process = 0 else if $key < $node->e_type[$fnum].key $node = $node->e_type[$fnum].left else $node = $node->e_type[$fnum].right end end end if $node printf "Found match on (btree *)%p\n", $node else printf "No matching node in the binary tree\n" end end
Hello,
Thanks for sharing. This gave me the hint that I needed to find a solution to my problem (recursively printing a memory pool tree and finding corrupted nodes)
I suspected the solution would be using something similar to PHP variable variables (creating new variables out of a variable name)
There is one thing however that I had to do different from you, perhaps due to GDB version?
Your macro:
define indentby
printf “%*c”, $arg0+1, 0
end
It did not work for me, what is the “*” supposed to do?
I had to do a while loop printing an space (with no line terminator) from 0 to $arg0 to print the number of indentations I wanted, such as:
define __indentby
set $indent_count = 0
while $indent_count < $arg0
printf “%4c”, ‘ ‘
set $indent_count = $indent_count + 1
end
end
Note that this will work, though perhaps not quite in the way you intended it to. $arg* are special, they will be replaced verbatim without evaluation (and that’s actually the only reason why you can construct variable names with them the way you do):
define walk_btree_x
set $leftid_$arg0 = $arg0 + 1
set $rightid_$arg0 = $arg0 + 2
print “$arg0”
print “$arg1”
if $arg1 < 3
walk_btree_x $leftid_$arg0 ($arg1+1)
walk_btree_x $rightid_$arg0 ($arg1+1)
end
end
walk_btree_x 0 0
Thus, you are effectively constructing variables like $leftid_$leftid_$leftid_0, not like $leftid_3. You are simulating a stack by prefixing.
Thus, in fact,
set $leftid_$arg0 = $arg0 + 1
and
set $rightid_$arg0 = $arg0 + 2
are completely irrelvant and can be omitted. The values will never be used.
If you want $leftid_3 (though I don't really see a reason why), you have to use eval. That will work only with a process to debug, however, not on a core file. (Might not bother you since you are already using printf, which has the same restrictions.)
Thank you.
This helped me solve my problem.
I am really surprised how GDB is so limited when it is a very old tool. I would expect it to be very rich and powerful.
Very interesting article. However, does recursion actually work in GDB in your first example? Does this command actually walk tree of any reasonable depth?