home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / +Sandman / si-ug-chapter13.txt < prev    next >
Text File  |  2000-05-25  |  40KB  |  959 lines

  1.                                            You know my methods. Apply them.
  2.                                                      Sir Arthur Conan Doyle
  3.  
  4. Using Breakpoints
  5.  
  6.      Introduction
  7.      Types of Breakpoints Supported by SoftICE
  8.           Breakpoint Options
  9.           Execution Breakpoints
  10.           Memory Breakpoints
  11.           Interrupt Breakpoints
  12.           I/O Breakpoints
  13.           Window Message Breakpoints
  14.      Understanding Breakpoint Contexts
  15.      Virtual Breakpoints
  16.      Setting a Breakpoint Action
  17.      Conditional Breakpoints
  18.           Conditional Breakpoint Count Functions
  19.           Using Local Variables in Conditional Expressions
  20.           Referencing the Stack in Conditional Breakpoints
  21.           Performance
  22.           Duplicate Breakpoints
  23.      Elapsed Time
  24.      Breakpoint Statistics
  25.      Referring to Breakpoints in Expressions
  26.      Manipulating Breakpoints
  27.      Using Embedded Breakpoints
  28.  
  29. Introduction
  30.  
  31.      You can use SoftICE to set breakpoints on program execution, memory
  32.      location reads and writes, interrupts, and reads and writes to I/O
  33.      ports. SoftICE assigns a breakpoint index, from 0 to FF, to each
  34.      breakpoint. You can use this breakpoint index to identify breakpoints
  35.      when you set, delete, disable, enable, or edit them.
  36.  
  37.      All SoftICE breakpoints are sticky, which means that SoftICE tracks
  38.      and maintains a breakpoint until you intentionally clear or disable it
  39.      using the BC or the BD command. After you clear breakpoints, you can
  40.      recall them with the BH command, which displays a breakpoint history.
  41.  
  42.      You can set up to 256 breakpoints at one time in SoftICE. However, the
  43.      number of breakpoints you can set on memory location (BPMs) and I/O
  44.      ports (BPIOs) is a total of four, due to restrictions of the x86
  45.      processors.
  46.  
  47.      Where symbol information is available, you can set breakpoints using
  48.      function names. When in source or mixed mode, you can set
  49.      point-and-shoot style breakpoints on any source code line. A valuable
  50.      feature is that you can set point-and-shoot breakpoints in a module
  51.      before it is even loaded.
  52.  
  53. Types of Breakpoints Supported by SoftICE
  54.  
  55.      SoftICE provides a powerful array of breakpoint capabilities that take
  56.      full advantage of the x86 architecture, as follows :
  57.  
  58.    * Execution Breakpoints: SoftICE replaces an existing instruction with
  59.      INT 3. You can use the BPX command to set execution breakpoints.
  60.  
  61.    * Memory Breakpoints: SoftICE uses the x86 debug registers to break when
  62.      a certain byte/word/dword of memory is read, written, or executed. You
  63.      can use the BPM command to set memory breakpoints.
  64.  
  65.    * Interrupt Breakpoints: SoftICE intercepts interrupts by modifying the
  66.      IDT (Interrupt Descriptor Table) vectors. You can use the BPINT
  67.      command to set interrupt breakpoints.
  68.  
  69.    * I/O Breakpoints: SoftICE uses a debug register extension available on
  70.      Pentium and Pentium-Pro CPUs to watch for an IN or OUT instruction
  71.      going to a particular port address. You can use the BPIO command to
  72.      set I/O breakpoints.
  73.  
  74.    * Window Message Breakpoints: SoftICE traps when a particular message or
  75.      range of messages arrives at a window. This is not a fundamental
  76.      breakpoint type; it is just a convenient feature built on top of the
  77.      other breakpoint primitives. You can use the BMSG command to set
  78.      window message breakpoints.
  79.  
  80. Breakpoint Options
  81.  
  82.      You can qualify each type of breakpoint with the following two
  83.      options:
  84.  
  85.    * A conditional expression [IF expression]: The expression must evaluate
  86.      to non-zero (TRUE) for the breakpoint to trigger. Refer to Conditional
  87.      Breakpoints.
  88.  
  89.    * A breakpoint action [DO "command1;command2;"]: A series of SoftICE
  90.      commands can automatically execute when the breakpoint triggers. You
  91.      can use this feature in concert with user-defined macros to automate
  92.      tasks that would otherwise be tedious. Refer to Setting a Breakpoint
  93.      Action on page 114.
  94.  
  95.      Note: For complete information on each breakpoint command, refer to
  96.      the SoftICE Command Reference.
  97.  
  98. Execution Breakpoints
  99.  
  100.      An execution breakpoint traps executing code such as a function call
  101.      or language statement. This is the most frequently used type of
  102.      breakpoint. By replacing an existing instruction with an INT 3
  103.      instruction, SoftICE takes control when execution reaches the INT 3
  104.      breakpoint.
  105.  
  106.      SoftICE provides two ways for setting execution breakpoints: using a
  107.      mouse and using the BPX command. The following sections describe how
  108.      to use these methods for setting breakpoints.
  109.  
  110. Using a Mouse to Set Breakpoints
  111.  
  112.      If you are using a Pentium processor and a mouse, you can use the
  113.      mouse to set or clear point-and-shoot (sticky) and one-shot
  114.      breakpoints. To set a sticky breakpoint, double-click the line on
  115.      which you want to set the breakpoint. SoftICE highlights the line to
  116.      indicate that you set a breakpoint. Double-click the line again to
  117.      clear the breakpoint. To set a one-shot breakpoint, click the line on
  118.      which you want to set the breakpoint and use the HERE command (F7) to
  119.      execute to that line.
  120.  
  121. Using the BPX Command to Set Breakpoints
  122.  
  123.      Use the BPX command with any of the following parameters to set an
  124.      execution breakpoint:
  125.  
  126.      BPX [address] [IF expression] [DO "command1;command2;"]
  127.  
  128.      IF expression:
  129.           Refer to Conditional Breakpoints.
  130.      DO "command1;command2;":
  131.           Refer to Setting a Breakpoint Action.
  132.  
  133.      Example:
  134.  
  135.           To set a breakpoint on your application's WinMain function, use
  136.           this command:
  137.  
  138.           BPX WinMain
  139.  
  140.      Use the BPX command without specifying any parameter to set a
  141.      point-and-shoot execution breakpoint in the source code. Use Alt-C to
  142.      move the cursor into the Code window. Then use the arrow keys to
  143.      position the cursor on the line on which you want to set the
  144.      breakpoint. Finally, use the BPX command (F9). If you prefer to use
  145.      your mouse to set the breakpoint, click the scroll arrows to scroll
  146.      the Code window, then double-click the line on which you want to set
  147.      the breakpoint.
  148.  
  149. Memory Breakpoints
  150.  
  151.      A memory breakpoint uses the debug registers found on the 386 CPUs and
  152.      later models to monitor access to a certain memory location. This type
  153.      of breakpoint is extremely useful for finding out when and where a
  154.      program variable is modified, and for setting an execution breakpoint
  155.      in read-only memory. You can only set four memory breakpoints at one
  156.      time, because the CPU contains only four debug registers.
  157.  
  158.      Use the BPM command to set memory breakpoints:
  159.  
  160.      BPM[B|W|D] address [R|W|RW|X] [ debug register] [IF expression]
  161.         [DO "command1;command2;"]
  162.  
  163.      BPM and BPMB:
  164.           Set a byte-size breakpoint.
  165.      BPMW:
  166.           Sets a word (2-byte) size breakpoint.
  167.      BPMD:
  168.           Sets a dword (4-byte) size breakpoint.
  169.      R, W, and RW:
  170.           Break on reads, writes, or both.
  171.      X:
  172.           Breaks on execution; this is more powerful than a BPX-style
  173.           breakpoint because memory does not need to be modified, enabling
  174.           such options as setting breakpoints in ROM or setting breakpoints
  175.           on addresses that are not present.
  176.      debug register:
  177.           Specifies which debug register to use. SoftICE normally manages
  178.           the debug register for you, unless you need to specify it in an
  179.           unusual situation.
  180.      IF expression:
  181.           Refer to Conditional Breakpoints.
  182.      DO "command1;command2;":
  183.           Refer to Setting a Breakpoint Action.
  184.  
  185.      Example:
  186.  
  187.           The following example sets a memory breakpoint to trigger when a
  188.           value of 5 is written to the Dword (4-byte) variable
  189.           MyGlobalVariable.
  190.  
  191.           BPMD MyGlobalVariable W IF MyGlobalVariable==5
  192.  
  193.      If the target location of a BPM breakpoint is frequently accessed,
  194.      performance can be degraded regardless of whether the conditional
  195.      expression evaluates to FALSE.
  196.  
  197. Interrupt Breakpoints
  198.  
  199.      Use an interrupt breakpoint to trap an interrupt through the IDT. The
  200.      breakpoint only triggers when a specified interrupt is dispatched
  201.      through the IDT.
  202.  
  203.      Use the BPINT command to set interrupt breakpoints:
  204.  
  205.      BPINT interrupt-number [IF expression] [DO "command1;command2;"]
  206.  
  207.      interrupt-number:
  208.           Number ranging from 0 to 255 (0 to FF hex).
  209.      IF expression:
  210.           Refer to Conditional Breakpoints.
  211.      DO "command1;command2;":
  212.           Refer to Setting a Breakpoint Action.
  213.  
  214.      If an interrupt is caused by a software INT instruction, the
  215.      instruction displayed will be the INT instruction. (SoftICE pops up
  216.      when execution reaches the INT instruction responsible for the
  217.      breakpoint, but before the instruction actually executes.) Otherwise,
  218.      the current instruction will be the first instruction of an interrupt
  219.      handler. You can list all interrupts and their handlers by using the
  220.      IDT command.
  221.  
  222.      Example:
  223.  
  224.           Use the following command to set a breakpoint to trigger when a
  225.           call to the kernel-mode routine NtCreateProcess is made from user
  226.           mode:
  227.  
  228.           BPINT 2E IF EAX==1E
  229.  
  230.           Note: The NtCreateProcess is normally called from ZwCreateProcess
  231.           in the NTDLL.DLL, which is in turn called from CreateProcessW in
  232.           the KERNEL32.DLL. In the conditional expression, 1E is the
  233.           service number for NtCreateProcess. Use the NTCALL command to
  234.           find this value.
  235.  
  236.      You can use the BPINT command to trap software interrupts, for
  237.      example, INT 21 made by 16-bit Windows programs. Note that software
  238.      interrupts issued from V86 mode do not pass through the IDT vector
  239.      that they specify. INT instructions executed in V86 generate processor
  240.      general protection faults (GPF), which are handled by vector 0xD in
  241.      the IDT. The Windows GPF handler realizes the cause of the fault and
  242.      passes control to a handler dedicated to specific V86 interrupt types.
  243.      The types may end up reflecting the interrupt down to V86 mode by
  244.      calling the interrupt handler entered in the V86 mode Interrupt Vector
  245.      Table (IVT). In some cases, a real-mode interrupt is reflected
  246.      (simulated) by calling the real-mode interrupt vector.
  247.  
  248.      In the case where the interrupt is reflected, you can trap it by
  249.      placing a BPX breakpoint at the beginning of the real-mode interrupt
  250.      handler.
  251.  
  252.      Example:
  253.  
  254.           To set a breakpoint on the real-mode INT 21 handler, use the
  255.           following command:
  256.  
  257.           BPX *($0:(21*4))
  258.  
  259. I/O Breakpoints
  260.  
  261.      An I/O breakpoint monitors reads and writes to a port address. The
  262.      breakpoint traps when an IN or OUT instruction accesses the port.
  263.      SoftICE implements I/O breakpoints by using the debug register
  264.      extensions introduced with the Pentium. As a result, I/O breakpoints
  265.      require a Pentium or Pentium-Pro CPU. A maximum of four I/O
  266.      breakpoints can be set at one time. The I/O breakpoint is effective in
  267.      kernel-level (ring 0) code as well as user (ring 3) code.
  268.  
  269.      Notes: Under Windows 95, SoftICE relies on the I/O permission bitmap,
  270.      which restricts I/O trapping to ring 3 code.
  271.  
  272.      Notes: You cannot use I/O breakpoints to trap IN/OUT instructions
  273.      executed by MS-DOS programs. The IN/OUT instructions are trapped and
  274.      emulated by the operating system, and therefore do not generate real
  275.      port I/O, at least not in a 1:1 mapping.
  276.  
  277.      Use the BPIO command to set I/O breakpoints:
  278.  
  279.      BPIO port-number [R|W|RW] [IF expression]
  280.         [DO "command1;command2;"]
  281.  
  282.      R, W, and RW :
  283.           Break on reads (IN instructions), writes (OUT instructions), or
  284.           both, respectively.
  285.      IF expression:
  286.           Refer to Conditional Breakpoints.
  287.      DO "command1;command2;":
  288.           Refer to Setting a Breakpoint Action.
  289.  
  290.      When an I/O breakpoint triggers and SoftICE pops up, the current
  291.      instruction is the instruction following the IN or OUT that caused the
  292.      breakpoint to trigger. Unlike BPM breakpoints, there is no size
  293.      specification; any access to the port-number, whether byte, word, or
  294.      dword, triggers the breakpoint. Any I/O that spans the I/O breakpoint
  295.      will also trigger the breakpoint. For example, if you set an I/O
  296.      breakpoint on port 2FF, a word I/O to port 2FE would trigger the
  297.      breakpoint.
  298.  
  299.      Example:
  300.  
  301.           Use the following command to set a breakpoint to trigger when a
  302.           value is read from port 3FEH with the upper 2 bits set:
  303.  
  304.           BPIO 3FE R IF (AL & C0)==C0
  305.  
  306.           The condition is evaluated after the instruction completes. The
  307.           value will be in AL, AX, or EAX because all port I/O, except for
  308.           the string I/O instructions (which are rarely used), use the EAX
  309.           register.
  310.  
  311. Window Message Breakpoints
  312.  
  313.      Use a window message breakpoint to trap a certain message or range of
  314.      messages delivered to a window procedure. Although you could implement
  315.      an equivalent breakpoint yourself using BPX with a conditional
  316.      expression, the following BMSG command is easier to use:
  317.  
  318.      BMSG window-handle [L] [ begin-message [ end-message]]
  319.         [IF expression] [DO "command1;command2;"]
  320.  
  321.      window-handle:
  322.           Value returned when the window was created; you can use the HWND
  323.           command to get a list of windows with their handles.
  324.      L:
  325.           Signifies that the window message should be printed to the
  326.           Command window without popping into SoftICE.
  327.      begin-message:
  328.           Single Windows message or the lower message number in a range of
  329.           Windows messages. If you do not specify a range with an
  330.           end-message, then only the begin-message will cause a break. For
  331.           both begin-message and end-message, the message numbers can be
  332.           specified either in hexadecimal or by using the actual ASCII
  333.           names of the messages, for example, WM_QUIT.
  334.      end-message:
  335.           Higher message number in a range of Windows messages.
  336.      IF expression:
  337.           Refer to Conditional Breakpoints.
  338.      DO "command1;command2;":
  339.           Refer to Setting a Breakpoint Action.
  340.  
  341.      When specifying a message or a message range, you can use the symbolic
  342.      name, for example, WM_NCPAINT. Use the WMSG command to get a list of
  343.      the window messages that SoftICE understands. If no message or message
  344.      range is specified, any message will trigger the breakpoint.
  345.  
  346.      Example:
  347.  
  348.           To set a window message breakpoint for the window handle 1001E,
  349.           use the following command:
  350.  
  351.           BMSG 1001E WM_NCPAINT
  352.  
  353.           SoftICE is smart enough to take into account the address context
  354.           of the process that owns the window, so it does not matter what
  355.           address context you are in when you use BMSG.
  356.  
  357.           You can construct an equivalent BPX-style breakpoint using a
  358.           conditional expression. Use the HWND command to get the address
  359.           of the window procedure, then use the following BPX command
  360.           (Win32 only):
  361.  
  362.           BPX 5FEBDD12 IF (esp->8)==WM_NCPAINT
  363.  
  364.      Warning: When setting a breakpoint using a raw address (not a symbol),
  365.      it is vital to be in the correct address context.
  366.  
  367. Understanding Breakpoint Contexts
  368.  
  369.      A breakpoint context consists of the address context in which the
  370.      breakpoint was set and in what code module the breakpoint is in, if
  371.      any. Breakpoint contexts apply to the BPX and BPM commands, and
  372.      breakpoint types based on those commands such as BMSG.
  373.  
  374.      For Win32 applications, breakpoints set in the upper 2GB of address
  375.      space are global; they break in any context. Breakpoints set in the
  376.      lower 2GB are context-sensitive; they trigger according to the
  377.      following criteria and SoftICE pops up:
  378.  
  379.         * SoftICE only pops up if the address context matches the context
  380.           in which the breakpoint was set.
  381.  
  382.         * If the breakpoint triggers in the same code module in which the
  383.           breakpoint was set, then SoftICE disregards the address context
  384.           and pops up. This means that a breakpoint set in a shared module
  385.           like KERNEL32.DLL breaks in every address context that has the
  386.           module loaded, regardless of what address context was selected
  387.           when the breakpoint was set.
  388.  
  389.           The exception is if another process mapped the module at a
  390.           different base address than the one in which the breakpoint is
  391.           set. In this case, the breakpoint does not trigger. Avoid this
  392.           situation by basing your DLLs at non-conflicting addresses.
  393.  
  394.      Breakpoints set on MS-DOS and 16-bit Windows programs are
  395.      context-sensitive too in the sense that the breakpoint only affects
  396.      the NTVDM process in which the breakpoint was set. The breakpoint
  397.      never crosses NTVDMs, even if the same program is run multiple times.
  398.  
  399.      Breakpoint contexts are more important for BPM-type breakpoints than
  400.      for BPX. BPM sets an x86 hardware breakpoint that triggers on a
  401.      certain virtual address. Because the CPU's breakpoint hardware knows
  402.      nothing of address spaces, it could potentially trigger on an
  403.      unrelated piece of code or data. Breakpoint contexts give SoftICE the
  404.      ability to discriminate between false traps and real ones.
  405.  
  406. Virtual Breakpoints
  407.  
  408.      In SoftICE, you can set breakpoints in Windows modules before they
  409.      load, and it is not necessary for a page to be present in physical
  410.      memory for a BPX (INT 3) breakpoint to be set. In such cases, the
  411.      breakpoint is virtual; it will be automatically armed when the module
  412.      loads or the page becomes present. Virtual breakpoints can only be set
  413.      on either symbols or source lines.
  414.  
  415. Setting a Breakpoint Action
  416.  
  417.      You can set a breakpoint to execute a series of SoftICE commands,
  418.      including user-defined macros, after the breakpoint is triggered. You
  419.      define these breakpoint actions with the DO option, which is available
  420.      with every breakpoint type:
  421.  
  422.      DO "command1;command2;"
  423.  
  424.      The body of a breakpoint action definition is a sequence of SoftICE
  425.      commands or other macros, separated by semicolons. You need not
  426.      terminate the final command with a semicolon.
  427.  
  428.      Breakpoint actions are closely related to macros. Refer to Working
  429.      with Persistent Macros on page 162 for more information about macros.
  430.      Breakpoint actions are essentially unnamed macros that do not accept
  431.      command-line arguments. Breakpoint actions, like macros, can call upon
  432.      macros. In fact a prime use of macros is to simplify the creation of
  433.      complex breakpoint actions.
  434.  
  435.      If you need to embed a literal quote character (") or a percent sign
  436.      (%) within the macro (breakpoint) body, precede the character with a
  437.      backslash character (\). To specify a literal backslash character, use
  438.      two consecutive backslashes (\\).
  439.  
  440.      If a breakpoint is being logged (refer to the built-in function
  441.      BPLOG), the action will not be executed.
  442.  
  443.      The following examples illustrate the basic use of breakpoint actions:
  444.  
  445.      BPX EIP DO "dd eax"
  446.      BPX EIP DO "data 1;dd eax"
  447.      BPMB dataaddr if (byte(*dataaddr)==1) do "? IRQL"
  448.  
  449. Conditional Breakpoints
  450.  
  451.      Conditional breakpoints provide a fast and easy way to isolate a
  452.      specific condition or state within the system or application you are
  453.      debugging. By setting a breakpoint on an instruction or memory address
  454.      and supplying a conditional expression, SoftICE will only trigger if
  455.      the breakpoint evaluates to non-zero (TRUE). Because the SoftICE
  456.      expression evaluator handles complex expressions easily, conditional
  457.      expressions take you right to the problem or situation you want to
  458.      debug with ease.
  459.  
  460.      All SoftICE breakpoint commands (BPX, BPM, BPIO, BMSG, and BPINT)
  461.      accept conditional expressions using the following syntax:
  462.  
  463.      breakpoint-command [ breakpoint options] [IF conditional expression]
  464.         [DO "commands"]
  465.  
  466.      The IF keyword, when present, is followed by any expression that you
  467.      want to be evaluated when the breakpoint is triggered. The breakpoint
  468.      will be ignored if the conditional expression is FALSE (zero). When
  469.      the conditional expression is TRUE (non-zero), SoftICE pop ups and
  470.      displays the reason for the break, which includes the conditional
  471.      expression.
  472.  
  473.      The following examples show conditional expressions used during the
  474.      development of SoftICE.
  475.  
  476.      Note: Most of these examples contain system-specific values that vary
  477.      depending on the exact version of Windows NT you are running.
  478.  
  479.    * Watch a thread being activated:
  480.  
  481.           bpx ntoskrnl!SwapContext IF (edi==0xFF8B4020)
  482.  
  483.    * Watch a thread being deactivated:
  484.  
  485.           bpx ntoskrnl!SwapContext IF (esi==0xFF8B4020)
  486.  
  487.    * Watch CSRSS HWND objects (type 1) being created:
  488.  
  489.           bpx winsrv!HMAllocObject IF (esp->c == 1)
  490.  
  491.    * Watch CSRSS thread info objects (type 6) being destroyed:
  492.  
  493.           bpx winsrv!HMFreeObject+0x25 IF (byte(esi->8) == 6)
  494.  
  495.    * Watch process object-handle-tables being created:
  496.  
  497.           bpx ntoskrnl!ExAllocatePoolWithTag IF (esp->c == æObtb')
  498.  
  499.    * Watch a thread state become terminated (enum == 4):
  500.  
  501.           bpmb _thread->29 IF byte(_thread->29) == 4)
  502.  
  503.    * Watch a heap block (230CD8) get freed:
  504.  
  505.           bpx ntddl!RtlFreeHeap IF (esp->c == 230CD8)
  506.  
  507.    * Watch a specific process make a system call:
  508.  
  509.           bpint 2E if (process == _process)
  510.  
  511.      Many of the previous examples use the thread and process intrinsic
  512.      functions provided by SoftICE. These functions refer to the active
  513.      thread or process in the operating system. In some cases, the examples
  514.      precede the function name with an underscore "_". This is a special
  515.      feature that makes it easier to refer to a dynamic value such as a
  516.      register's contents or the currently running thread or process as a
  517.      constant. The following examples should help to clarify this concept:
  518.  
  519.    * This example sets a conditional breakpoint that will be triggered if
  520.      the dynamic (run-time) value of the EAX register equals its current
  521.      value.
  522.  
  523.           bpx eip IF (eax == _eax)
  524.  
  525.      This is equivalent to:
  526.  
  527.           ? EAX
  528.           00010022
  529.           bpx eip IF (eax == 10022)
  530.  
  531.    * This example sets a conditional breakpoint that will be triggered if
  532.      the value of an executing thread's thread-id matches the thread-id of
  533.      the currently executing thread.
  534.  
  535.           bpx eip IF (tid == _tid)
  536.  
  537.      This is equivalent to:
  538.  
  539.           ? tid
  540.           8
  541.           bpx eip IF (tid == 8)
  542.  
  543.      When you precede a function name or register with an underscore in an
  544.      expression, the function is evaluated immediately and remains constant
  545.      throughout the use of that expression.
  546.  
  547. Conditional Breakpoint Count Functions
  548.  
  549.      SoftICE supports the ability to monitor and control breakpoints based
  550.      on the number of times a particular breakpoint has or has not been
  551.      triggered. You can use the following count functions in conditional
  552.      expressions:
  553.  
  554.    * BPCOUNT
  555.  
  556.    * BPMISS
  557.  
  558.    * BPTOTAL
  559.  
  560.    * BPLOG
  561.  
  562.    * BPINDEX
  563.  
  564. BPCOUNT
  565.  
  566.      The value for the BPCOUNT function is the current number of times that
  567.      the breakpoint has been evaluated as TRUE.
  568.  
  569.      Use this function to control the point at which a triggered breakpoint
  570.      causes a popup to occur. Each time the breakpoint is triggered, the
  571.      conditional expression associated with the breakpoint is evaluated. If
  572.      the condition evaluates to TRUE, the breakpoint instance count
  573.      (BPCOUNT) increments by one. If the conditional evaluates to FALSE,
  574.      the breakpoint miss instance count (BPMISS) increments by one.
  575.  
  576.      Example:
  577.  
  578.           The fifth time the breakpoint triggers, the BPCOUNT equals 5, so
  579.           the conditional expression evaluates to TRUE and SoftICE pops up.
  580.  
  581.           bpx myaddr IF (bpcount==5)
  582.  
  583.      Use BPCOUNT only on the righthand side of compound conditional
  584.      expressions for BPCOUNT to increment correctly:
  585.  
  586.      bpx myaddr if (eax==1) && (bpcount==5)
  587.  
  588.      Due to the early-out algorithm employed by the expression evaluator,
  589.      the BPCOUNT==5 expression will not be evaluated unless EAX==1. (The C
  590.      language works the same way.) Therefore, by the time BPCOUNT==5 gets
  591.      evaluated, the expression is TRUE. BPCOUNT will be incremented and if
  592.      it equals 5, the full expression evaluates to TRUE and SoftICE pops
  593.      up. If BPCOUNT != 5, the expression fails, BPMISS is incremented and
  594.      SoftICE will not pop up (although BPCOUNT is now 1 greater).
  595.  
  596.      Once the full expression returns TRUE, SoftICE pops up, and all
  597.      instance counts (BPCOUNT and BPMISS) are reset to 0.
  598.  
  599.      Note: Do not use BPCOUNT before the conditional expression, otherwise
  600.      BPCOUNT will not increment correctly:
  601.  
  602.      bpx myaddr if (bpcount==5) && (eax==1)
  603.  
  604. BPMISS
  605.  
  606.      The value for the BPMISS expression function is the current number of
  607.      times that the breakpoint was evaluated as FALSE.
  608.  
  609.      The expression function is similar to the BPCOUNT function. Use it to
  610.      specify that SoftICE pop up in situations where the breakpoint is
  611.      continually evaluating to FALSE. The value of BPMISS will always be
  612.      one less than you expect, because it is not updated until the
  613.      conditional expression is evaluated. You can use the (>=) operator to
  614.      correct this delayed update condition.
  615.  
  616.      Example:
  617.  
  618.           bpx myaddr if (eax==43) || (bpmiss>=5)
  619.  
  620.      Due to the early-out algorithm employed by the expression evaluator,
  621.      if the expression eax==43 is ever TRUE, the conditional evaluates to
  622.      TRUE and SoftICE pops up. Otherwise, BPMISS is updated each time the
  623.      conditional evaluates to FALSE. After 5 consecutive failures, the
  624.      expression evaluates to TRUE and SoftICE pops up.
  625.  
  626. BPTOTAL
  627.  
  628.      The value for the BPTOTAL expression function is the total number of
  629.      times that the breakpoint was triggered.
  630.  
  631.      Use this expression function to control the point at which a triggered
  632.      breakpoint causes a popup to occur. The value of this expression is
  633.      the total number of times the breakpoint was triggered (refer to the
  634.      Hits field in the output of the BSTAT command) over its lifetime. This
  635.      value is never cleared.
  636.  
  637.      Example:
  638.  
  639.           The first 50 times this breakpoint is triggered, the condition
  640.           evaluates to FALSE and SoftICE will not pop up. Every time after
  641.           50, the condition evaluates to TRUE, and SoftICE pops up on this
  642.           and every subsequent trap.
  643.  
  644.           bpx myaddr if (bptotal > 50)
  645.  
  646.      You can use BPTOTAL to implement functionality identical to that of
  647.      BPCOUNT. Use the modulo "%" operator as follows:
  648.  
  649.      if (!(bptotal%COUNT))
  650.  
  651.      The COUNT is the frequency with which you want the breakpoint to
  652.      trigger. If COUNT is 4, SoftICE pops up every fourth time the
  653.      breakpoint triggers.
  654.  
  655. BPLOG
  656.  
  657.      Use the BPLOG expression function to log the breakpoint to the history
  658.      buffer. SoftICE does not pop up when logged breakpoints trigger.
  659.  
  660.      Note: Actions only execute when SoftICE pops up, so using actions with
  661.      the BPLOG function is pointless.
  662.  
  663.      The BPLOG expression function always returns TRUE. It causes SoftICE
  664.      to log the breakpoint and relevant information about the breakpoint to
  665.      the SoftICE history buffer.
  666.  
  667.      Example:
  668.  
  669.           Any time the breakpoint triggers and the value of EAX equals 1,
  670.           SoftICE logs the breakpoint in the history buffer. SoftICE will
  671.           not popup.
  672.  
  673.           bpx myaddr if ((eax==1) && bplog)
  674.  
  675. BPINDEX
  676.  
  677.      Use the BPINDEX expression function to obtain the breakpoint index to
  678.      use with breakpoint actions.
  679.  
  680.      This expression function returns the index of the breakpoint that
  681.      caused SoftICE to pop up. This index is the same index used by the BL,
  682.      BC, BD, BE, BPE, BPT, and BSTAT commands. You can use this value as a
  683.      parameter to any command that is being executed as an action.
  684.  
  685.      Example:
  686.  
  687.           This example of a breakpoint action causes the BSTAT command to
  688.           be executed with the breakpoint that caused the action to be
  689.           executed as its parameter:
  690.  
  691.           bpx myaddr do "bstat bpindex"
  692.  
  693.           This example shows a breakpoint that uses an action to create
  694.           another breakpoint:
  695.  
  696.           bpx myaddr do "t;bpx @esp if(tid==_tid) do \"bc bpindex\";g"
  697.  
  698.      Note: BPINDEX is intended to be used with breakpoint actions, and
  699.      causes an error if it is used within a conditional expression. Its use
  700.      outside of actions is allowed, but the result is unspecified and you
  701.      should not rely on it.
  702.  
  703. Using Local Variables in Conditional Expressions
  704.  
  705.      SoftICE lets you use local variable names in conditional expressions
  706.      as long as the type ofbreakpoint is an execution breakpoint (BPX or
  707.      BPM X). SoftICE does not recognize local symbols in conditional
  708.      expressions for other breakpoint types, such as BPIO or BPMD RW,
  709.      because they require an execution scope. This type of breakpoint is
  710.      not tied to a specific section of executing code, so local variables
  711.      have no meaning.
  712.  
  713.      When using local variables in conditional expressions, functions
  714.      typically have a prologue where local variables are created and an
  715.      epilogue where they are destroyed. You can access local variables
  716.      after the prologue code completes execution and before the epilogue
  717.      code begins execution. Function parameters are also temporarily
  718.      inaccessible using symbol names during prologue and epilogue
  719.      execution, because of adjustments to the stack frame.
  720.  
  721.      To avoid these restrictions, set a breakpoint on either the first or
  722.      last source code line within the function body. The following concepts
  723.      use the foobar function to explain this concept.
  724.  
  725. Foobar Function
  726.  
  727.      1:DWORD foobar ( DWORD foo )
  728.      2:{
  729.      3: DWORD fooTmp=0;
  730.      4:
  731.      5: if(foo)
  732.      6: {
  733.      7: fooTmp=foo*2;
  734.      8: }else{
  735.      9: fooTmp=1;
  736.      10: }
  737.      11:
  738.      12: return fooTmp;
  739.      13:}
  740.  
  741.      Source code lines 1 and 2 are outside the function body. These lines
  742.      execute the prologue code. If you use a local variable at this point,
  743.      you receive the following symbol error:
  744.  
  745.      :BPX foobar if(foo==1)
  746.      error: Undefined Symbol (foo)
  747.  
  748.      Set the conditional on the source code line 3 where the local variable
  749.      fooTmp is declared and initialized, as follows:
  750.  
  751.      :BPX .3 if(foo==0)
  752.  
  753.      Source code line 13 marks the end of the function body. It also begins
  754.      epilogue code execution; thus, local variables and parameters are out
  755.      of scope. To set a conditional at the end of the foobar function, use
  756.      source line 12, as follows:
  757.  
  758.      :BPX.12 if(fooTmp==1)
  759.  
  760.      Note: Although it is possible to use local variables as the input to a
  761.      breakpoint command, such as BPMD RW, you should avoid doing this.
  762.      Local variables are relative to the stack, so their absolute address
  763.      changes each time the function scope where the variable is declared
  764.      executes. When the original function scope exits, the address tied to
  765.      the breakpoint no longer refers to the value of the local variable.
  766.  
  767. Referencing the Stack in Conditional Breakpoints
  768.  
  769.      If you create your symbol file with full symbol information, you can
  770.      access function parameters and local variables through their symbolic
  771.      names, as described in Using Local Variables in Conditional
  772.      Expressions. If, however, you are debugging without full symbol
  773.      information, you need to reference function parameters and local
  774.      variables on the stack. For example, if you translated a module with
  775.      publics only or you want to debug a function for an operating system,
  776.      reference function parameters and local variables on the stack.
  777.  
  778.      This section is specific to 32-bit flat application or system code.
  779.  
  780.      Function parameters are passed on the stack, so you need to
  781.      de-reference these parameters through the ESP or EBP registers. Which
  782.      one you use depends on the function's prologue and where you set the
  783.      actual breakpoint in relation to that prologue.
  784.  
  785.      Most 32-bit functions have a prologue of the following form:
  786.  
  787.      PUSH EBP
  788.      MOV EBP,ESP
  789.      SUB ESP,size (locals)
  790.  
  791.      Which sets up a stack frame as follows:
  792.  
  793.       Stack Top          PARAM n           ESP+(n*4), or
  794.                                             EBP+(n*4)+4        Pushed by
  795.                          PARAM #2         ESP+8, or EBP+C        Caller
  796.  
  797.                          PARAM #1         ESP+4, or EBP+8
  798.  
  799.                          RET EIP         Stack pointer on
  800.                                                Entry
  801.                 Current                 Base Pointer (PUSH
  802.                   EBP    SAVE EBP        EBP, MOV EBP,ESP)
  803.                          LOCALS+SIZE-1                       Call prologue
  804.  
  805.                                         Stack Pointer after
  806.                          LOCALS+0       prologue (SUB ESP,
  807.                                            size(locals)
  808.  
  809.                          SAVE EBX      Optional save of "C"
  810.                                              registers          Register
  811.                          SAVE ESI                               saved by
  812.         Stack   Current                 Stack pointer after     compiler
  813.        Bottom     ESP    SAVE EDI       registers are saved
  814.  
  815.      Use either the ESP or EBP register to address parameters. Using the
  816.      EBP register is not valid until the PUSH EBP and MOV EBP, ESP
  817.      instructions are executed. Also note that once space for local
  818.      variables is created (SUB ESP,size) the position of the parameters
  819.      relative to ESP needs to be adjusted by the size of the local
  820.      variables and any saved registers.
  821.  
  822.      Typically you set a breakpoint on the function address, for example:
  823.  
  824.      BPX IsWindow
  825.  
  826.      When this breakpoint is triggered, the prologue has not been executed,
  827.      and parameters can easily be accessed through the ESP register. At
  828.      this point, use of EBP is not valid.
  829.  
  830.      To be sure that de-referencing the stack in a conditional expression
  831.      operates as you would expect, use the following guidelines.
  832.  
  833.      Note: This assumes a stack-based calling convention with arguments
  834.      pushed right-to-left.
  835.  
  836.    * If you set a breakpoint at the exact function address, for example,
  837.      BPX IsWindow, use ESP+(param# * 4) to address parameters, where param#
  838.      is 1...n.
  839.  
  840.    * If you set a breakpoint inside a function body (after the full
  841.      prologue has been executed), use EBP+(param# * 4)+4 to address
  842.      parameters, where param# is 1...n. Be sure that the routine does not
  843.      use the EBP register for a purpose other than a stack-frame.
  844.  
  845.    * Functions that are assembly-language based or are optimized for
  846.      frame-pointer omission may require that you use the ESP register,
  847.      because EBP may not be set up correctly.
  848.  
  849.      Note: Once the space for local variables is allocated on the stack,
  850.      the local variables can be addressed using a negative offset from EBP.
  851.      The first local variable is at EBP-4. Simple data types are typically
  852.      Dword sized, so their offset can be calculated in a manner similar to
  853.      function parameters. For example, with two pointer local variables,
  854.      one will be at EBP-4 and the other will be at EBP-8.
  855.  
  856. Performance
  857.  
  858.      Conditional breakpoints have some overhead associated with run-time
  859.      evaluation. Under most circumstances you see little or no effect on
  860.      performance when using conditional expressions. In situations where
  861.      you set a conditional breakpoint on a highly accessed data variable or
  862.      code sequence, you may notice slower system performance. This is due
  863.      to the fact that every time the breakpoint is triggered, the
  864.      conditional expression is evaluated. If a routine is executed hundreds
  865.      of times per second (such as ExAllocatePool or SwapContext), the fact
  866.      that any type of breakpoint with or without a conditional is trapped
  867.      and evaluated with this frequency results in some performance
  868.      degradation.
  869.  
  870. Duplicate Breakpoints
  871.  
  872.      Once a breakpoint is set on an address, you cannot set another
  873.      breakpoint on the same address. With conditional expressions, however,
  874.      you can create a compound expression using the logical operators (&&)
  875.      or (||) to test more than one condition at the same address.
  876.  
  877. Elapsed Time
  878.  
  879.      SoftICE supports using the time stamp counter (RDTSC instruction) on
  880.      all Pentium and Pentium-Pro machines. When SoftICE first starts, it
  881.      displays the clock speed of the machine on which it is running. Every
  882.      time SoftICE pops up due to a breakpoint, the elapsed time displays
  883.      since the last time SoftICE popped up. The time displays after the
  884.      break reason in seconds, milliseconds, or microseconds:
  885.  
  886.      Break due to G (ET=23.99 microseconds)
  887.  
  888.      The Pentium cycle counter is highly accurate, but you must keep the
  889.      following two issues in mind:
  890.  
  891.      1- There is overhead involved in popping SoftICE up and down. On a
  892.      100MHz machine, this takes approximately 5 microseconds. This number
  893.      is slightly variable due to caching and privilege level changes.
  894.  
  895.      2- If a hardware interrupt occurs before the breakpoint goes off, all
  896.      the interrupt processing time is included. Interrupts are off when
  897.      SoftICE pops up, so a hardware interrupt almost always goes off as
  898.      soon as Windows NT resumes.
  899.  
  900. Breakpoint Statistics
  901.  
  902.      SoftICE collects statistical information about each breakpoint,
  903.      including the following:
  904.  
  905.         * Total number of hits, breaks, misses, and errors
  906.  
  907.         * Current hits and misses
  908.  
  909.      Use the BSTAT command to display this information. Refer to the
  910.      SoftICE Command Reference for more information on the BSTAT command.
  911.  
  912. Referring to Breakpoints in Expressions
  913.  
  914.      You can combine the prefix "BP" with the breakpoint index to use as a
  915.      symbol in an expression. This works for all BPX and BPM breakpoints.
  916.      SoftICE uses the actual address of the breakpoint.
  917.  
  918.      Example:
  919.  
  920.           To disassemble code at the address of the breakpoint with index
  921.           0, use the command:
  922.  
  923.           U BP0
  924.  
  925. Manipulating Breakpoints
  926.  
  927.      SoftICE provides a variety of commands for manipulating breakpoints
  928.      such as listing, modifying, deleting, enabling, disabling, and
  929.      recalling breakpoints. Breakpoints are identified by breakpoint index
  930.      numbers, which are numbers ranging from 0 to FF (hex). Breakpoint
  931.      index numbers are assigned sequentially as breakpoints are added. The
  932.      following table describes the breakpoint manipulation commands:
  933.  
  934.       BD Disable a breakpoint
  935.       BE Enable a breakpoint
  936.       BL List current breakpoints
  937.       BPEEdit a breakpoint
  938.       BPTUse breakpoint as template
  939.       BC Clear (remove) a breakpoint
  940.       BH Display breakpoint history
  941.  
  942.      Note: Refer to the SoftICE Command Reference for more information on
  943.      each of these commands.
  944.  
  945. Using Embedded Breakpoints
  946.  
  947.      It may be helpful for you to embed a breakpoint in your program source
  948.      rather than setting a breakpoint with SoftICE. To embed a breakpoint
  949.      in your program, do the following:
  950.  
  951.      1 Place an INT 1 or INT 3 instruction at the desired point in the
  952.      program source.
  953.  
  954.      2 To enable SoftICE to pop up on such embedded breakpoints, use the
  955.      following command:
  956.  
  957.      SET I1HERE ON ; for INT 1 breakpoints
  958.      SET I3HERE ON ; for INT 3 breakpoints
  959.