Home | History | Annotate | Download | only in Lib
      1 """Debugger basics"""
      2 
      3 import fnmatch
      4 import sys
      5 import os
      6 import types
      7 
      8 __all__ = ["BdbQuit","Bdb","Breakpoint"]
      9 
     10 class BdbQuit(Exception):
     11     """Exception to give up completely"""
     12 
     13 
     14 class Bdb:
     15 
     16     """Generic Python debugger base class.
     17 
     18     This class takes care of details of the trace facility;
     19     a derived class should implement user interaction.
     20     The standard debugger class (pdb.Pdb) is an example.
     21     """
     22 
     23     def __init__(self, skip=None):
     24         self.skip = set(skip) if skip else None
     25         self.breaks = {}
     26         self.fncache = {}
     27 
     28     def canonic(self, filename):
     29         if filename == "<" + filename[1:-1] + ">":
     30             return filename
     31         canonic = self.fncache.get(filename)
     32         if not canonic:
     33             canonic = os.path.abspath(filename)
     34             canonic = os.path.normcase(canonic)
     35             self.fncache[filename] = canonic
     36         return canonic
     37 
     38     def reset(self):
     39         import linecache
     40         linecache.checkcache()
     41         self.botframe = None
     42         self._set_stopinfo(None, None)
     43 
     44     def trace_dispatch(self, frame, event, arg):
     45         if self.quitting:
     46             return # None

     47         if event == 'line':
     48             return self.dispatch_line(frame)
     49         if event == 'call':
     50             return self.dispatch_call(frame, arg)
     51         if event == 'return':
     52             return self.dispatch_return(frame, arg)
     53         if event == 'exception':
     54             return self.dispatch_exception(frame, arg)
     55         if event == 'c_call':
     56             return self.trace_dispatch
     57         if event == 'c_exception':
     58             return self.trace_dispatch
     59         if event == 'c_return':
     60             return self.trace_dispatch
     61         print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event)
     62         return self.trace_dispatch
     63 
     64     def dispatch_line(self, frame):
     65         if self.stop_here(frame) or self.break_here(frame):
     66             self.user_line(frame)
     67             if self.quitting: raise BdbQuit
     68         return self.trace_dispatch
     69 
     70     def dispatch_call(self, frame, arg):
     71         # XXX 'arg' is no longer used

     72         if self.botframe is None:
     73             # First call of dispatch since reset()

     74             self.botframe = frame.f_back # (CT) Note that this may also be None!

     75             return self.trace_dispatch
     76         if not (self.stop_here(frame) or self.break_anywhere(frame)):
     77             # No need to trace this function

     78             return # None

     79         self.user_call(frame, arg)
     80         if self.quitting: raise BdbQuit
     81         return self.trace_dispatch
     82 
     83     def dispatch_return(self, frame, arg):
     84         if self.stop_here(frame) or frame == self.returnframe:
     85             self.user_return(frame, arg)
     86             if self.quitting: raise BdbQuit
     87         return self.trace_dispatch
     88 
     89     def dispatch_exception(self, frame, arg):
     90         if self.stop_here(frame):
     91             self.user_exception(frame, arg)
     92             if self.quitting: raise BdbQuit
     93         return self.trace_dispatch
     94 
     95     # Normally derived classes don't override the following

     96     # methods, but they may if they want to redefine the

     97     # definition of stopping and breakpoints.

     98 
     99     def is_skipped_module(self, module_name):
    100         for pattern in self.skip:
    101             if fnmatch.fnmatch(module_name, pattern):
    102                 return True
    103         return False
    104 
    105     def stop_here(self, frame):
    106         # (CT) stopframe may now also be None, see dispatch_call.

    107         # (CT) the former test for None is therefore removed from here.

    108         if self.skip and \
    109                self.is_skipped_module(frame.f_globals.get('__name__')):
    110             return False
    111         if frame is self.stopframe:
    112             if self.stoplineno == -1:
    113                 return False
    114             return frame.f_lineno >= self.stoplineno
    115         while frame is not None and frame is not self.stopframe:
    116             if frame is self.botframe:
    117                 return True
    118             frame = frame.f_back
    119         return False
    120 
    121     def break_here(self, frame):
    122         filename = self.canonic(frame.f_code.co_filename)
    123         if not filename in self.breaks:
    124             return False
    125         lineno = frame.f_lineno
    126         if not lineno in self.breaks[filename]:
    127             # The line itself has no breakpoint, but maybe the line is the

    128             # first line of a function with breakpoint set by function name.

    129             lineno = frame.f_code.co_firstlineno
    130             if not lineno in self.breaks[filename]:
    131                 return False
    132 
    133         # flag says ok to delete temp. bp

    134         (bp, flag) = effective(filename, lineno, frame)
    135         if bp:
    136             self.currentbp = bp.number
    137             if (flag and bp.temporary):
    138                 self.do_clear(str(bp.number))
    139             return True
    140         else:
    141             return False
    142 
    143     def do_clear(self, arg):
    144         raise NotImplementedError, "subclass of bdb must implement do_clear()"
    145 
    146     def break_anywhere(self, frame):
    147         return self.canonic(frame.f_code.co_filename) in self.breaks
    148 
    149     # Derived classes should override the user_* methods

    150     # to gain control.

    151 
    152     def user_call(self, frame, argument_list):
    153         """This method is called when there is the remote possibility
    154         that we ever need to stop in this function."""
    155         pass
    156 
    157     def user_line(self, frame):
    158         """This method is called when we stop or break at this line."""
    159         pass
    160 
    161     def user_return(self, frame, return_value):
    162         """This method is called when a return trap is set here."""
    163         pass
    164 
    165     def user_exception(self, frame, exc_info):
    166         exc_type, exc_value, exc_traceback = exc_info
    167         """This method is called if an exception occurs,
    168         but only if we are to stop at or just below this level."""
    169         pass
    170 
    171     def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
    172         self.stopframe = stopframe
    173         self.returnframe = returnframe
    174         self.quitting = 0
    175         # stoplineno >= 0 means: stop at line >= the stoplineno

    176         # stoplineno -1 means: don't stop at all

    177         self.stoplineno = stoplineno
    178 
    179     # Derived classes and clients can call the following methods

    180     # to affect the stepping state.

    181 
    182     def set_until(self, frame): #the name "until" is borrowed from gdb

    183         """Stop when the line with the line no greater than the current one is
    184         reached or when returning from current frame"""
    185         self._set_stopinfo(frame, frame, frame.f_lineno+1)
    186 
    187     def set_step(self):
    188         """Stop after one line of code."""
    189         self._set_stopinfo(None, None)
    190 
    191     def set_next(self, frame):
    192         """Stop on the next line in or below the given frame."""
    193         self._set_stopinfo(frame, None)
    194 
    195     def set_return(self, frame):
    196         """Stop when returning from the given frame."""
    197         self._set_stopinfo(frame.f_back, frame)
    198 
    199     def set_trace(self, frame=None):
    200         """Start debugging from `frame`.
    201 
    202         If frame is not specified, debugging starts from caller's frame.
    203         """
    204         if frame is None:
    205             frame = sys._getframe().f_back
    206         self.reset()
    207         while frame:
    208             frame.f_trace = self.trace_dispatch
    209             self.botframe = frame
    210             frame = frame.f_back
    211         self.set_step()
    212         sys.settrace(self.trace_dispatch)
    213 
    214     def set_continue(self):
    215         # Don't stop except at breakpoints or when finished

    216         self._set_stopinfo(self.botframe, None, -1)
    217         if not self.breaks:
    218             # no breakpoints; run without debugger overhead

    219             sys.settrace(None)
    220             frame = sys._getframe().f_back
    221             while frame and frame is not self.botframe:
    222                 del frame.f_trace
    223                 frame = frame.f_back
    224 
    225     def set_quit(self):
    226         self.stopframe = self.botframe
    227         self.returnframe = None
    228         self.quitting = 1
    229         sys.settrace(None)
    230 
    231     # Derived classes and clients can call the following methods

    232     # to manipulate breakpoints.  These methods return an

    233     # error message is something went wrong, None if all is well.

    234     # Set_break prints out the breakpoint line and file:lineno.

    235     # Call self.get_*break*() to see the breakpoints or better

    236     # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().

    237 
    238     def set_break(self, filename, lineno, temporary=0, cond = None,
    239                   funcname=None):
    240         filename = self.canonic(filename)
    241         import linecache # Import as late as possible

    242         line = linecache.getline(filename, lineno)
    243         if not line:
    244             return 'Line %s:%d does not exist' % (filename,
    245                                    lineno)
    246         if not filename in self.breaks:
    247             self.breaks[filename] = []
    248         list = self.breaks[filename]
    249         if not lineno in list:
    250             list.append(lineno)
    251         bp = Breakpoint(filename, lineno, temporary, cond, funcname)
    252 
    253     def _prune_breaks(self, filename, lineno):
    254         if (filename, lineno) not in Breakpoint.bplist:
    255             self.breaks[filename].remove(lineno)
    256         if not self.breaks[filename]:
    257             del self.breaks[filename]
    258 
    259     def clear_break(self, filename, lineno):
    260         filename = self.canonic(filename)
    261         if not filename in self.breaks:
    262             return 'There are no breakpoints in %s' % filename
    263         if lineno not in self.breaks[filename]:
    264             return 'There is no breakpoint at %s:%d' % (filename,
    265                                     lineno)
    266         # If there's only one bp in the list for that file,line

    267         # pair, then remove the breaks entry

    268         for bp in Breakpoint.bplist[filename, lineno][:]:
    269             bp.deleteMe()
    270         self._prune_breaks(filename, lineno)
    271 
    272     def clear_bpbynumber(self, arg):
    273         try:
    274             number = int(arg)
    275         except:
    276             return 'Non-numeric breakpoint number (%s)' % arg
    277         try:
    278             bp = Breakpoint.bpbynumber[number]
    279         except IndexError:
    280             return 'Breakpoint number (%d) out of range' % number
    281         if not bp:
    282             return 'Breakpoint (%d) already deleted' % number
    283         bp.deleteMe()
    284         self._prune_breaks(bp.file, bp.line)
    285 
    286     def clear_all_file_breaks(self, filename):
    287         filename = self.canonic(filename)
    288         if not filename in self.breaks:
    289             return 'There are no breakpoints in %s' % filename
    290         for line in self.breaks[filename]:
    291             blist = Breakpoint.bplist[filename, line]
    292             for bp in blist:
    293                 bp.deleteMe()
    294         del self.breaks[filename]
    295 
    296     def clear_all_breaks(self):
    297         if not self.breaks:
    298             return 'There are no breakpoints'
    299         for bp in Breakpoint.bpbynumber:
    300             if bp:
    301                 bp.deleteMe()
    302         self.breaks = {}
    303 
    304     def get_break(self, filename, lineno):
    305         filename = self.canonic(filename)
    306         return filename in self.breaks and \
    307             lineno in self.breaks[filename]
    308 
    309     def get_breaks(self, filename, lineno):
    310         filename = self.canonic(filename)
    311         return filename in self.breaks and \
    312             lineno in self.breaks[filename] and \
    313             Breakpoint.bplist[filename, lineno] or []
    314 
    315     def get_file_breaks(self, filename):
    316         filename = self.canonic(filename)
    317         if filename in self.breaks:
    318             return self.breaks[filename]
    319         else:
    320             return []
    321 
    322     def get_all_breaks(self):
    323         return self.breaks
    324 
    325     # Derived classes and clients can call the following method

    326     # to get a data structure representing a stack trace.

    327 
    328     def get_stack(self, f, t):
    329         stack = []
    330         if t and t.tb_frame is f:
    331             t = t.tb_next
    332         while f is not None:
    333             stack.append((f, f.f_lineno))
    334             if f is self.botframe:
    335                 break
    336             f = f.f_back
    337         stack.reverse()
    338         i = max(0, len(stack) - 1)
    339         while t is not None:
    340             stack.append((t.tb_frame, t.tb_lineno))
    341             t = t.tb_next
    342         if f is None:
    343             i = max(0, len(stack) - 1)
    344         return stack, i
    345 
    346     #

    347 
    348     def format_stack_entry(self, frame_lineno, lprefix=': '):
    349         import linecache, repr
    350         frame, lineno = frame_lineno
    351         filename = self.canonic(frame.f_code.co_filename)
    352         s = '%s(%r)' % (filename, lineno)
    353         if frame.f_code.co_name:
    354             s = s + frame.f_code.co_name
    355         else:
    356             s = s + "<lambda>"
    357         if '__args__' in frame.f_locals:
    358             args = frame.f_locals['__args__']
    359         else:
    360             args = None
    361         if args:
    362             s = s + repr.repr(args)
    363         else:
    364             s = s + '()'
    365         if '__return__' in frame.f_locals:
    366             rv = frame.f_locals['__return__']
    367             s = s + '->'
    368             s = s + repr.repr(rv)
    369         line = linecache.getline(filename, lineno, frame.f_globals)
    370         if line: s = s + lprefix + line.strip()
    371         return s
    372 
    373     # The following two methods can be called by clients to use

    374     # a debugger to debug a statement, given as a string.

    375 
    376     def run(self, cmd, globals=None, locals=None):
    377         if globals is None:
    378             import __main__
    379             globals = __main__.__dict__
    380         if locals is None:
    381             locals = globals
    382         self.reset()
    383         sys.settrace(self.trace_dispatch)
    384         if not isinstance(cmd, types.CodeType):
    385             cmd = cmd+'\n'
    386         try:
    387             exec cmd in globals, locals
    388         except BdbQuit:
    389             pass
    390         finally:
    391             self.quitting = 1
    392             sys.settrace(None)
    393 
    394     def runeval(self, expr, globals=None, locals=None):
    395         if globals is None:
    396             import __main__
    397             globals = __main__.__dict__
    398         if locals is None:
    399             locals = globals
    400         self.reset()
    401         sys.settrace(self.trace_dispatch)
    402         if not isinstance(expr, types.CodeType):
    403             expr = expr+'\n'
    404         try:
    405             return eval(expr, globals, locals)
    406         except BdbQuit:
    407             pass
    408         finally:
    409             self.quitting = 1
    410             sys.settrace(None)
    411 
    412     def runctx(self, cmd, globals, locals):
    413         # B/W compatibility

    414         self.run(cmd, globals, locals)
    415 
    416     # This method is more useful to debug a single function call.

    417 
    418     def runcall(self, func, *args, **kwds):
    419         self.reset()
    420         sys.settrace(self.trace_dispatch)
    421         res = None
    422         try:
    423             res = func(*args, **kwds)
    424         except BdbQuit:
    425             pass
    426         finally:
    427             self.quitting = 1
    428             sys.settrace(None)
    429         return res
    430 
    431 
    432 def set_trace():
    433     Bdb().set_trace()
    434 
    435 
    436 class Breakpoint:
    437 
    438     """Breakpoint class
    439 
    440     Implements temporary breakpoints, ignore counts, disabling and
    441     (re)-enabling, and conditionals.
    442 
    443     Breakpoints are indexed by number through bpbynumber and by
    444     the file,line tuple using bplist.  The former points to a
    445     single instance of class Breakpoint.  The latter points to a
    446     list of such instances since there may be more than one
    447     breakpoint per line.
    448 
    449     """
    450 
    451     # XXX Keeping state in the class is a mistake -- this means

    452     # you cannot have more than one active Bdb instance.

    453 
    454     next = 1        # Next bp to be assigned

    455     bplist = {}     # indexed by (file, lineno) tuple

    456     bpbynumber = [None] # Each entry is None or an instance of Bpt

    457                 # index 0 is unused, except for marking an

    458                 # effective break .... see effective()

    459 
    460     def __init__(self, file, line, temporary=0, cond=None, funcname=None):
    461         self.funcname = funcname
    462         # Needed if funcname is not None.

    463         self.func_first_executable_line = None
    464         self.file = file    # This better be in canonical form!

    465         self.line = line
    466         self.temporary = temporary
    467         self.cond = cond
    468         self.enabled = 1
    469         self.ignore = 0
    470         self.hits = 0
    471         self.number = Breakpoint.next
    472         Breakpoint.next = Breakpoint.next + 1
    473         # Build the two lists

    474         self.bpbynumber.append(self)
    475         if (file, line) in self.bplist:
    476             self.bplist[file, line].append(self)
    477         else:
    478             self.bplist[file, line] = [self]
    479 
    480 
    481     def deleteMe(self):
    482         index = (self.file, self.line)
    483         self.bpbynumber[self.number] = None   # No longer in list

    484         self.bplist[index].remove(self)
    485         if not self.bplist[index]:
    486             # No more bp for this f:l combo

    487             del self.bplist[index]
    488 
    489     def enable(self):
    490         self.enabled = 1
    491 
    492     def disable(self):
    493         self.enabled = 0
    494 
    495     def bpprint(self, out=None):
    496         if out is None:
    497             out = sys.stdout
    498         if self.temporary:
    499             disp = 'del  '
    500         else:
    501             disp = 'keep '
    502         if self.enabled:
    503             disp = disp + 'yes  '
    504         else:
    505             disp = disp + 'no   '
    506         print >>out, '%-4dbreakpoint   %s at %s:%d' % (self.number, disp,
    507                                                        self.file, self.line)
    508         if self.cond:
    509             print >>out, '\tstop only if %s' % (self.cond,)
    510         if self.ignore:
    511             print >>out, '\tignore next %d hits' % (self.ignore)
    512         if (self.hits):
    513             if (self.hits > 1): ss = 's'
    514             else: ss = ''
    515             print >>out, ('\tbreakpoint already hit %d time%s' %
    516                           (self.hits, ss))
    517 
    518 # -----------end of Breakpoint class----------

    519 
    520 def checkfuncname(b, frame):
    521     """Check whether we should break here because of `b.funcname`."""
    522     if not b.funcname:
    523         # Breakpoint was set via line number.

    524         if b.line != frame.f_lineno:
    525             # Breakpoint was set at a line with a def statement and the function

    526             # defined is called: don't break.

    527             return False
    528         return True
    529 
    530     # Breakpoint set via function name.

    531 
    532     if frame.f_code.co_name != b.funcname:
    533         # It's not a function call, but rather execution of def statement.

    534         return False
    535 
    536     # We are in the right frame.

    537     if not b.func_first_executable_line:
    538         # The function is entered for the 1st time.

    539         b.func_first_executable_line = frame.f_lineno
    540 
    541     if  b.func_first_executable_line != frame.f_lineno:
    542         # But we are not at the first line number: don't break.

    543         return False
    544     return True
    545 
    546 # Determines if there is an effective (active) breakpoint at this

    547 # line of code.  Returns breakpoint number or 0 if none

    548 def effective(file, line, frame):
    549     """Determine which breakpoint for this file:line is to be acted upon.
    550 
    551     Called only if we know there is a bpt at this
    552     location.  Returns breakpoint that was triggered and a flag
    553     that indicates if it is ok to delete a temporary bp.
    554 
    555     """
    556     possibles = Breakpoint.bplist[file,line]
    557     for i in range(0, len(possibles)):
    558         b = possibles[i]
    559         if b.enabled == 0:
    560             continue
    561         if not checkfuncname(b, frame):
    562             continue
    563         # Count every hit when bp is enabled

    564         b.hits = b.hits + 1
    565         if not b.cond:
    566             # If unconditional, and ignoring,

    567             # go on to next, else break

    568             if b.ignore > 0:
    569                 b.ignore = b.ignore -1
    570                 continue
    571             else:
    572                 # breakpoint and marker that's ok

    573                 # to delete if temporary

    574                 return (b,1)
    575         else:
    576             # Conditional bp.

    577             # Ignore count applies only to those bpt hits where the

    578             # condition evaluates to true.

    579             try:
    580                 val = eval(b.cond, frame.f_globals,
    581                        frame.f_locals)
    582                 if val:
    583                     if b.ignore > 0:
    584                         b.ignore = b.ignore -1
    585                         # continue

    586                     else:
    587                         return (b,1)
    588                 # else:

    589                 #   continue

    590             except:
    591                 # if eval fails, most conservative

    592                 # thing is to stop on breakpoint

    593                 # regardless of ignore count.

    594                 # Don't delete temporary,

    595                 # as another hint to user.

    596                 return (b,0)
    597     return (None, None)
    598 
    599 # -------------------- testing --------------------

    600 
    601 class Tdb(Bdb):
    602     def user_call(self, frame, args):
    603         name = frame.f_code.co_name
    604         if not name: name = '???'
    605         print '+++ call', name, args
    606     def user_line(self, frame):
    607         import linecache
    608         name = frame.f_code.co_name
    609         if not name: name = '???'
    610         fn = self.canonic(frame.f_code.co_filename)
    611         line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
    612         print '+++', fn, frame.f_lineno, name, ':', line.strip()
    613     def user_return(self, frame, retval):
    614         print '+++ return', retval
    615     def user_exception(self, frame, exc_stuff):
    616         print '+++ exception', exc_stuff
    617         self.set_continue()
    618 
    619 def foo(n):
    620     print 'foo(', n, ')'
    621     x = bar(n*10)
    622     print 'bar returned', x
    623 
    624 def bar(a):
    625     print 'bar(', a, ')'
    626     return a/2
    627 
    628 def test():
    629     t = Tdb()
    630     t.run('import bdb; bdb.foo(10)')
    631 
    632 # end

    633