From: <Saved by Microsoft Internet Explorer 5>
Subject: Hardware breakpoints
Date: Thu, 22 Jan 2004 20:45:20 -0500
MIME-Version: 1.0
Content-Type: multipart/related;
	boundary="----=_NextPart_000_0040_01C3E128.A692DD10";
	type="text/html"
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165

This is a multi-part message in MIME format.

------=_NextPart_000_0040_01C3E128.A692DD10
Content-Type: text/html;
	charset="Windows-1252"
Content-Transfer-Encoding: quoted-printable
Content-Location: http://www.morearty.com/code/breakpoint/

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Hardware breakpoints</TITLE>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Dwindows-1252">
<META content=3D"MSHTML 6.00.2800.1276" name=3DGENERATOR>
<META content=3DFrontPage.Editor.Document name=3DProgId><LINK=20
href=3D"http://www.morearty.com/code.css" type=3Dtext/css =
rel=3Dstylesheet></HEAD>
<BODY>
<TABLE width=3D"100%" border=3D0>
  <TBODY>
  <TR>
    <TD>
      <H1>Hardware breakpoints</H1></TD>
    <TD align=3Dright><B><A=20
      =
href=3D"http://www.morearty.com/code/breakpoint/breakpoint.zip">Click to =

      download source</A></B></TD></TR></TBODY></TABLE>
<P>This is a debugging helper class which lets you set breakpoints on =
the fly=20
from within code. This is mainly useful for the case where you have a =
variable=20
that you know is getting trashed, but you have no idea who is trashing =
it. You=20
can cause the debugger to break in at the very moment the variable is =
changed.=20
The really cool thing is that this makes use of the Intel Pentium's =
built-in=20
debug registers, which means that it really will stop no matter <I>what =
</I>code=20
is executing, even if it's down in the NT kernel, in a different thread, =
or=20
whatever.</P>
<P>(Visual C++ has the ability to set a breakpoint when a variable's =
value=20
changes, but these breakpoints can be very hard to use, especially on =
local=20
variables.)</P>
<H2>Usage</H2>
<P>The class is called CBreakpoint. If, for example, you have a DWORD =
called "x"=20
and you want to break the next time it's written to, do this:</P>
<BLOCKQUOTE><PRE>DWORD x =3D 1;

CBreakpoint bp;
bp.Set(&amp;x, sizeof(x), CBreakpoint::Write);</PRE></BLOCKQUOTE>
<P>As your code continues to execute, if Visual C++ stops at a location =
where=20
you didn't have a VC++ breakpoint set, it's possible that the =
CBreakpoint=20
triggered.&nbsp; If it did, the assembly instruction <I>immediately =
before</I>=20
the instruction pointer is the one that caused it to trigger.</P>
<P>The breakpoint will be cleared automatically when the CBreakpoint =
object=20
falls out of scope.&nbsp; Or, to clear it explicitly, do this:</P>
<BLOCKQUOTE><PRE>bp.Clear();</PRE></BLOCKQUOTE>
<P>You can also break the moment any code even tries to read the value =
of the=20
variable x! (Actually, this will break when someone tries to read =
<I>or</I>=20
write it.)</P>
<BLOCKQUOTE><PRE>bp.Set(&amp;x, sizeof(x), =
CBreakpoint::Read);</PRE></BLOCKQUOTE>
<H2>Notes</H2>
<P>This code is Intel-specific.&nbsp; It will run on Win95/98/ME and on=20
WinNT/2000, as long as the machine is running an Intel or compatible =
chip (e.g.=20
not Alpha).</P>
<P>There are certain limitations when the breakpoint is triggered inside =
system=20
code (these same limitations apply to hardware breakpoints set by Visual =
C++ or=20
any other debugger):</P>
<UL>
  <LI>On WinNT/2000, some system code runs in ring 3 (with user =
privileges), and=20
  other system code runs in ring 0.&nbsp; If a hardware breakpoint =
triggers=20
  inside ring 0 code, the debugger <I>will</I> stop, but not exactly =
when the=20
  data write happens -- it will stop after execution transitions back to =
ring 3=20
  code.&nbsp; In practice, this is not a problem at all -- when the =
breakpoint=20
  triggers, it's usually quite easy to figure out what happened.=20
  <LI>On Win95/98/ME, the situation is not as good.&nbsp; <I>All</I> =
system code=20
  is treated by the debugger as untouchable.&nbsp; Worse, whenever any =
hardware=20
  breakpoint triggers inside system code, you'll never see the =
breakpoint=20
  trigger.&nbsp; For example, if a call to <TT>strcpy()</TT> would cause =
your=20
  breakpoint to trigger, you'll see it, because <TT>strcpy()</TT> is =
just a=20
  regular part of your application.&nbsp; But if a call to =
<TT>lstrcpy()</TT>=20
  would cause your breakpoint to trigger, you won't see it, because=20
  <TT>lstrcpy()</TT> is system code. </LI></UL>
<P>You can do "bp.Clear()" from the QuickWatch dialog to clear a =
breakpoint from=20
within the debugger.</P>
<P>The second parameter is the number of bytes to watch. This <I>must =
</I>be=20
either 1, 2, or 4. Also, the variable being watched <I>must </I>be =
aligned=20
appropriately (e.g. if you're watching 4 bytes, they must be=20
DWORD-aligned).&nbsp; If you don't do this, you'll get an error when you =
try to=20
set the breakpoint.&nbsp; There is a limit of 4 hardware breakpoints. =
Because of=20
this (and also because of common sense), don't check in code that uses=20
breakpoints -- just write the code temporarily to find bugs, but delete =
it=20
before checking in your source into your source control system.</P>
<P>It's important to pass in the address that you actually want to =
watch.=20
Consider these two similar but different cases:</P>
<BLOCKQUOTE><PRE>long *my_array;
my_array =3D new long[3];

CBreakpoint bpArrayPtr, bpArrayFirstElement;

// break if someone changes the POINTER
bpArrayPtr.Set(&amp;my_array, sizeof(long*), CBreakpoint::Write);

// break if someone changes the FIRST ELEMENT POINTED TO
bpArrayFirstElement.Set(&amp;my_array[0], sizeof(long), =
CBreakpoint::Write);</PRE></BLOCKQUOTE>
<H2>How does it work?</H2>
<P>The Intel x86 CPUs have some special registers which are intended for =

debugging use only.&nbsp; By storing special values into these =
registers, a=20
program can ask the CPU to execute an INT 1 (interrupt 1) instruction=20
immediately whenever a specified memory location is read from or written =

to.&nbsp; (They can also stop when a memory address is about to be =
executed as=20
code, but my CBreakpoint class doesn't use that functionality.)</P>
<P>INT 1 also happens to be the interrupt that's executed by the CPU =
after a=20
debugger asks the CPU to single-step one assembly line of the =
program.&nbsp; And=20
by good fortune, when Visual C++ encounters an INT 1 that it wasn't =
expecting to=20
see (as is the case when a CBreakpoint breakpoint is triggered), it =
responds=20
gracefully, stopping the debugger at the appropriate instruction.</P>
<P align=3Dright><I><SMALL><A =
href=3D"http://www.morearty.com/code/">Back to the=20
"Code" page</A></SMALL></I></P></BODY></HTML>

------=_NextPart_000_0040_01C3E128.A692DD10
Content-Type: text/css;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Location: http://www.morearty.com/code/breakpoint/main.css

BODY {
	BACKGROUND-COLOR: white
}
BODY {
	FONT-SIZE: x-small; FONT-FAMILY: Verdana,Helvetica,Arial
}
P {
	FONT-SIZE: x-small; FONT-FAMILY: Verdana,Helvetica,Arial
}
TD {
	FONT-SIZE: x-small; FONT-FAMILY: Verdana,Helvetica,Arial
}
H1 {
	FONT-SIZE: large; TEXT-ALIGN: center
}
TD H1 {
	TEXT-ALIGN: left
}
H2 {
	FONT-SIZE: medium
}
PRE {
	FONT-SIZE: x-small; FONT-FAMILY: Courier New, monospace
}
TT {
	FONT-SIZE: x-small; FONT-FAMILY: Courier New, monospace
}

------=_NextPart_000_0040_01C3E128.A692DD10
Content-Type: text/css;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Location: http://www.morearty.com/code.css

@import url( main.css );
A:link {
	COLOR: #25548d
}
H1 {
	COLOR: #25548d
}
H2 {
	COLOR: #25548d
}
A:visited {
	COLOR: #3c5677
}

------=_NextPart_000_0040_01C3E128.A692DD10--
