xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/bdb.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1"""Debugger basics"""
2
3import fnmatch
4import sys
5import os
6from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
7
8__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
9
10GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR
11
12
13class BdbQuit(Exception):
14    """Exception to give up completely."""
15
16
17class Bdb:
18    """Generic Python debugger base class.
19
20    This class takes care of details of the trace facility;
21    a derived class should implement user interaction.
22    The standard debugger class (pdb.Pdb) is an example.
23
24    The optional skip argument must be an iterable of glob-style
25    module name patterns.  The debugger will not step into frames
26    that originate in a module that matches one of these patterns.
27    Whether a frame is considered to originate in a certain module
28    is determined by the __name__ in the frame globals.
29    """
30
31    def __init__(self, skip=None):
32        self.skip = set(skip) if skip else None
33        self.breaks = {}
34        self.fncache = {}
35        self.frame_returning = None
36
37        self._load_breaks()
38
39    def canonic(self, filename):
40        """Return canonical form of filename.
41
42        For real filenames, the canonical form is a case-normalized (on
43        case insensitive filesystems) absolute path.  'Filenames' with
44        angle brackets, such as "<stdin>", generated in interactive
45        mode, are returned unchanged.
46        """
47        if filename == "<" + filename[1:-1] + ">":
48            return filename
49        canonic = self.fncache.get(filename)
50        if not canonic:
51            canonic = os.path.abspath(filename)
52            canonic = os.path.normcase(canonic)
53            self.fncache[filename] = canonic
54        return canonic
55
56    def reset(self):
57        """Set values of attributes as ready to start debugging."""
58        import linecache
59        linecache.checkcache()
60        self.botframe = None
61        self._set_stopinfo(None, None)
62
63    def trace_dispatch(self, frame, event, arg):
64        """Dispatch a trace function for debugged frames based on the event.
65
66        This function is installed as the trace function for debugged
67        frames. Its return value is the new trace function, which is
68        usually itself. The default implementation decides how to
69        dispatch a frame, depending on the type of event (passed in as a
70        string) that is about to be executed.
71
72        The event can be one of the following:
73            line: A new line of code is going to be executed.
74            call: A function is about to be called or another code block
75                  is entered.
76            return: A function or other code block is about to return.
77            exception: An exception has occurred.
78            c_call: A C function is about to be called.
79            c_return: A C function has returned.
80            c_exception: A C function has raised an exception.
81
82        For the Python events, specialized functions (see the dispatch_*()
83        methods) are called.  For the C events, no action is taken.
84
85        The arg parameter depends on the previous event.
86        """
87        if self.quitting:
88            return # None
89        if event == 'line':
90            return self.dispatch_line(frame)
91        if event == 'call':
92            return self.dispatch_call(frame, arg)
93        if event == 'return':
94            return self.dispatch_return(frame, arg)
95        if event == 'exception':
96            return self.dispatch_exception(frame, arg)
97        if event == 'c_call':
98            return self.trace_dispatch
99        if event == 'c_exception':
100            return self.trace_dispatch
101        if event == 'c_return':
102            return self.trace_dispatch
103        print('bdb.Bdb.dispatch: unknown debugging event:', repr(event))
104        return self.trace_dispatch
105
106    def dispatch_line(self, frame):
107        """Invoke user function and return trace function for line event.
108
109        If the debugger stops on the current line, invoke
110        self.user_line(). Raise BdbQuit if self.quitting is set.
111        Return self.trace_dispatch to continue tracing in this scope.
112        """
113        if self.stop_here(frame) or self.break_here(frame):
114            self.user_line(frame)
115            if self.quitting: raise BdbQuit
116        return self.trace_dispatch
117
118    def dispatch_call(self, frame, arg):
119        """Invoke user function and return trace function for call event.
120
121        If the debugger stops on this function call, invoke
122        self.user_call(). Raise BdbQuit if self.quitting is set.
123        Return self.trace_dispatch to continue tracing in this scope.
124        """
125        # XXX 'arg' is no longer used
126        if self.botframe is None:
127            # First call of dispatch since reset()
128            self.botframe = frame.f_back # (CT) Note that this may also be None!
129            return self.trace_dispatch
130        if not (self.stop_here(frame) or self.break_anywhere(frame)):
131            # No need to trace this function
132            return # None
133        # Ignore call events in generator except when stepping.
134        if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
135            return self.trace_dispatch
136        self.user_call(frame, arg)
137        if self.quitting: raise BdbQuit
138        return self.trace_dispatch
139
140    def dispatch_return(self, frame, arg):
141        """Invoke user function and return trace function for return event.
142
143        If the debugger stops on this function return, invoke
144        self.user_return(). Raise BdbQuit if self.quitting is set.
145        Return self.trace_dispatch to continue tracing in this scope.
146        """
147        if self.stop_here(frame) or frame == self.returnframe:
148            # Ignore return events in generator except when stepping.
149            if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
150                return self.trace_dispatch
151            try:
152                self.frame_returning = frame
153                self.user_return(frame, arg)
154            finally:
155                self.frame_returning = None
156            if self.quitting: raise BdbQuit
157            # The user issued a 'next' or 'until' command.
158            if self.stopframe is frame and self.stoplineno != -1:
159                self._set_stopinfo(None, None)
160        return self.trace_dispatch
161
162    def dispatch_exception(self, frame, arg):
163        """Invoke user function and return trace function for exception event.
164
165        If the debugger stops on this exception, invoke
166        self.user_exception(). Raise BdbQuit if self.quitting is set.
167        Return self.trace_dispatch to continue tracing in this scope.
168        """
169        if self.stop_here(frame):
170            # When stepping with next/until/return in a generator frame, skip
171            # the internal StopIteration exception (with no traceback)
172            # triggered by a subiterator run with the 'yield from' statement.
173            if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
174                    and arg[0] is StopIteration and arg[2] is None):
175                self.user_exception(frame, arg)
176                if self.quitting: raise BdbQuit
177        # Stop at the StopIteration or GeneratorExit exception when the user
178        # has set stopframe in a generator by issuing a return command, or a
179        # next/until command at the last statement in the generator before the
180        # exception.
181        elif (self.stopframe and frame is not self.stopframe
182                and self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
183                and arg[0] in (StopIteration, GeneratorExit)):
184            self.user_exception(frame, arg)
185            if self.quitting: raise BdbQuit
186
187        return self.trace_dispatch
188
189    # Normally derived classes don't override the following
190    # methods, but they may if they want to redefine the
191    # definition of stopping and breakpoints.
192
193    def is_skipped_module(self, module_name):
194        "Return True if module_name matches any skip pattern."
195        if module_name is None:  # some modules do not have names
196            return False
197        for pattern in self.skip:
198            if fnmatch.fnmatch(module_name, pattern):
199                return True
200        return False
201
202    def stop_here(self, frame):
203        "Return True if frame is below the starting frame in the stack."
204        # (CT) stopframe may now also be None, see dispatch_call.
205        # (CT) the former test for None is therefore removed from here.
206        if self.skip and \
207               self.is_skipped_module(frame.f_globals.get('__name__')):
208            return False
209        if frame is self.stopframe:
210            if self.stoplineno == -1:
211                return False
212            return frame.f_lineno >= self.stoplineno
213        if not self.stopframe:
214            return True
215        return False
216
217    def break_here(self, frame):
218        """Return True if there is an effective breakpoint for this line.
219
220        Check for line or function breakpoint and if in effect.
221        Delete temporary breakpoints if effective() says to.
222        """
223        filename = self.canonic(frame.f_code.co_filename)
224        if filename not in self.breaks:
225            return False
226        lineno = frame.f_lineno
227        if lineno not in self.breaks[filename]:
228            # The line itself has no breakpoint, but maybe the line is the
229            # first line of a function with breakpoint set by function name.
230            lineno = frame.f_code.co_firstlineno
231            if lineno not in self.breaks[filename]:
232                return False
233
234        # flag says ok to delete temp. bp
235        (bp, flag) = effective(filename, lineno, frame)
236        if bp:
237            self.currentbp = bp.number
238            if (flag and bp.temporary):
239                self.do_clear(str(bp.number))
240            return True
241        else:
242            return False
243
244    def do_clear(self, arg):
245        """Remove temporary breakpoint.
246
247        Must implement in derived classes or get NotImplementedError.
248        """
249        raise NotImplementedError("subclass of bdb must implement do_clear()")
250
251    def break_anywhere(self, frame):
252        """Return True if there is any breakpoint for frame's filename.
253        """
254        return self.canonic(frame.f_code.co_filename) in self.breaks
255
256    # Derived classes should override the user_* methods
257    # to gain control.
258
259    def user_call(self, frame, argument_list):
260        """Called if we might stop in a function."""
261        pass
262
263    def user_line(self, frame):
264        """Called when we stop or break at a line."""
265        pass
266
267    def user_return(self, frame, return_value):
268        """Called when a return trap is set here."""
269        pass
270
271    def user_exception(self, frame, exc_info):
272        """Called when we stop on an exception."""
273        pass
274
275    def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
276        """Set the attributes for stopping.
277
278        If stoplineno is greater than or equal to 0, then stop at line
279        greater than or equal to the stopline.  If stoplineno is -1, then
280        don't stop at all.
281        """
282        self.stopframe = stopframe
283        self.returnframe = returnframe
284        self.quitting = False
285        # stoplineno >= 0 means: stop at line >= the stoplineno
286        # stoplineno -1 means: don't stop at all
287        self.stoplineno = stoplineno
288
289    # Derived classes and clients can call the following methods
290    # to affect the stepping state.
291
292    def set_until(self, frame, lineno=None):
293        """Stop when the line with the lineno greater than the current one is
294        reached or when returning from current frame."""
295        # the name "until" is borrowed from gdb
296        if lineno is None:
297            lineno = frame.f_lineno + 1
298        self._set_stopinfo(frame, frame, lineno)
299
300    def set_step(self):
301        """Stop after one line of code."""
302        # Issue #13183: pdb skips frames after hitting a breakpoint and running
303        # step commands.
304        # Restore the trace function in the caller (that may not have been set
305        # for performance reasons) when returning from the current frame.
306        if self.frame_returning:
307            caller_frame = self.frame_returning.f_back
308            if caller_frame and not caller_frame.f_trace:
309                caller_frame.f_trace = self.trace_dispatch
310        self._set_stopinfo(None, None)
311
312    def set_next(self, frame):
313        """Stop on the next line in or below the given frame."""
314        self._set_stopinfo(frame, None)
315
316    def set_return(self, frame):
317        """Stop when returning from the given frame."""
318        if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
319            self._set_stopinfo(frame, None, -1)
320        else:
321            self._set_stopinfo(frame.f_back, frame)
322
323    def set_trace(self, frame=None):
324        """Start debugging from frame.
325
326        If frame is not specified, debugging starts from caller's frame.
327        """
328        if frame is None:
329            frame = sys._getframe().f_back
330        self.reset()
331        while frame:
332            frame.f_trace = self.trace_dispatch
333            self.botframe = frame
334            frame = frame.f_back
335        self.set_step()
336        sys.settrace(self.trace_dispatch)
337
338    def set_continue(self):
339        """Stop only at breakpoints or when finished.
340
341        If there are no breakpoints, set the system trace function to None.
342        """
343        # Don't stop except at breakpoints or when finished
344        self._set_stopinfo(self.botframe, None, -1)
345        if not self.breaks:
346            # no breakpoints; run without debugger overhead
347            sys.settrace(None)
348            frame = sys._getframe().f_back
349            while frame and frame is not self.botframe:
350                del frame.f_trace
351                frame = frame.f_back
352
353    def set_quit(self):
354        """Set quitting attribute to True.
355
356        Raises BdbQuit exception in the next call to a dispatch_*() method.
357        """
358        self.stopframe = self.botframe
359        self.returnframe = None
360        self.quitting = True
361        sys.settrace(None)
362
363    # Derived classes and clients can call the following methods
364    # to manipulate breakpoints.  These methods return an
365    # error message if something went wrong, None if all is well.
366    # Set_break prints out the breakpoint line and file:lineno.
367    # Call self.get_*break*() to see the breakpoints or better
368    # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
369
370    def _add_to_breaks(self, filename, lineno):
371        """Add breakpoint to breaks, if not already there."""
372        bp_linenos = self.breaks.setdefault(filename, [])
373        if lineno not in bp_linenos:
374            bp_linenos.append(lineno)
375
376    def set_break(self, filename, lineno, temporary=False, cond=None,
377                  funcname=None):
378        """Set a new breakpoint for filename:lineno.
379
380        If lineno doesn't exist for the filename, return an error message.
381        The filename should be in canonical form.
382        """
383        filename = self.canonic(filename)
384        import linecache # Import as late as possible
385        line = linecache.getline(filename, lineno)
386        if not line:
387            return 'Line %s:%d does not exist' % (filename, lineno)
388        self._add_to_breaks(filename, lineno)
389        bp = Breakpoint(filename, lineno, temporary, cond, funcname)
390        return None
391
392    def _load_breaks(self):
393        """Apply all breakpoints (set in other instances) to this one.
394
395        Populates this instance's breaks list from the Breakpoint class's
396        list, which can have breakpoints set by another Bdb instance. This
397        is necessary for interactive sessions to keep the breakpoints
398        active across multiple calls to run().
399        """
400        for (filename, lineno) in Breakpoint.bplist.keys():
401            self._add_to_breaks(filename, lineno)
402
403    def _prune_breaks(self, filename, lineno):
404        """Prune breakpoints for filename:lineno.
405
406        A list of breakpoints is maintained in the Bdb instance and in
407        the Breakpoint class.  If a breakpoint in the Bdb instance no
408        longer exists in the Breakpoint class, then it's removed from the
409        Bdb instance.
410        """
411        if (filename, lineno) not in Breakpoint.bplist:
412            self.breaks[filename].remove(lineno)
413        if not self.breaks[filename]:
414            del self.breaks[filename]
415
416    def clear_break(self, filename, lineno):
417        """Delete breakpoints for filename:lineno.
418
419        If no breakpoints were set, return an error message.
420        """
421        filename = self.canonic(filename)
422        if filename not in self.breaks:
423            return 'There are no breakpoints in %s' % filename
424        if lineno not in self.breaks[filename]:
425            return 'There is no breakpoint at %s:%d' % (filename, lineno)
426        # If there's only one bp in the list for that file,line
427        # pair, then remove the breaks entry
428        for bp in Breakpoint.bplist[filename, lineno][:]:
429            bp.deleteMe()
430        self._prune_breaks(filename, lineno)
431        return None
432
433    def clear_bpbynumber(self, arg):
434        """Delete a breakpoint by its index in Breakpoint.bpbynumber.
435
436        If arg is invalid, return an error message.
437        """
438        try:
439            bp = self.get_bpbynumber(arg)
440        except ValueError as err:
441            return str(err)
442        bp.deleteMe()
443        self._prune_breaks(bp.file, bp.line)
444        return None
445
446    def clear_all_file_breaks(self, filename):
447        """Delete all breakpoints in filename.
448
449        If none were set, return an error message.
450        """
451        filename = self.canonic(filename)
452        if filename not in self.breaks:
453            return 'There are no breakpoints in %s' % filename
454        for line in self.breaks[filename]:
455            blist = Breakpoint.bplist[filename, line]
456            for bp in blist:
457                bp.deleteMe()
458        del self.breaks[filename]
459        return None
460
461    def clear_all_breaks(self):
462        """Delete all existing breakpoints.
463
464        If none were set, return an error message.
465        """
466        if not self.breaks:
467            return 'There are no breakpoints'
468        for bp in Breakpoint.bpbynumber:
469            if bp:
470                bp.deleteMe()
471        self.breaks = {}
472        return None
473
474    def get_bpbynumber(self, arg):
475        """Return a breakpoint by its index in Breakpoint.bybpnumber.
476
477        For invalid arg values or if the breakpoint doesn't exist,
478        raise a ValueError.
479        """
480        if not arg:
481            raise ValueError('Breakpoint number expected')
482        try:
483            number = int(arg)
484        except ValueError:
485            raise ValueError('Non-numeric breakpoint number %s' % arg) from None
486        try:
487            bp = Breakpoint.bpbynumber[number]
488        except IndexError:
489            raise ValueError('Breakpoint number %d out of range' % number) from None
490        if bp is None:
491            raise ValueError('Breakpoint %d already deleted' % number)
492        return bp
493
494    def get_break(self, filename, lineno):
495        """Return True if there is a breakpoint for filename:lineno."""
496        filename = self.canonic(filename)
497        return filename in self.breaks and \
498            lineno in self.breaks[filename]
499
500    def get_breaks(self, filename, lineno):
501        """Return all breakpoints for filename:lineno.
502
503        If no breakpoints are set, return an empty list.
504        """
505        filename = self.canonic(filename)
506        return filename in self.breaks and \
507            lineno in self.breaks[filename] and \
508            Breakpoint.bplist[filename, lineno] or []
509
510    def get_file_breaks(self, filename):
511        """Return all lines with breakpoints for filename.
512
513        If no breakpoints are set, return an empty list.
514        """
515        filename = self.canonic(filename)
516        if filename in self.breaks:
517            return self.breaks[filename]
518        else:
519            return []
520
521    def get_all_breaks(self):
522        """Return all breakpoints that are set."""
523        return self.breaks
524
525    # Derived classes and clients can call the following method
526    # to get a data structure representing a stack trace.
527
528    def get_stack(self, f, t):
529        """Return a list of (frame, lineno) in a stack trace and a size.
530
531        List starts with original calling frame, if there is one.
532        Size may be number of frames above or below f.
533        """
534        stack = []
535        if t and t.tb_frame is f:
536            t = t.tb_next
537        while f is not None:
538            stack.append((f, f.f_lineno))
539            if f is self.botframe:
540                break
541            f = f.f_back
542        stack.reverse()
543        i = max(0, len(stack) - 1)
544        while t is not None:
545            stack.append((t.tb_frame, t.tb_lineno))
546            t = t.tb_next
547        if f is None:
548            i = max(0, len(stack) - 1)
549        return stack, i
550
551    def format_stack_entry(self, frame_lineno, lprefix=': '):
552        """Return a string with information about a stack entry.
553
554        The stack entry frame_lineno is a (frame, lineno) tuple.  The
555        return string contains the canonical filename, the function name
556        or '<lambda>', the input arguments, the return value, and the
557        line of code (if it exists).
558
559        """
560        import linecache, reprlib
561        frame, lineno = frame_lineno
562        filename = self.canonic(frame.f_code.co_filename)
563        s = '%s(%r)' % (filename, lineno)
564        if frame.f_code.co_name:
565            s += frame.f_code.co_name
566        else:
567            s += "<lambda>"
568        s += '()'
569        if '__return__' in frame.f_locals:
570            rv = frame.f_locals['__return__']
571            s += '->'
572            s += reprlib.repr(rv)
573        if lineno is not None:
574            line = linecache.getline(filename, lineno, frame.f_globals)
575            if line:
576                s += lprefix + line.strip()
577        else:
578            s += f'{lprefix}Warning: lineno is None'
579        return s
580
581    # The following methods can be called by clients to use
582    # a debugger to debug a statement or an expression.
583    # Both can be given as a string, or a code object.
584
585    def run(self, cmd, globals=None, locals=None):
586        """Debug a statement executed via the exec() function.
587
588        globals defaults to __main__.dict; locals defaults to globals.
589        """
590        if globals is None:
591            import __main__
592            globals = __main__.__dict__
593        if locals is None:
594            locals = globals
595        self.reset()
596        if isinstance(cmd, str):
597            cmd = compile(cmd, "<string>", "exec")
598        sys.settrace(self.trace_dispatch)
599        try:
600            exec(cmd, globals, locals)
601        except BdbQuit:
602            pass
603        finally:
604            self.quitting = True
605            sys.settrace(None)
606
607    def runeval(self, expr, globals=None, locals=None):
608        """Debug an expression executed via the eval() function.
609
610        globals defaults to __main__.dict; locals defaults to globals.
611        """
612        if globals is None:
613            import __main__
614            globals = __main__.__dict__
615        if locals is None:
616            locals = globals
617        self.reset()
618        sys.settrace(self.trace_dispatch)
619        try:
620            return eval(expr, globals, locals)
621        except BdbQuit:
622            pass
623        finally:
624            self.quitting = True
625            sys.settrace(None)
626
627    def runctx(self, cmd, globals, locals):
628        """For backwards-compatibility.  Defers to run()."""
629        # B/W compatibility
630        self.run(cmd, globals, locals)
631
632    # This method is more useful to debug a single function call.
633
634    def runcall(self, func, /, *args, **kwds):
635        """Debug a single function call.
636
637        Return the result of the function call.
638        """
639        self.reset()
640        sys.settrace(self.trace_dispatch)
641        res = None
642        try:
643            res = func(*args, **kwds)
644        except BdbQuit:
645            pass
646        finally:
647            self.quitting = True
648            sys.settrace(None)
649        return res
650
651
652def set_trace():
653    """Start debugging with a Bdb instance from the caller's frame."""
654    Bdb().set_trace()
655
656
657class Breakpoint:
658    """Breakpoint class.
659
660    Implements temporary breakpoints, ignore counts, disabling and
661    (re)-enabling, and conditionals.
662
663    Breakpoints are indexed by number through bpbynumber and by
664    the (file, line) tuple using bplist.  The former points to a
665    single instance of class Breakpoint.  The latter points to a
666    list of such instances since there may be more than one
667    breakpoint per line.
668
669    When creating a breakpoint, its associated filename should be
670    in canonical form.  If funcname is defined, a breakpoint hit will be
671    counted when the first line of that function is executed.  A
672    conditional breakpoint always counts a hit.
673    """
674
675    # XXX Keeping state in the class is a mistake -- this means
676    # you cannot have more than one active Bdb instance.
677
678    next = 1        # Next bp to be assigned
679    bplist = {}     # indexed by (file, lineno) tuple
680    bpbynumber = [None] # Each entry is None or an instance of Bpt
681                # index 0 is unused, except for marking an
682                # effective break .... see effective()
683
684    def __init__(self, file, line, temporary=False, cond=None, funcname=None):
685        self.funcname = funcname
686        # Needed if funcname is not None.
687        self.func_first_executable_line = None
688        self.file = file    # This better be in canonical form!
689        self.line = line
690        self.temporary = temporary
691        self.cond = cond
692        self.enabled = True
693        self.ignore = 0
694        self.hits = 0
695        self.number = Breakpoint.next
696        Breakpoint.next += 1
697        # Build the two lists
698        self.bpbynumber.append(self)
699        if (file, line) in self.bplist:
700            self.bplist[file, line].append(self)
701        else:
702            self.bplist[file, line] = [self]
703
704    @staticmethod
705    def clearBreakpoints():
706        Breakpoint.next = 1
707        Breakpoint.bplist = {}
708        Breakpoint.bpbynumber = [None]
709
710    def deleteMe(self):
711        """Delete the breakpoint from the list associated to a file:line.
712
713        If it is the last breakpoint in that position, it also deletes
714        the entry for the file:line.
715        """
716
717        index = (self.file, self.line)
718        self.bpbynumber[self.number] = None   # No longer in list
719        self.bplist[index].remove(self)
720        if not self.bplist[index]:
721            # No more bp for this f:l combo
722            del self.bplist[index]
723
724    def enable(self):
725        """Mark the breakpoint as enabled."""
726        self.enabled = True
727
728    def disable(self):
729        """Mark the breakpoint as disabled."""
730        self.enabled = False
731
732    def bpprint(self, out=None):
733        """Print the output of bpformat().
734
735        The optional out argument directs where the output is sent
736        and defaults to standard output.
737        """
738        if out is None:
739            out = sys.stdout
740        print(self.bpformat(), file=out)
741
742    def bpformat(self):
743        """Return a string with information about the breakpoint.
744
745        The information includes the breakpoint number, temporary
746        status, file:line position, break condition, number of times to
747        ignore, and number of times hit.
748
749        """
750        if self.temporary:
751            disp = 'del  '
752        else:
753            disp = 'keep '
754        if self.enabled:
755            disp = disp + 'yes  '
756        else:
757            disp = disp + 'no   '
758        ret = '%-4dbreakpoint   %s at %s:%d' % (self.number, disp,
759                                                self.file, self.line)
760        if self.cond:
761            ret += '\n\tstop only if %s' % (self.cond,)
762        if self.ignore:
763            ret += '\n\tignore next %d hits' % (self.ignore,)
764        if self.hits:
765            if self.hits > 1:
766                ss = 's'
767            else:
768                ss = ''
769            ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)
770        return ret
771
772    def __str__(self):
773        "Return a condensed description of the breakpoint."
774        return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)
775
776# -----------end of Breakpoint class----------
777
778
779def checkfuncname(b, frame):
780    """Return True if break should happen here.
781
782    Whether a break should happen depends on the way that b (the breakpoint)
783    was set.  If it was set via line number, check if b.line is the same as
784    the one in the frame.  If it was set via function name, check if this is
785    the right function and if it is on the first executable line.
786    """
787    if not b.funcname:
788        # Breakpoint was set via line number.
789        if b.line != frame.f_lineno:
790            # Breakpoint was set at a line with a def statement and the function
791            # defined is called: don't break.
792            return False
793        return True
794
795    # Breakpoint set via function name.
796    if frame.f_code.co_name != b.funcname:
797        # It's not a function call, but rather execution of def statement.
798        return False
799
800    # We are in the right frame.
801    if not b.func_first_executable_line:
802        # The function is entered for the 1st time.
803        b.func_first_executable_line = frame.f_lineno
804
805    if b.func_first_executable_line != frame.f_lineno:
806        # But we are not at the first line number: don't break.
807        return False
808    return True
809
810
811def effective(file, line, frame):
812    """Return (active breakpoint, delete temporary flag) or (None, None) as
813       breakpoint to act upon.
814
815       The "active breakpoint" is the first entry in bplist[line, file] (which
816       must exist) that is enabled, for which checkfuncname is True, and that
817       has neither a False condition nor a positive ignore count.  The flag,
818       meaning that a temporary breakpoint should be deleted, is False only
819       when the condiion cannot be evaluated (in which case, ignore count is
820       ignored).
821
822       If no such entry exists, then (None, None) is returned.
823    """
824    possibles = Breakpoint.bplist[file, line]
825    for b in possibles:
826        if not b.enabled:
827            continue
828        if not checkfuncname(b, frame):
829            continue
830        # Count every hit when bp is enabled
831        b.hits += 1
832        if not b.cond:
833            # If unconditional, and ignoring go on to next, else break
834            if b.ignore > 0:
835                b.ignore -= 1
836                continue
837            else:
838                # breakpoint and marker that it's ok to delete if temporary
839                return (b, True)
840        else:
841            # Conditional bp.
842            # Ignore count applies only to those bpt hits where the
843            # condition evaluates to true.
844            try:
845                val = eval(b.cond, frame.f_globals, frame.f_locals)
846                if val:
847                    if b.ignore > 0:
848                        b.ignore -= 1
849                        # continue
850                    else:
851                        return (b, True)
852                # else:
853                #   continue
854            except:
855                # if eval fails, most conservative thing is to stop on
856                # breakpoint regardless of ignore count.  Don't delete
857                # temporary, as another hint to user.
858                return (b, False)
859    return (None, None)
860
861
862# -------------------- testing --------------------
863
864class Tdb(Bdb):
865    def user_call(self, frame, args):
866        name = frame.f_code.co_name
867        if not name: name = '???'
868        print('+++ call', name, args)
869    def user_line(self, frame):
870        import linecache
871        name = frame.f_code.co_name
872        if not name: name = '???'
873        fn = self.canonic(frame.f_code.co_filename)
874        line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
875        print('+++', fn, frame.f_lineno, name, ':', line.strip())
876    def user_return(self, frame, retval):
877        print('+++ return', retval)
878    def user_exception(self, frame, exc_stuff):
879        print('+++ exception', exc_stuff)
880        self.set_continue()
881
882def foo(n):
883    print('foo(', n, ')')
884    x = bar(n*10)
885    print('bar returned', x)
886
887def bar(a):
888    print('bar(', a, ')')
889    return a/2
890
891def test():
892    t = Tdb()
893    t.run('import bdb; bdb.foo(10)')
894