Home | History | Annotate | Download | only in python2.7
      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         self.frame_returning = None
     28 
     29     def canonic(self, filename):
     30         if filename == "<" + filename[1:-1] + ">":
     31             return filename
     32         canonic = self.fncache.get(filename)
     33         if not canonic:
     34             canonic = os.path.abspath(filename)
     35             canonic = os.path.normcase(canonic)
     36             self.fncache[filename] = canonic
     37         return canonic
     38 
     39     def reset(self):
     40         import linecache
     41         linecache.checkcache()
     42         self.botframe = None
     43         self._set_stopinfo(None, None)
     44 
     45     def trace_dispatch(self, frame, event, arg):
     46         if self.quitting:
     47             return # None
     48         if event == 'line':
     49             return self.dispatch_line(frame)
     50         if event == 'call':
     51             return self.dispatch_call(frame, arg)
     52         if event == 'return':
     53             return self.dispatch_return(frame, arg)
     54         if event == 'exception':
     55             return self.dispatch_exception(frame, arg)
     56         if event == 'c_call':
     57             return self.trace_dispatch
     58         if event == 'c_exception':
     59             return self.trace_dispatch
     60         if event == 'c_return':
     61             return self.trace_dispatch
     62         print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event)
     63         return self.trace_dispatch
     64 
     65     def dispatch_line(self, frame):
     66         if self.stop_here(frame) or self.break_here(frame):
     67             self.user_line(frame)
     68             if self.quitting: raise BdbQuit
     69         return self.trace_dispatch
     70 
     71     def dispatch_call(self, frame, arg):
     72         # XXX 'arg' is no longer used
     73         if self.botframe is None:
     74             # First call of dispatch since reset()
     75             self.botframe = frame.f_back # (CT) Note that this may also be None!
     76             return self.trace_dispatch
     77         if not (self.stop_here(frame) or self.break_anywhere(frame)):
     78             # No need to trace this function
     79             return # None
     80         self.user_call(frame, arg)
     81         if self.quitting: raise BdbQuit
     82         return self.trace_dispatch
     83 
     84     def dispatch_return(self, frame, arg):
     85         if self.stop_here(frame) or frame == self.returnframe:
     86             try:
     87                 self.frame_returning = frame
     88                 self.user_return(frame, arg)
     89             finally:
     90                 self.frame_returning = None
     91             if self.quitting: raise BdbQuit
     92         return self.trace_dispatch
     93 
     94     def dispatch_exception(self, frame, arg):
     95         if self.stop_here(frame):
     96             self.user_exception(frame, arg)
     97             if self.quitting: raise BdbQuit
     98         return self.trace_dispatch
     99 
    100     # Normally derived classes don't override the following
    101     # methods, but they may if they want to redefine the
    102     # definition of stopping and breakpoints.
    103 
    104     def is_skipped_module(self, module_name):
    105         for pattern in self.skip:
    106             if fnmatch.fnmatch(module_name, pattern):
    107                 return True
    108         return False
    109 
    110     def stop_here(self, frame):
    111         # (CT) stopframe may now also be None, see dispatch_call.
    112         # (CT) the former test for None is therefore removed from here.
    113         if self.skip and \
    114                self.is_skipped_module(frame.f_globals.get('__name__')):
    115             return False
    116         if frame is self.stopframe:
    117             if self.stoplineno == -1:
    118                 return False
    119             return frame.f_lineno >= self.stoplineno
    120         while frame is not None and frame is not self.stopframe:
    121             if frame is self.botframe:
    122                 return True
    123             frame = frame.f_back
    124         return False
    125 
    126     def break_here(self, frame):
    127         filename = self.canonic(frame.f_code.co_filename)
    128         if not filename in self.breaks:
    129             return False
    130         lineno = frame.f_lineno
    131         if not lineno in self.breaks[filename]:
    132             # The line itself has no breakpoint, but maybe the line is the
    133             # first line of a function with breakpoint set by function name.
    134             lineno = frame.f_code.co_firstlineno
    135             if not lineno in self.breaks[filename]:
    136                 return False
    137 
    138         # flag says ok to delete temp. bp
    139         (bp, flag) = effective(filename, lineno, frame)
    140         if bp:
    141             self.currentbp = bp.number
    142             if (flag and bp.temporary):
    143                 self.do_clear(str(bp.number))
    144             return True
    145         else:
    146             return False
    147 
    148     def do_clear(self, arg):
    149         raise NotImplementedError, "subclass of bdb must implement do_clear()"
    150 
    151     def break_anywhere(self, frame):
    152         return self.canonic(frame.f_code.co_filename) in self.breaks
    153 
    154     # Derived classes should override the user_* methods
    155     # to gain control.
    156 
    157     def user_call(self, frame, argument_list):
    158         """This method is called when there is the remote possibility
    159         that we ever need to stop in this function."""
    160         pass
    161 
    162     def user_line(self, frame):
    163         """This method is called when we stop or break at this line."""
    164         pass
    165 
    166     def user_return(self, frame, return_value):
    167         """This method is called when a return trap is set here."""
    168         pass
    169 
    170     def user_exception(self, frame, exc_info):
    171         exc_type, exc_value, exc_traceback = exc_info
    172         """This method is called if an exception occurs,
    173         but only if we are to stop at or just below this level."""
    174         pass
    175 
    176     def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
    177         self.stopframe = stopframe
    178         self.returnframe = returnframe
    179         self.quitting = 0
    180         # stoplineno >= 0 means: stop at line >= the stoplineno
    181         # stoplineno -1 means: don't stop at all
    182         self.stoplineno = stoplineno
    183 
    184     # Derived classes and clients can call the following methods
    185     # to affect the stepping state.
    186 
    187     def set_until(self, frame): #the name "until" is borrowed from gdb
    188         """Stop when the line with the line no greater than the current one is
    189         reached or when returning from current frame"""
    190         self._set_stopinfo(frame, frame, frame.f_lineno+1)
    191 
    192     def set_step(self):
    193         """Stop after one line of code."""
    194         # Issue #13183: pdb skips frames after hitting a breakpoint and running
    195         # step commands.
    196         # Restore the trace function in the caller (that may not have been set
    197         # for performance reasons) when returning from the current frame.
    198         if self.frame_returning:
    199             caller_frame = self.frame_returning.f_back
    200             if caller_frame and not caller_frame.f_trace:
    201                 caller_frame.f_trace = self.trace_dispatch
    202         self._set_stopinfo(None, None)
    203 
    204     def set_next(self, frame):
    205         """Stop on the next line in or below the given frame."""
    206         self._set_stopinfo(frame, None)
    207 
    208     def set_return(self, frame):
    209         """Stop when returning from the given frame."""
    210         self._set_stopinfo(frame.f_back, frame)
    211 
    212     def set_trace(self, frame=None):
    213         """Start debugging from `frame`.
    214 
    215         If frame is not specified, debugging starts from caller's frame.
    216         """
    217         if frame is None:
    218             frame = sys._getframe().f_back
    219         self.reset()
    220         while frame:
    221             frame.f_trace = self.trace_dispatch
    222             self.botframe = frame
    223             frame = frame.f_back
    224         self.set_step()
    225         sys.settrace(self.trace_dispatch)
    226 
    227     def set_continue(self):
    228         # Don't stop except at breakpoints or when finished
    229         self._set_stopinfo(self.botframe, None, -1)
    230         if not self.breaks:
    231             # no breakpoints; run without debugger overhead
    232             sys.settrace(None)
    233             frame = sys._getframe().f_back
    234             while frame and frame is not self.botframe:
    235                 del frame.f_trace
    236                 frame = frame.f_back
    237 
    238     def set_quit(self):
    239         self.stopframe = self.botframe
    240         self.returnframe = None
    241         self.quitting = 1
    242         sys.settrace(None)
    243 
    244     # Derived classes and clients can call the following methods
    245     # to manipulate breakpoints.  These methods return an
    246     # error message is something went wrong, None if all is well.
    247     # Set_break prints out the breakpoint line and file:lineno.
    248     # Call self.get_*break*() to see the breakpoints or better
    249     # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
    250 
    251     def set_break(self, filename, lineno, temporary=0, cond = None,
    252                   funcname=None):
    253         filename = self.canonic(filename)
    254         import linecache # Import as late as possible
    255         line = linecache.getline(filename, lineno)
    256         if not line:
    257             return 'Line %s:%d does not exist' % (filename,
    258                                    lineno)
    259         if not filename in self.breaks:
    260             self.breaks[filename] = []
    261         list = self.breaks[filename]
    262         if not lineno in list:
    263             list.append(lineno)
    264         bp = Breakpoint(filename, lineno, temporary, cond, funcname)
    265 
    266     def _prune_breaks(self, filename, lineno):
    267         if (filename, lineno) not in Breakpoint.bplist:
    268             self.breaks[filename].remove(lineno)
    269         if not self.breaks[filename]:
    270             del self.breaks[filename]
    271 
    272     def clear_break(self, filename, lineno):
    273         filename = self.canonic(filename)
    274         if not filename in self.breaks:
    275             return 'There are no breakpoints in %s' % filename
    276         if lineno not in self.breaks[filename]:
    277             return 'There is no breakpoint at %s:%d' % (filename,
    278                                     lineno)
    279         # If there's only one bp in the list for that file,line
    280         # pair, then remove the breaks entry
    281         for bp in Breakpoint.bplist[filename, lineno][:]:
    282             bp.deleteMe()
    283         self._prune_breaks(filename, lineno)
    284 
    285     def clear_bpbynumber(self, arg):
    286         try:
    287             number = int(arg)
    288         except:
    289             return 'Non-numeric breakpoint number (%s)' % arg
    290         try:
    291             bp = Breakpoint.bpbynumber[number]
    292         except IndexError:
    293             return 'Breakpoint number (%d) out of range' % number
    294         if not bp:
    295             return 'Breakpoint (%d) already deleted' % number
    296         bp.deleteMe()
    297         self._prune_breaks(bp.file, bp.line)
    298 
    299     def clear_all_file_breaks(self, filename):
    300         filename = self.canonic(filename)
    301         if not filename in self.breaks:
    302             return 'There are no breakpoints in %s' % filename
    303         for line in self.breaks[filename]:
    304             blist = Breakpoint.bplist[filename, line]
    305             for bp in blist:
    306                 bp.deleteMe()
    307         del self.breaks[filename]
    308 
    309     def clear_all_breaks(self):
    310         if not self.breaks:
    311             return 'There are no breakpoints'
    312         for bp in Breakpoint.bpbynumber:
    313             if bp:
    314                 bp.deleteMe()
    315         self.breaks = {}
    316 
    317     def get_break(self, filename, lineno):
    318         filename = self.canonic(filename)
    319         return filename in self.breaks and \
    320             lineno in self.breaks[filename]
    321 
    322     def get_breaks(self, filename, lineno):
    323         filename = self.canonic(filename)
    324         return filename in self.breaks and \
    325             lineno in self.breaks[filename] and \
    326             Breakpoint.bplist[filename, lineno] or []
    327 
    328     def get_file_breaks(self, filename):
    329         filename = self.canonic(filename)
    330         if filename in self.breaks:
    331             return self.breaks[filename]
    332         else:
    333             return []
    334 
    335     def get_all_breaks(self):
    336         return self.breaks
    337 
    338     # Derived classes and clients can call the following method
    339     # to get a data structure representing a stack trace.
    340 
    341     def get_stack(self, f, t):
    342         stack = []
    343         if t and t.tb_frame is f:
    344             t = t.tb_next
    345         while f is not None:
    346             stack.append((f, f.f_lineno))
    347             if f is self.botframe:
    348                 break
    349             f = f.f_back
    350         stack.reverse()
    351         i = max(0, len(stack) - 1)
    352         while t is not None:
    353             stack.append((t.tb_frame, t.tb_lineno))
    354             t = t.tb_next
    355         if f is None:
    356             i = max(0, len(stack) - 1)
    357         return stack, i
    358 
    359     #
    360 
    361     def format_stack_entry(self, frame_lineno, lprefix=': '):
    362         import linecache, repr
    363         frame, lineno = frame_lineno
    364         filename = self.canonic(frame.f_code.co_filename)
    365         s = '%s(%r)' % (filename, lineno)
    366         if frame.f_code.co_name:
    367             s = s + frame.f_code.co_name
    368         else:
    369             s = s + "<lambda>"
    370         if '__args__' in frame.f_locals:
    371             args = frame.f_locals['__args__']
    372         else:
    373             args = None
    374         if args:
    375             s = s + repr.repr(args)
    376         else:
    377             s = s + '()'
    378         if '__return__' in frame.f_locals:
    379             rv = frame.f_locals['__return__']
    380             s = s + '->'
    381             s = s + repr.repr(rv)
    382         line = linecache.getline(filename, lineno, frame.f_globals)
    383         if line: s = s + lprefix + line.strip()
    384         return s
    385 
    386     # The following two methods can be called by clients to use
    387     # a debugger to debug a statement, given as a string.
    388 
    389     def run(self, cmd, globals=None, locals=None):
    390         if globals is None:
    391             import __main__
    392             globals = __main__.__dict__
    393         if locals is None:
    394             locals = globals
    395         self.reset()
    396         sys.settrace(self.trace_dispatch)
    397         if not isinstance(cmd, types.CodeType):
    398             cmd = cmd+'\n'
    399         try:
    400             exec cmd in globals, locals
    401         except BdbQuit:
    402             pass
    403         finally:
    404             self.quitting = 1
    405             sys.settrace(None)
    406 
    407     def runeval(self, expr, globals=None, locals=None):
    408         if globals is None:
    409             import __main__
    410             globals = __main__.__dict__
    411         if locals is None:
    412             locals = globals
    413         self.reset()
    414         sys.settrace(self.trace_dispatch)
    415         if not isinstance(expr, types.CodeType):
    416             expr = expr+'\n'
    417         try:
    418             return eval(expr, globals, locals)
    419         except BdbQuit:
    420             pass
    421         finally:
    422             self.quitting = 1
    423             sys.settrace(None)
    424 
    425     def runctx(self, cmd, globals, locals):
    426         # B/W compatibility
    427         self.run(cmd, globals, locals)
    428 
    429     # This method is more useful to debug a single function call.
    430 
    431     def runcall(self, func, *args, **kwds):
    432         self.reset()
    433         sys.settrace(self.trace_dispatch)
    434         res = None
    435         try:
    436             res = func(*args, **kwds)
    437         except BdbQuit:
    438             pass
    439         finally:
    440             self.quitting = 1
    441             sys.settrace(None)
    442         return res
    443 
    444 
    445 def set_trace():
    446     Bdb().set_trace()
    447 
    448 
    449 class Breakpoint:
    450 
    451     """Breakpoint class
    452 
    453     Implements temporary breakpoints, ignore counts, disabling and
    454     (re)-enabling, and conditionals.
    455 
    456     Breakpoints are indexed by number through bpbynumber and by
    457     the file,line tuple using bplist.  The former points to a
    458     single instance of class Breakpoint.  The latter points to a
    459     list of such instances since there may be more than one
    460     breakpoint per line.
    461 
    462     """
    463 
    464     # XXX Keeping state in the class is a mistake -- this means
    465     # you cannot have more than one active Bdb instance.
    466 
    467     next = 1        # Next bp to be assigned
    468     bplist = {}     # indexed by (file, lineno) tuple
    469     bpbynumber = [None] # Each entry is None or an instance of Bpt
    470                 # index 0 is unused, except for marking an
    471                 # effective break .... see effective()
    472 
    473     def __init__(self, file, line, temporary=0, cond=None, funcname=None):
    474         self.funcname = funcname
    475         # Needed if funcname is not None.
    476         self.func_first_executable_line = None
    477         self.file = file    # This better be in canonical form!
    478         self.line = line
    479         self.temporary = temporary
    480         self.cond = cond
    481         self.enabled = 1
    482         self.ignore = 0
    483         self.hits = 0
    484         self.number = Breakpoint.next
    485         Breakpoint.next = Breakpoint.next + 1
    486         # Build the two lists
    487         self.bpbynumber.append(self)
    488         if (file, line) in self.bplist:
    489             self.bplist[file, line].append(self)
    490         else:
    491             self.bplist[file, line] = [self]
    492 
    493 
    494     def deleteMe(self):
    495         index = (self.file, self.line)
    496         self.bpbynumber[self.number] = None   # No longer in list
    497         self.bplist[index].remove(self)
    498         if not self.bplist[index]:
    499             # No more bp for this f:l combo
    500             del self.bplist[index]
    501 
    502     def enable(self):
    503         self.enabled = 1
    504 
    505     def disable(self):
    506         self.enabled = 0
    507 
    508     def bpprint(self, out=None):
    509         if out is None:
    510             out = sys.stdout
    511         if self.temporary:
    512             disp = 'del  '
    513         else:
    514             disp = 'keep '
    515         if self.enabled:
    516             disp = disp + 'yes  '
    517         else:
    518             disp = disp + 'no   '
    519         print >>out, '%-4dbreakpoint   %s at %s:%d' % (self.number, disp,
    520                                                        self.file, self.line)
    521         if self.cond:
    522             print >>out, '\tstop only if %s' % (self.cond,)
    523         if self.ignore:
    524             print >>out, '\tignore next %d hits' % (self.ignore)
    525         if (self.hits):
    526             if (self.hits > 1): ss = 's'
    527             else: ss = ''
    528             print >>out, ('\tbreakpoint already hit %d time%s' %
    529                           (self.hits, ss))
    530 
    531 # -----------end of Breakpoint class----------
    532 
    533 def checkfuncname(b, frame):
    534     """Check whether we should break here because of `b.funcname`."""
    535     if not b.funcname:
    536         # Breakpoint was set via line number.
    537         if b.line != frame.f_lineno:
    538             # Breakpoint was set at a line with a def statement and the function
    539             # defined is called: don't break.
    540             return False
    541         return True
    542 
    543     # Breakpoint set via function name.
    544 
    545     if frame.f_code.co_name != b.funcname:
    546         # It's not a function call, but rather execution of def statement.
    547         return False
    548 
    549     # We are in the right frame.
    550     if not b.func_first_executable_line:
    551         # The function is entered for the 1st time.
    552         b.func_first_executable_line = frame.f_lineno
    553 
    554     if  b.func_first_executable_line != frame.f_lineno:
    555         # But we are not at the first line number: don't break.
    556         return False
    557     return True
    558 
    559 # Determines if there is an effective (active) breakpoint at this
    560 # line of code.  Returns breakpoint number or 0 if none
    561 def effective(file, line, frame):
    562     """Determine which breakpoint for this file:line is to be acted upon.
    563 
    564     Called only if we know there is a bpt at this
    565     location.  Returns breakpoint that was triggered and a flag
    566     that indicates if it is ok to delete a temporary bp.
    567 
    568     """
    569     possibles = Breakpoint.bplist[file,line]
    570     for i in range(0, len(possibles)):
    571         b = possibles[i]
    572         if b.enabled == 0:
    573             continue
    574         if not checkfuncname(b, frame):
    575             continue
    576         # Count every hit when bp is enabled
    577         b.hits = b.hits + 1
    578         if not b.cond:
    579             # If unconditional, and ignoring,
    580             # go on to next, else break
    581             if b.ignore > 0:
    582                 b.ignore = b.ignore -1
    583                 continue
    584             else:
    585                 # breakpoint and marker that's ok
    586                 # to delete if temporary
    587                 return (b,1)
    588         else:
    589             # Conditional bp.
    590             # Ignore count applies only to those bpt hits where the
    591             # condition evaluates to true.
    592             try:
    593                 val = eval(b.cond, frame.f_globals,
    594                        frame.f_locals)
    595                 if val:
    596                     if b.ignore > 0:
    597                         b.ignore = b.ignore -1
    598                         # continue
    599                     else:
    600                         return (b,1)
    601                 # else:
    602                 #   continue
    603             except:
    604                 # if eval fails, most conservative
    605                 # thing is to stop on breakpoint
    606                 # regardless of ignore count.
    607                 # Don't delete temporary,
    608                 # as another hint to user.
    609                 return (b,0)
    610     return (None, None)
    611 
    612 # -------------------- testing --------------------
    613 
    614 class Tdb(Bdb):
    615     def user_call(self, frame, args):
    616         name = frame.f_code.co_name
    617         if not name: name = '???'
    618         print '+++ call', name, args
    619     def user_line(self, frame):
    620         import linecache
    621         name = frame.f_code.co_name
    622         if not name: name = '???'
    623         fn = self.canonic(frame.f_code.co_filename)
    624         line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
    625         print '+++', fn, frame.f_lineno, name, ':', line.strip()
    626     def user_return(self, frame, retval):
    627         print '+++ return', retval
    628     def user_exception(self, frame, exc_stuff):
    629         print '+++ exception', exc_stuff
    630         self.set_continue()
    631 
    632 def foo(n):
    633     print 'foo(', n, ')'
    634     x = bar(n*10)
    635     print 'bar returned', x
    636 
    637 def bar(a):
    638     print 'bar(', a, ')'
    639     return a/2
    640 
    641 def test():
    642     t = Tdb()
    643     t.run('import bdb; bdb.foo(10)')
    644 
    645 # end
    646