I'm trying to track down some refcnt leaks in the Linux kernel (specifically in the ax.25 subsystem). I'm trying to see if calls to netdev_put
balance with calls to netdev_hold
, and to do so I'm using breakpoints like this:
break netdev_hold
commands
silent
if $_regex(dev->name, "ax")
printf "netdev_hold %s r:%d u:%d n:%d\n", dev->name, dev->dev_refcnt->refs->counter, dev->refcnt_tracker->untracked->refs->counter, dev->refcnt_tracker->no_tracker->refs->counter
end
continue
end
break netdev_put
commands
silent
if $_regex(dev->name, "ax")
printf "netdev_put %s r:%d u:%d n:%d\n", dev->name, dev->dev_refcnt->refs->counter, dev->refcnt_tracker->untracked->refs->counter, dev->refcnt_tracker->no_tracker->refs->counter
end
continue
end
The goal is to only print information when we're dealing with ax*
interfaces. This works, mostly, except once in a while it results in:
value has been optimized out
And that causes gdb to drop back to the (gdb)
prompt. Is there a way to ignore this error so that gdb will continue in any case? I wasn't sure how to write "if the named variable is available" in gdb.
I guess I should be clear that I'm not looking to disable optimizations -- the cases in which netdev_{hold,put}
is called when dev
is not available are not cases in which I am interested.
Using the linked solution as inspiration, I ended up writing a new "is_optimized_out" convenience function, like this:
class IsOptimizedOutFunction(gdb.Function):
def __init__ (self):
super ().__init__ ("is_optimized_out")
def invoke (self, arg):
val = gdb.parse_and_eval(arg.string())
return val.is_optimized_out
IsOptimizedOutFunction()
That allows me to write a gdb script like this:
break netdev_hold
commands
silent
if ! $is_optimized_out("dev")
if $_regex(dev->name, "ax")
printf "netdev_hold %s r:%d u:%d n:%d\n", dev->name, dev->dev_refcnt->refs->counter, dev->refcnt_tracker->untracked->refs->counter, dev->refcnt_tracker->no_tracker->refs->counter
end
end
continue
end
And that does exactly what I want; the printf
only executes when netdev_hold
is called for ax*
devices, and doesn't abort if the value of dev
isn't available.
NB: You might look at this and ask yourself (or me), "why not write it like this?":
if ! $is_optimized_out("dev") && $_regex(dev->name, "ax")
printf ...
end
It appears that gdb
doesn't implement short-circuit behavior in boolean expressions, so even if ! $is_optimized_out()
is false, the second expression also gets evaluated, causing the commands to abort with the value has been optimized out
error.