home *** CD-ROM | disk | FTP | other *** search
- You know my methods. Apply them.
- Sir Arthur Conan Doyle
-
- Using Breakpoints
-
- Introduction
- Types of Breakpoints Supported by SoftICE
- Breakpoint Options
- Execution Breakpoints
- Memory Breakpoints
- Interrupt Breakpoints
- I/O Breakpoints
- Window Message Breakpoints
- Understanding Breakpoint Contexts
- Virtual Breakpoints
- Setting a Breakpoint Action
- Conditional Breakpoints
- Conditional Breakpoint Count Functions
- Using Local Variables in Conditional Expressions
- Referencing the Stack in Conditional Breakpoints
- Performance
- Duplicate Breakpoints
- Elapsed Time
- Breakpoint Statistics
- Referring to Breakpoints in Expressions
- Manipulating Breakpoints
- Using Embedded Breakpoints
-
- Introduction
-
- You can use SoftICE to set breakpoints on program execution, memory
- location reads and writes, interrupts, and reads and writes to I/O
- ports. SoftICE assigns a breakpoint index, from 0 to FF, to each
- breakpoint. You can use this breakpoint index to identify breakpoints
- when you set, delete, disable, enable, or edit them.
-
- All SoftICE breakpoints are sticky, which means that SoftICE tracks
- and maintains a breakpoint until you intentionally clear or disable it
- using the BC or the BD command. After you clear breakpoints, you can
- recall them with the BH command, which displays a breakpoint history.
-
- You can set up to 256 breakpoints at one time in SoftICE. However, the
- number of breakpoints you can set on memory location (BPMs) and I/O
- ports (BPIOs) is a total of four, due to restrictions of the x86
- processors.
-
- Where symbol information is available, you can set breakpoints using
- function names. When in source or mixed mode, you can set
- point-and-shoot style breakpoints on any source code line. A valuable
- feature is that you can set point-and-shoot breakpoints in a module
- before it is even loaded.
-
- Types of Breakpoints Supported by SoftICE
-
- SoftICE provides a powerful array of breakpoint capabilities that take
- full advantage of the x86 architecture, as follows :
-
- * Execution Breakpoints: SoftICE replaces an existing instruction with
- INT 3. You can use the BPX command to set execution breakpoints.
-
- * Memory Breakpoints: SoftICE uses the x86 debug registers to break when
- a certain byte/word/dword of memory is read, written, or executed. You
- can use the BPM command to set memory breakpoints.
-
- * Interrupt Breakpoints: SoftICE intercepts interrupts by modifying the
- IDT (Interrupt Descriptor Table) vectors. You can use the BPINT
- command to set interrupt breakpoints.
-
- * I/O Breakpoints: SoftICE uses a debug register extension available on
- Pentium and Pentium-Pro CPUs to watch for an IN or OUT instruction
- going to a particular port address. You can use the BPIO command to
- set I/O breakpoints.
-
- * Window Message Breakpoints: SoftICE traps when a particular message or
- range of messages arrives at a window. This is not a fundamental
- breakpoint type; it is just a convenient feature built on top of the
- other breakpoint primitives. You can use the BMSG command to set
- window message breakpoints.
-
- Breakpoint Options
-
- You can qualify each type of breakpoint with the following two
- options:
-
- * A conditional expression [IF expression]: The expression must evaluate
- to non-zero (TRUE) for the breakpoint to trigger. Refer to Conditional
- Breakpoints.
-
- * A breakpoint action [DO "command1;command2;"]: A series of SoftICE
- commands can automatically execute when the breakpoint triggers. You
- can use this feature in concert with user-defined macros to automate
- tasks that would otherwise be tedious. Refer to Setting a Breakpoint
- Action on page 114.
-
- Note: For complete information on each breakpoint command, refer to
- the SoftICE Command Reference.
-
- Execution Breakpoints
-
- An execution breakpoint traps executing code such as a function call
- or language statement. This is the most frequently used type of
- breakpoint. By replacing an existing instruction with an INT 3
- instruction, SoftICE takes control when execution reaches the INT 3
- breakpoint.
-
- SoftICE provides two ways for setting execution breakpoints: using a
- mouse and using the BPX command. The following sections describe how
- to use these methods for setting breakpoints.
-
- Using a Mouse to Set Breakpoints
-
- If you are using a Pentium processor and a mouse, you can use the
- mouse to set or clear point-and-shoot (sticky) and one-shot
- breakpoints. To set a sticky breakpoint, double-click the line on
- which you want to set the breakpoint. SoftICE highlights the line to
- indicate that you set a breakpoint. Double-click the line again to
- clear the breakpoint. To set a one-shot breakpoint, click the line on
- which you want to set the breakpoint and use the HERE command (F7) to
- execute to that line.
-
- Using the BPX Command to Set Breakpoints
-
- Use the BPX command with any of the following parameters to set an
- execution breakpoint:
-
- BPX [address] [IF expression] [DO "command1;command2;"]
-
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- Example:
-
- To set a breakpoint on your application's WinMain function, use
- this command:
-
- BPX WinMain
-
- Use the BPX command without specifying any parameter to set a
- point-and-shoot execution breakpoint in the source code. Use Alt-C to
- move the cursor into the Code window. Then use the arrow keys to
- position the cursor on the line on which you want to set the
- breakpoint. Finally, use the BPX command (F9). If you prefer to use
- your mouse to set the breakpoint, click the scroll arrows to scroll
- the Code window, then double-click the line on which you want to set
- the breakpoint.
-
- Memory Breakpoints
-
- A memory breakpoint uses the debug registers found on the 386 CPUs and
- later models to monitor access to a certain memory location. This type
- of breakpoint is extremely useful for finding out when and where a
- program variable is modified, and for setting an execution breakpoint
- in read-only memory. You can only set four memory breakpoints at one
- time, because the CPU contains only four debug registers.
-
- Use the BPM command to set memory breakpoints:
-
- BPM[B|W|D] address [R|W|RW|X] [ debug register] [IF expression]
- [DO "command1;command2;"]
-
- BPM and BPMB:
- Set a byte-size breakpoint.
- BPMW:
- Sets a word (2-byte) size breakpoint.
- BPMD:
- Sets a dword (4-byte) size breakpoint.
- R, W, and RW:
- Break on reads, writes, or both.
- X:
- Breaks on execution; this is more powerful than a BPX-style
- breakpoint because memory does not need to be modified, enabling
- such options as setting breakpoints in ROM or setting breakpoints
- on addresses that are not present.
- debug register:
- Specifies which debug register to use. SoftICE normally manages
- the debug register for you, unless you need to specify it in an
- unusual situation.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- Example:
-
- The following example sets a memory breakpoint to trigger when a
- value of 5 is written to the Dword (4-byte) variable
- MyGlobalVariable.
-
- BPMD MyGlobalVariable W IF MyGlobalVariable==5
-
- If the target location of a BPM breakpoint is frequently accessed,
- performance can be degraded regardless of whether the conditional
- expression evaluates to FALSE.
-
- Interrupt Breakpoints
-
- Use an interrupt breakpoint to trap an interrupt through the IDT. The
- breakpoint only triggers when a specified interrupt is dispatched
- through the IDT.
-
- Use the BPINT command to set interrupt breakpoints:
-
- BPINT interrupt-number [IF expression] [DO "command1;command2;"]
-
- interrupt-number:
- Number ranging from 0 to 255 (0 to FF hex).
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- If an interrupt is caused by a software INT instruction, the
- instruction displayed will be the INT instruction. (SoftICE pops up
- when execution reaches the INT instruction responsible for the
- breakpoint, but before the instruction actually executes.) Otherwise,
- the current instruction will be the first instruction of an interrupt
- handler. You can list all interrupts and their handlers by using the
- IDT command.
-
- Example:
-
- Use the following command to set a breakpoint to trigger when a
- call to the kernel-mode routine NtCreateProcess is made from user
- mode:
-
- BPINT 2E IF EAX==1E
-
- Note: The NtCreateProcess is normally called from ZwCreateProcess
- in the NTDLL.DLL, which is in turn called from CreateProcessW in
- the KERNEL32.DLL. In the conditional expression, 1E is the
- service number for NtCreateProcess. Use the NTCALL command to
- find this value.
-
- You can use the BPINT command to trap software interrupts, for
- example, INT 21 made by 16-bit Windows programs. Note that software
- interrupts issued from V86 mode do not pass through the IDT vector
- that they specify. INT instructions executed in V86 generate processor
- general protection faults (GPF), which are handled by vector 0xD in
- the IDT. The Windows GPF handler realizes the cause of the fault and
- passes control to a handler dedicated to specific V86 interrupt types.
- The types may end up reflecting the interrupt down to V86 mode by
- calling the interrupt handler entered in the V86 mode Interrupt Vector
- Table (IVT). In some cases, a real-mode interrupt is reflected
- (simulated) by calling the real-mode interrupt vector.
-
- In the case where the interrupt is reflected, you can trap it by
- placing a BPX breakpoint at the beginning of the real-mode interrupt
- handler.
-
- Example:
-
- To set a breakpoint on the real-mode INT 21 handler, use the
- following command:
-
- BPX *($0:(21*4))
-
- I/O Breakpoints
-
- An I/O breakpoint monitors reads and writes to a port address. The
- breakpoint traps when an IN or OUT instruction accesses the port.
- SoftICE implements I/O breakpoints by using the debug register
- extensions introduced with the Pentium. As a result, I/O breakpoints
- require a Pentium or Pentium-Pro CPU. A maximum of four I/O
- breakpoints can be set at one time. The I/O breakpoint is effective in
- kernel-level (ring 0) code as well as user (ring 3) code.
-
- Notes: Under Windows 95, SoftICE relies on the I/O permission bitmap,
- which restricts I/O trapping to ring 3 code.
-
- Notes: You cannot use I/O breakpoints to trap IN/OUT instructions
- executed by MS-DOS programs. The IN/OUT instructions are trapped and
- emulated by the operating system, and therefore do not generate real
- port I/O, at least not in a 1:1 mapping.
-
- Use the BPIO command to set I/O breakpoints:
-
- BPIO port-number [R|W|RW] [IF expression]
- [DO "command1;command2;"]
-
- R, W, and RW :
- Break on reads (IN instructions), writes (OUT instructions), or
- both, respectively.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- When an I/O breakpoint triggers and SoftICE pops up, the current
- instruction is the instruction following the IN or OUT that caused the
- breakpoint to trigger. Unlike BPM breakpoints, there is no size
- specification; any access to the port-number, whether byte, word, or
- dword, triggers the breakpoint. Any I/O that spans the I/O breakpoint
- will also trigger the breakpoint. For example, if you set an I/O
- breakpoint on port 2FF, a word I/O to port 2FE would trigger the
- breakpoint.
-
- Example:
-
- Use the following command to set a breakpoint to trigger when a
- value is read from port 3FEH with the upper 2 bits set:
-
- BPIO 3FE R IF (AL & C0)==C0
-
- The condition is evaluated after the instruction completes. The
- value will be in AL, AX, or EAX because all port I/O, except for
- the string I/O instructions (which are rarely used), use the EAX
- register.
-
- Window Message Breakpoints
-
- Use a window message breakpoint to trap a certain message or range of
- messages delivered to a window procedure. Although you could implement
- an equivalent breakpoint yourself using BPX with a conditional
- expression, the following BMSG command is easier to use:
-
- BMSG window-handle [L] [ begin-message [ end-message]]
- [IF expression] [DO "command1;command2;"]
-
- window-handle:
- Value returned when the window was created; you can use the HWND
- command to get a list of windows with their handles.
- L:
- Signifies that the window message should be printed to the
- Command window without popping into SoftICE.
- begin-message:
- Single Windows message or the lower message number in a range of
- Windows messages. If you do not specify a range with an
- end-message, then only the begin-message will cause a break. For
- both begin-message and end-message, the message numbers can be
- specified either in hexadecimal or by using the actual ASCII
- names of the messages, for example, WM_QUIT.
- end-message:
- Higher message number in a range of Windows messages.
- IF expression:
- Refer to Conditional Breakpoints.
- DO "command1;command2;":
- Refer to Setting a Breakpoint Action.
-
- When specifying a message or a message range, you can use the symbolic
- name, for example, WM_NCPAINT. Use the WMSG command to get a list of
- the window messages that SoftICE understands. If no message or message
- range is specified, any message will trigger the breakpoint.
-
- Example:
-
- To set a window message breakpoint for the window handle 1001E,
- use the following command:
-
- BMSG 1001E WM_NCPAINT
-
- SoftICE is smart enough to take into account the address context
- of the process that owns the window, so it does not matter what
- address context you are in when you use BMSG.
-
- You can construct an equivalent BPX-style breakpoint using a
- conditional expression. Use the HWND command to get the address
- of the window procedure, then use the following BPX command
- (Win32 only):
-
- BPX 5FEBDD12 IF (esp->8)==WM_NCPAINT
-
- Warning: When setting a breakpoint using a raw address (not a symbol),
- it is vital to be in the correct address context.
-
- Understanding Breakpoint Contexts
-
- A breakpoint context consists of the address context in which the
- breakpoint was set and in what code module the breakpoint is in, if
- any. Breakpoint contexts apply to the BPX and BPM commands, and
- breakpoint types based on those commands such as BMSG.
-
- For Win32 applications, breakpoints set in the upper 2GB of address
- space are global; they break in any context. Breakpoints set in the
- lower 2GB are context-sensitive; they trigger according to the
- following criteria and SoftICE pops up:
-
- * SoftICE only pops up if the address context matches the context
- in which the breakpoint was set.
-
- * If the breakpoint triggers in the same code module in which the
- breakpoint was set, then SoftICE disregards the address context
- and pops up. This means that a breakpoint set in a shared module
- like KERNEL32.DLL breaks in every address context that has the
- module loaded, regardless of what address context was selected
- when the breakpoint was set.
-
- The exception is if another process mapped the module at a
- different base address than the one in which the breakpoint is
- set. In this case, the breakpoint does not trigger. Avoid this
- situation by basing your DLLs at non-conflicting addresses.
-
- Breakpoints set on MS-DOS and 16-bit Windows programs are
- context-sensitive too in the sense that the breakpoint only affects
- the NTVDM process in which the breakpoint was set. The breakpoint
- never crosses NTVDMs, even if the same program is run multiple times.
-
- Breakpoint contexts are more important for BPM-type breakpoints than
- for BPX. BPM sets an x86 hardware breakpoint that triggers on a
- certain virtual address. Because the CPU's breakpoint hardware knows
- nothing of address spaces, it could potentially trigger on an
- unrelated piece of code or data. Breakpoint contexts give SoftICE the
- ability to discriminate between false traps and real ones.
-
- Virtual Breakpoints
-
- In SoftICE, you can set breakpoints in Windows modules before they
- load, and it is not necessary for a page to be present in physical
- memory for a BPX (INT 3) breakpoint to be set. In such cases, the
- breakpoint is virtual; it will be automatically armed when the module
- loads or the page becomes present. Virtual breakpoints can only be set
- on either symbols or source lines.
-
- Setting a Breakpoint Action
-
- You can set a breakpoint to execute a series of SoftICE commands,
- including user-defined macros, after the breakpoint is triggered. You
- define these breakpoint actions with the DO option, which is available
- with every breakpoint type:
-
- DO "command1;command2;"
-
- The body of a breakpoint action definition is a sequence of SoftICE
- commands or other macros, separated by semicolons. You need not
- terminate the final command with a semicolon.
-
- Breakpoint actions are closely related to macros. Refer to Working
- with Persistent Macros on page 162 for more information about macros.
- Breakpoint actions are essentially unnamed macros that do not accept
- command-line arguments. Breakpoint actions, like macros, can call upon
- macros. In fact a prime use of macros is to simplify the creation of
- complex breakpoint actions.
-
- If you need to embed a literal quote character (") or a percent sign
- (%) within the macro (breakpoint) body, precede the character with a
- backslash character (\). To specify a literal backslash character, use
- two consecutive backslashes (\\).
-
- If a breakpoint is being logged (refer to the built-in function
- BPLOG), the action will not be executed.
-
- The following examples illustrate the basic use of breakpoint actions:
-
- BPX EIP DO "dd eax"
- BPX EIP DO "data 1;dd eax"
- BPMB dataaddr if (byte(*dataaddr)==1) do "? IRQL"
-
- Conditional Breakpoints
-
- Conditional breakpoints provide a fast and easy way to isolate a
- specific condition or state within the system or application you are
- debugging. By setting a breakpoint on an instruction or memory address
- and supplying a conditional expression, SoftICE will only trigger if
- the breakpoint evaluates to non-zero (TRUE). Because the SoftICE
- expression evaluator handles complex expressions easily, conditional
- expressions take you right to the problem or situation you want to
- debug with ease.
-
- All SoftICE breakpoint commands (BPX, BPM, BPIO, BMSG, and BPINT)
- accept conditional expressions using the following syntax:
-
- breakpoint-command [ breakpoint options] [IF conditional expression]
- [DO "commands"]
-
- The IF keyword, when present, is followed by any expression that you
- want to be evaluated when the breakpoint is triggered. The breakpoint
- will be ignored if the conditional expression is FALSE (zero). When
- the conditional expression is TRUE (non-zero), SoftICE pop ups and
- displays the reason for the break, which includes the conditional
- expression.
-
- The following examples show conditional expressions used during the
- development of SoftICE.
-
- Note: Most of these examples contain system-specific values that vary
- depending on the exact version of Windows NT you are running.
-
- * Watch a thread being activated:
-
- bpx ntoskrnl!SwapContext IF (edi==0xFF8B4020)
-
- * Watch a thread being deactivated:
-
- bpx ntoskrnl!SwapContext IF (esi==0xFF8B4020)
-
- * Watch CSRSS HWND objects (type 1) being created:
-
- bpx winsrv!HMAllocObject IF (esp->c == 1)
-
- * Watch CSRSS thread info objects (type 6) being destroyed:
-
- bpx winsrv!HMFreeObject+0x25 IF (byte(esi->8) == 6)
-
- * Watch process object-handle-tables being created:
-
- bpx ntoskrnl!ExAllocatePoolWithTag IF (esp->c == æObtb')
-
- * Watch a thread state become terminated (enum == 4):
-
- bpmb _thread->29 IF byte(_thread->29) == 4)
-
- * Watch a heap block (230CD8) get freed:
-
- bpx ntddl!RtlFreeHeap IF (esp->c == 230CD8)
-
- * Watch a specific process make a system call:
-
- bpint 2E if (process == _process)
-
- Many of the previous examples use the thread and process intrinsic
- functions provided by SoftICE. These functions refer to the active
- thread or process in the operating system. In some cases, the examples
- precede the function name with an underscore "_". This is a special
- feature that makes it easier to refer to a dynamic value such as a
- register's contents or the currently running thread or process as a
- constant. The following examples should help to clarify this concept:
-
- * This example sets a conditional breakpoint that will be triggered if
- the dynamic (run-time) value of the EAX register equals its current
- value.
-
- bpx eip IF (eax == _eax)
-
- This is equivalent to:
-
- ? EAX
- 00010022
- bpx eip IF (eax == 10022)
-
- * This example sets a conditional breakpoint that will be triggered if
- the value of an executing thread's thread-id matches the thread-id of
- the currently executing thread.
-
- bpx eip IF (tid == _tid)
-
- This is equivalent to:
-
- ? tid
- 8
- bpx eip IF (tid == 8)
-
- When you precede a function name or register with an underscore in an
- expression, the function is evaluated immediately and remains constant
- throughout the use of that expression.
-
- Conditional Breakpoint Count Functions
-
- SoftICE supports the ability to monitor and control breakpoints based
- on the number of times a particular breakpoint has or has not been
- triggered. You can use the following count functions in conditional
- expressions:
-
- * BPCOUNT
-
- * BPMISS
-
- * BPTOTAL
-
- * BPLOG
-
- * BPINDEX
-
- BPCOUNT
-
- The value for the BPCOUNT function is the current number of times that
- the breakpoint has been evaluated as TRUE.
-
- Use this function to control the point at which a triggered breakpoint
- causes a popup to occur. Each time the breakpoint is triggered, the
- conditional expression associated with the breakpoint is evaluated. If
- the condition evaluates to TRUE, the breakpoint instance count
- (BPCOUNT) increments by one. If the conditional evaluates to FALSE,
- the breakpoint miss instance count (BPMISS) increments by one.
-
- Example:
-
- The fifth time the breakpoint triggers, the BPCOUNT equals 5, so
- the conditional expression evaluates to TRUE and SoftICE pops up.
-
- bpx myaddr IF (bpcount==5)
-
- Use BPCOUNT only on the righthand side of compound conditional
- expressions for BPCOUNT to increment correctly:
-
- bpx myaddr if (eax==1) && (bpcount==5)
-
- Due to the early-out algorithm employed by the expression evaluator,
- the BPCOUNT==5 expression will not be evaluated unless EAX==1. (The C
- language works the same way.) Therefore, by the time BPCOUNT==5 gets
- evaluated, the expression is TRUE. BPCOUNT will be incremented and if
- it equals 5, the full expression evaluates to TRUE and SoftICE pops
- up. If BPCOUNT != 5, the expression fails, BPMISS is incremented and
- SoftICE will not pop up (although BPCOUNT is now 1 greater).
-
- Once the full expression returns TRUE, SoftICE pops up, and all
- instance counts (BPCOUNT and BPMISS) are reset to 0.
-
- Note: Do not use BPCOUNT before the conditional expression, otherwise
- BPCOUNT will not increment correctly:
-
- bpx myaddr if (bpcount==5) && (eax==1)
-
- BPMISS
-
- The value for the BPMISS expression function is the current number of
- times that the breakpoint was evaluated as FALSE.
-
- The expression function is similar to the BPCOUNT function. Use it to
- specify that SoftICE pop up in situations where the breakpoint is
- continually evaluating to FALSE. The value of BPMISS will always be
- one less than you expect, because it is not updated until the
- conditional expression is evaluated. You can use the (>=) operator to
- correct this delayed update condition.
-
- Example:
-
- bpx myaddr if (eax==43) || (bpmiss>=5)
-
- Due to the early-out algorithm employed by the expression evaluator,
- if the expression eax==43 is ever TRUE, the conditional evaluates to
- TRUE and SoftICE pops up. Otherwise, BPMISS is updated each time the
- conditional evaluates to FALSE. After 5 consecutive failures, the
- expression evaluates to TRUE and SoftICE pops up.
-
- BPTOTAL
-
- The value for the BPTOTAL expression function is the total number of
- times that the breakpoint was triggered.
-
- Use this expression function to control the point at which a triggered
- breakpoint causes a popup to occur. The value of this expression is
- the total number of times the breakpoint was triggered (refer to the
- Hits field in the output of the BSTAT command) over its lifetime. This
- value is never cleared.
-
- Example:
-
- The first 50 times this breakpoint is triggered, the condition
- evaluates to FALSE and SoftICE will not pop up. Every time after
- 50, the condition evaluates to TRUE, and SoftICE pops up on this
- and every subsequent trap.
-
- bpx myaddr if (bptotal > 50)
-
- You can use BPTOTAL to implement functionality identical to that of
- BPCOUNT. Use the modulo "%" operator as follows:
-
- if (!(bptotal%COUNT))
-
- The COUNT is the frequency with which you want the breakpoint to
- trigger. If COUNT is 4, SoftICE pops up every fourth time the
- breakpoint triggers.
-
- BPLOG
-
- Use the BPLOG expression function to log the breakpoint to the history
- buffer. SoftICE does not pop up when logged breakpoints trigger.
-
- Note: Actions only execute when SoftICE pops up, so using actions with
- the BPLOG function is pointless.
-
- The BPLOG expression function always returns TRUE. It causes SoftICE
- to log the breakpoint and relevant information about the breakpoint to
- the SoftICE history buffer.
-
- Example:
-
- Any time the breakpoint triggers and the value of EAX equals 1,
- SoftICE logs the breakpoint in the history buffer. SoftICE will
- not popup.
-
- bpx myaddr if ((eax==1) && bplog)
-
- BPINDEX
-
- Use the BPINDEX expression function to obtain the breakpoint index to
- use with breakpoint actions.
-
- This expression function returns the index of the breakpoint that
- caused SoftICE to pop up. This index is the same index used by the BL,
- BC, BD, BE, BPE, BPT, and BSTAT commands. You can use this value as a
- parameter to any command that is being executed as an action.
-
- Example:
-
- This example of a breakpoint action causes the BSTAT command to
- lly executecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecutecu