notlesh
notlesh

Reputation: 645

GDB break on exception thrown when called from specific function

I would like to use GDB to break when an exception is thrown only when the stack goes through a specific function.

My use case is that I have a Thread class whose doRun() function is called in a new thread. That thread catches any exception that bubbles up, but I would like to be able to break when the exception is thrown (not caught).

I know GDB can do "reverse debugging" (awesome concept) so this could potentially be used, but I'd like something more general purpose -- in fact, I'd like this solution to find its way to my .gdbinit file.

Upvotes: 5

Views: 1358

Answers (2)

It doesn't appear $caller_matches (or its sister function $caller_is) are included in the base installation of GDB.


Go ahead and add the source code into your GDB python functions folder.

This folder is usually found in /usr/share/gdb/python/gdb/function; the filename should be caller_is.py.

Note that when using $caller_matches, the underlying implementation is using re.match, so make sure the string you pass it works with that function.

As well, both functions have an optional second parameter, defaulting to 1, that specifies how far up the stack to traverse (look). This means that if you omit it, it will only check the direct caller of the current function. If you want to check specific stack positions (i.e. if you want to check the grandparent caller), use 2, 3, etc..

I've included the source below.

# Caller-is functions.

# Copyright (C) 2008 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import gdb
import re

class CallerIs (gdb.Function):
    """Return True if the calling function's name is equal to a string.
This function takes one or two arguments.
The first argument is the name of a function; if the calling function's
name is equal to this argument, this function returns True.
The optional second argument tells this function how many stack frames
to traverse to find the calling function.  The default is 1."""

    def __init__ (self):
        super (CallerIs, self).__init__ ("caller_is")

    def invoke (self, name, nframes = 1):
        frame = gdb.selected_frame ()
        while nframes > 0:
            frame = frame.older ()
            nframes = nframes - 1
        return frame.name () == name.string ()

class CallerMatches (gdb.Function):
    """Return True if the calling function's name matches a string.
This function takes one or two arguments.
The first argument is a regular expression; if the calling function's
name is matched by this argument, this function returns True.
The optional second argument tells this function how many stack frames
to traverse to find the calling function.  The default is 1."""

    def __init__ (self):
        super (CallerMatches, self).__init__ ("caller_matches")

    def invoke (self, name, nframes = 1):
        frame = gdb.selected_frame ()
        while nframes > 0:
            frame = frame.older ()
            nframes = nframes - 1
        return re.match (name.string (), frame.name ()) is not None

CallerIs()
CallerMatches()

Upvotes: 5

Tom Tromey
Tom Tromey

Reputation: 22519

Recent versions of gdb have some convenience functions that are useful for this, e.g., "$_any_caller_matches". These are written in Python, so even if your gdb doesn't have them built-in, you might be able to grab the code and just drop it into your gdb.

You would use it like (untested, but you get the idea):

catch throw if $_any_caller_matches("Thread::doRun")

Upvotes: 7

Related Questions