B0 through B3 (breakpoint condition detected) flags (bits 0 through 3) — Indicates (when set) that its associated breakpoint condition was met when a debug exception was generated . These flags are set if the condition described for each breakpoint by the LENn, and R/Wn flags in debug control register DR7 is true. They are set even if the breakpoint is not enabled by the Ln and Gn flags in register DR7.

#if BX_X86_DEBUGGER

else {

// only bother comparing if any breakpoints enabled and

// debug events are not inhibited on this boundary.

if (! (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG_SHADOW) && ! BX_CPU_THIS_PTR in_repeat) {

if (BX_CPU_THIS_PTR dr7 & 0x000000ff) {

bx_address iaddr = get_laddr(BX_SEG_REG_CS, BX_CPU_THIS_PTR prev_rip);

Bit32u dr6_bits = hwdebug_compare(iaddr, 1, BX_HWDebugInstruction, BX_HWDebugInstruction);

if (dr6_bits) {

// Add to the list of debug events thus far.

BX_CPU_THIS_PTR debug_trap |= dr6_bits;

BX_ERROR(("#DB: x86 code breakpoint catched"));

exception(BX_DB_EXCEPTION, 0, 0); // no error, not interrupt

}

}

}

}

#endif

for (unsigned n=0;n<4;n++) {

bx_address dr_start = BX_CPU_THIS_PTR dr[n] & ~alignment_mask[dr_len[n]];

bx_address dr_end = dr_start + alignment_mask[dr_len[n]];

ibpoint_found_n[n] = 0;



// See if this instruction address matches any breakpoints

if (dr7 & (3 << n*2)) {

if ((dr_op[n]==opa || dr_op[n]==opb) &&

(laddr_0 <= dr_end) &&

(laddr_n >= dr_start)) {

ibpoint_found_n[n] = 1;

ibpoint_found = 1;

}

}

}



// If *any* enabled breakpoints matched, then we need to

// set status bits for *all* breakpoints, even disabled ones,

// as long as they meet the other breakpoint criteria.

// dr6_mask is the return value. These bits represent the bits

// to be OR'd into DR6 as a result of the debug event.

Bit32u dr6_mask = 0;



if (ibpoint_found) {

if (ibpoint_found_n[0]) dr6_mask |= 0x1;

if (ibpoint_found_n[1]) dr6_mask |= 0x2;

if (ibpoint_found_n[2]) dr6_mask |= 0x4;

if (ibpoint_found_n[3]) dr6_mask |= 0x8;

}

Microsoft VirtualPC (detected)



QEMU (not detected)



Sun VirtualBox (not detected)



Laptop (not detected)



Netbook (not detected)



B0 through B3 (breakpoint condition detected) flags (bits 0 through 3) — Indicates (when set) that its associated breakpoint condition was met when a debug exception was generated. These flags are set if the condition described for each breakpoint by the LENn, and R/Wn flags in debug control register DR7 is true. They may or may not be set if the breakpoint is not enabled by the Ln or the Gn flags in register DR7 . Therefore on a #DB, a debug handler should check only those B0-B3 bits which correspond to an enabled breakpoint.

Intel® Core™2 Quad processor Q6000 series

Intel® Xeon® processor 3000, 3200 series

Intel® Xeon® processor 5000 series

Intel® Xeon® processor 5300 series

Intel® Core™2 Extreme processor X7000 and X6800 series

Intel® Core™2 Extreme QX6000 series

Intel® Xeon® processor 7100 series

Intel® Pentium® Dual-Core processor

Intel® Xeon® processor 7200, 7300 series

Intel® Core™2 Extreme QX9000 series

Intel® Xeon® processor 5200, 5400, 7400 series

Intel® CoreTM2 Extreme processor QX9000 and X9000 series

Intel® CoreTM2 Quad processor Q9000 series

Intel® CoreTM2 Duo processor E8000, T9000 series

Intel® AtomTM processor family

Intel® CoreTM i7 processor

Intel® CoreTM i5 processor

This post will be similar to the previous one , and will be about small, but interesting, details of x86 architecture, that might be (and sometimes are) easily overlooked by creators of emulators and virtual machines. The hero of today's post is the DR6 debug register, or, to be more precise, the four least significant bits of this register - B0 to B3 (breakpoint condition detected flags).Let's take a look at the Intel manual (volume 3B):So, this has to be interpreted the following way:1. A debugger exception (int 1) is generated2. For each hardware breakpoint set (0-3) a check is made, and a flag is, or is not setNow, please note, that nothing here is said about checking if a hardware breakpoint set is enabled (register DR7, bits Ln and Gn) before setting the flags (exception generation is another thing).OK, so how many of you guys suspect that some vm/emu authors might interpret it another way: "when a hardware breakpoint is hit, set it's flag in the DR6 register, and generate int1"? Let's check it! :)I'll start with bochs. First of all, as far as I know, bochs default binary distro has the debugging register functionality turned off, so if you would like to test it, a recompilation (detection by DRn not working at all anyone?) will be needed (--enable-x86-debugger option at ./configure).Let's look at the following code:Let's look into the hwdebug_compare funciton:As you can see in the comment, the authors were aware of this detail. However, the code above is invalid - they check at first if the exception is enabled, before checking if the condition was met. So, the comment is OK, but the code is not.Below, you can see a screenshot (click to enlarge) from a proof of concept code:So, seem that bochs can be detected. Now, for some screenshots from other vm/emu's (ignore the interrupt 8 message):And now, so we can compare the output, two photos of real hardware (ASUS laptop with Core 2 Duo, and ASUS EeePC netbook with Intel Atom cpu):Yaay, so we can you this method to detect Bochs and VirtualPC!!!Well... not exactly. The manual I quoted at the beginning of this post is from October 2006. A few days ago a new set of manuals were released (December 2009), and seems something changed:Well, this makes this post useful or not useful. However, as far as I'm concerned, this change is made in the new processors, which are handled by this version of the manual, and are not handled by the previous. These new CPUs are (it's not stated in which of them the change was made):So I guess, the detection needs additional check, to know which CPU it's dealing with.All in all, it was quite fun to play with it ;>