Breakpoints are central to the ZeroBugs debugger engine layer.
Breakpoints can be set by the user, or by the debugger for internal
purposes (such as detecting the creation of new threads). Physical vs. LogicalBreakpoints can be classified in several ways. One categorization distinguishes between "logical breakpoints" and "physical breakpoints". What this means is that not all the breakpoints that you have inserted in the program are physically there, but the debugger will support the illusion that they are; reality is the realm of physical breakpoints, and logic is derived off perception. So if you perceive a breakpoint as being inserted in the debugged process, it is logically there, even though, physically, the debuggee has not been affected. Let's consider a couple of examples, to help bring the discussion out of the philosophical realm.
The logical breakpoints are implemented as actions associated with physical breakpoints. Each physical breakpoint maintains a list of actions. An action may be temporary (or once-only), which means that it gets discarded after being executed once. Once-only actions are similar to UNIX System V signal handlers. Non-temporary actions are executed each time the physical breakpoint is hit -- similar to BSD signal handlers. Algorithm for executing breakpoint actions
Software vs. Hardware
Global vs. Per-ThreadAnother categorization of breakpoints is by the what threads they affect in a multi-threaded program. A global breakpoint causes the program to stop, regardless of what thread has hit it. Per-thread breakpoints will stop the program only when reached by a given thread. Because all threads share the same code segment, a software breakpoint is also a global breakpoint, since any thread that reaches the break opcode will stop. The operating system creates the illusion of each thread running on its own CPU, therefore a hardware breakpoint may be private to a given thread. A bit in the debug control register of the 386 chip can be used to control the global/per-task behavior of hardware breakpoints. A thread ID can be added to the data structure or class that represents a software breakpoint. When the breakpoint is hit, the thread ID in the structure may be compared against the ID of the current thread. The behavior of a per-thread breakpoint can be emulated this way. The debugger uses emulated breakpoints when it needs a hardware breapoint and none of the 4 debug registers is available. Consider the case where the debugger uses a breakpoint for quickly stepping over function calls. The debugged program must stop only if the breakpoint at the function's return address is hit by the same thread that was current when the user gave the "step over" command.
|