VOGONS


x86 debug registers?

Topic actions

First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

Do the x86 debug registers work while in virtual 8086 mode?
What about in real mode? Is DR6 still updated when a single step trap is thrown (setting bit 14)?
Edit: OK. So DR6 is still updated, even in real mode from what I can learn from Bochs' source code (looking into it's exception handling from the exception() call).
I've adjusted my emulator to do the same.

Real and virtual 8086 mode also get debugged in the same way, although just on the logical address part (like in protected mode), which effectively is the same as a physical address in real mode.

Ran WinDBG, used a debugger command to set the DR register up for an instruction faulting:

Kernel base = 0x807c2000 PsLoadedModuleList = 0x8083ce28
System Uptime: not available
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
* *
* You are seeing this message because you pressed either *
* CTRL+C (if you run kd.exe) or, *
* CTRL+BREAK (if you run WinDBG), *
* on your debugger machine's keyboard. *
* *
* THIS IS NOT A BUG OR A SYSTEM CRASH *
* *
* If you did not intend to break into the debugger, press the "g" key, then *
* press the "Enter" key now. This message might immediately reappear. If it *
* does, press "g" and "Enter" again. *
* *
*******************************************************************************
ntkrnlmp!RtlpBreakWithStatusInstruction:
807e984c cc int 3
kd> t
ntkrnlmp!RtlpBreakWithStatusInstruction+1:
807e984d c20400 ret 0x4
kd> t
ntkrnlmp!ExpInitializeExecutive+310:
80964c28 8b4358 mov eax,[ebx+0x58]
kd> g
Breakpoint 0 hit
ntkrnlmp!ExpInitializeExecutive+316:
80964c2e 7206 jb ntkrnlmp!ExpInitializeExecutive+0x31e (80964c36)
kd> ba e 1 80964c31
kd> t
ntkrnlmp!ExpInitializeExecutive+318:
80964c30 53 push ebx
kd> g
CS descriptor lookup failed
Breakpoint 1 hit
4c31:7000 ?? ???
kd> t

*** Fatal System Error: 0x0000007f
(0x0000000D,0x00000000,0x00000000,0x00000000)


A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

Use !analyzebugcheck -v to get more information.

BugCheck 7F, {d, 0, 0, 0}
*** Bugcheck Analysis may not be correct, please followup with the following.
Followup : MachineOwner

Show last 3 lines
ntkrnlmp!RtlpBreakWithStatusInstruction:
807e984c cc int 3

Although the breakpoint hit correctly, somehow the return address was invalid it look like, leading to a 0x7F bugcheck?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 8, by superfury

User metadata
Rank l33t++
Rank
l33t++

Remade the exception handling code for both interrupts (#DB) and VIP/VIF before an instruction starts.
Now both are crafted again, being based upon the INTA logic (although starting a different interrupt and exception of course).
The only exception in those cases are that that they fault using the normal logic (#DB or #GP) after the initial interrupt start-up logic (which resets state to the start of the executed instruction properly, taking REP-prefixes and savestate etc. into account).

I've also improved the REP-prefix behaviour in this case, as it could be interfering with the above mechanics otherwise (as it was possible resetting the EIP to the instruction beforehand, which is shouldn't, depending on the instruction state).

Said function points (for #DB and #GP) also now properly jump to the correct point in execution, instead of aborting the entire CPU execution handling (which might be incorrect, based on the INTA/NMI/SMI handling startup code I wrote).
Edit: Interesting: the 0x7B 0xD seems to imply a double fault happened.
I've just also applied the same logic to the double fault handler, just in case such a thing happens during instruction fetching (it shouldn't easily, but there's a possibility during interrupt handling, which requires correct behaviour).
Edit: Also added the logic to all other fault handlers, as they might occur when an instruction is started (due to interrupt and fault logic itself triggering at that point), properly resetting state for the fault.
Also added the logic to the SMI/NMI/INTA startup handling, as they require it as well for a consistent state. Basically said function makes sure that the return point of an exception or interrupt-type (SMI/NMI/INTA) returns to the correct spot and state.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 2 of 8, by superfury

User metadata
Rank l33t++
Rank
l33t++

Having fixed the interrupt/fault handling when starting a new instruction, I can now at last set breakpoints (simply a few instructions ahead and performing a "go" command to let it trigger), I now get a proper state when said breakpoint hits.
Although that might also fix all other kinds of interrupts that happen inside various OSes.

Some output from my debugger(WinDBG) that's connected on the serial port (through COM0COM and another UniPCemu instance):

Microsoft (R) Windows Kernel Debugger  Version 3.0.0020.0
Copyright (c) Microsoft Corporation. All rights reserved.

Waiting to reconnect...
Will request initial breakpoint at next boot.
Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Kernel Debugger connection established. (Initial Breakpoint requested)
Loaded dbghelp extension DLL
Loaded ext extension DLL
Loaded exts extension DLL
Loaded kext extension DLL
Loaded kdexts extension DLL
Symbol search path is: c:\windowsxprtm2600\symbols;srv*c:\myserversymbols*https://msdl.microsoft.com/download/symbols;c:\windowsxprtm2600\symbols
Symbol search path is: c:\windowsxprtm2600\symbols;srv*c:\myserversymbols*https://msdl.microsoft.com/download/symbols;c:\windowsxprtm2600\symbols;C:\windowsxprtm2600\symbols;srv*C:\MyServerSymbols*https://msdl.microsoft.com/download/symbols
Executable search path is:
PsLoadedModuleList not initialized yet. Delay kernel load.
Windows XP Kernel Version 2600 MP (1 procs) Free x86 compatible
Built by: 2600.xpclient.010817-1148
Kernel base = 0x807c2000 PsLoadedModuleList = 0x8083ce28
System Uptime: not available
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
* *
* You are seeing this message because you pressed either *
* CTRL+C (if you run kd.exe) or, *
* CTRL+BREAK (if you run WinDBG), *
* on your debugger machine's keyboard. *
* *
* THIS IS NOT A BUG OR A SYSTEM CRASH *
* *
* If you did not intend to break into the debugger, press the "g" key, then *
* press the "Enter" key now. This message might immediately reappear. If it *
* does, press "g" and "Enter" again. *
* *
*******************************************************************************
ntkrnlmp!RtlpBreakWithStatusInstruction:
807e984c cc int 3
kd> !pci 0 1
kd> !pci 1 0
PCI Bus 0
00:0 8086:1237.00 Cmd[0006:.mb...] Sts[0280:.....] Device Host bridge
cf8:80000000 IntPin:0 IntLine:0 Rom:0 cis:0 cap:0

01:0 8086:7000.02 Cmd[000f:imb...] Sts[0200:.....] Device ISA bridge
cf8:80000800 IntPin:0 IntLine:ff Rom:0 cis:0 cap:0

01:1 8086:7010.02 Cmd[0007:imb...] Sts[0000:.....] Device Class:1:1:80
cf8:80000900 IntPin:0 IntLine:ff Rom:0 cis:0 cap:0
IO[4]:e801

0f:0 1283:8888.01 Cmd[0007:imb...] Sts[0000:.....] Device SubID:100c:3203 Other bridge device
cf8:80007800 IntPin:0 IntLine:0 Rom:0 cis:0 cap:0
MEM[0]:e7000000

kd> !pcitree
PciFdoExtensionListHead forward pointer is NULL, list is empty
kd> lm
start end module name
80190000 801b4000 halapic (deferred)
807c2000 809aa000 nt c:\windowsxprtm2600\symbols\exe\ntkrnlmp.pdb
Show last 185 lines
fc0de000 fc160400   ntfs         (deferred)                 
fc161000 fc184580 fastfat (deferred)
fc185000 fc198780 ksecdd (deferred)
fc199000 fc257a80 dmboot (deferred)
fc2f8000 fc323d80 dac2w2k (deferred)
fc324000 fc33ce00 adpu160m (deferred)
fc33d000 fc34fd80 tffsport (deferred)
fc350000 fc365280 atapi (deferred)
fc366000 fc37bf80 scsiport (deferred)
fc37c000 fc39a180 usbport (deferred)
fc39b000 fc3beb80 dmio (deferred)
fc3bf000 fc3dd880 ftdisk (deferred)
fc3de000 fc3fa680 pcmcia (deferred)
fc3fb000 fc426c00 acpi (deferred)
fc427000 fc499d80 setupdd (deferred)
fc4bb000 fc4ca400 pci c:\windowsxprtm2600\symbols\sys\pci.pdb
fc4cb000 fc4d3c00 isapnp (deferred)
fc4db000 fc4e8880 ohci1394 (deferred)
fc4eb000 fc4f7180 1394bus (deferred)
fc4fb000 fc504280 mountmgr (deferred)
fc50b000 fc514280 sbp2port (deferred)
fc51b000 fc523280 lbrtfdc (deferred)
fc52b000 fc537600 usbhub (deferred)
fc53b000 fc543180 hidclass (deferred)
fc54b000 fc55a400 serial (deferred)
fc55b000 fc56ae00 videoprt (deferred)
fc56b000 fc577700 i8042prt (deferred)
fc57b000 fc588e80 aic78xx (deferred)
fc58b000 fc593180 ql10wnt (deferred)
fc59b000 fc5a4e00 ql1240 (deferred)
fc5ab000 fc5b8780 aic78u2 (deferred)
fc5bb000 fc5c3f80 ultra (deferred)
fc5cb000 fc5d4d80 ql1080 (deferred)
fc5db000 fc5e6f80 ql1280 (deferred)
fc5eb000 fc5f6100 ql12160 (deferred)
fc5fb000 fc604500 hpt3xx (deferred)
fc60b000 fc616980 cdrom (deferred)
fc61b000 fc625f80 classpnp (deferred)
fc62b000 fc633380 disk (deferred)
fc63b000 fc64a300 cdfs (deferred)
fc73b000 fc740c80 pciidex (deferred)
fc743000 fc747900 partmgr (deferred)
fc74b000 fc751680 fdc (deferred)
fc753000 fc757a00 usbuhci (deferred)
fc75b000 fc761180 usbccgp (deferred)
fc763000 fc768c80 hidparse (deferred)
fc76b000 fc770500 usbstor (deferred)
fc773000 fc777c80 vga (deferred)
fc77b000 fc780b80 kbdclass (deferred)
fc783000 fc787a80 sparrow (deferred)
fc78b000 fc78f480 i2omp (deferred)
fc793000 fc799780 asc (deferred)
fc79b000 fc79f380 mraid35x (deferred)
fc7a3000 fc7aaf80 symc8xx (deferred)
fc7ab000 fc7b1ee0 sym_hi (deferred)
fc7b3000 fc7ba7e0 sym_u3 (deferred)
fc7bb000 fc7c0780 asc3350p (deferred)
fc7c3000 fc7c8c00 abp480n5 (deferred)
fc7cb000 fc7cfee0 dpti2o (deferred)
fc7d3000 fc7d9aa0 perc2 (deferred)
fc7db000 fc7e1560 hpn (deferred)
fc7e3000 fc7e7d00 flpydisk (deferred)
fc8cb000 fc8ce000 bootvid (deferred)
fc8cf000 fc8d1d80 acpiec (deferred)
fc8d3000 fc8d6d00 usbohci (deferred)
fc8d7000 fc8d9580 hidusb (deferred)
fc8db000 fc8dea80 serenum (deferred)
fc8df000 fc8e2680 kbdhid (deferred)
fc8e3000 fc8e6a80 cpqarray (deferred)
fc8e7000 fc8ea200 aha154x (deferred)
fc8eb000 fc8eef80 symc810 (deferred)
fc8ef000 fc8f2980 dac960nt (deferred)
fc8f3000 fc8f5f00 amsint (deferred)
fc8f7000 fc8faa00 asc3550 (deferred)
fc8fb000 fc8fee80 ini910u (deferred)
fc8ff000 fc902680 cbidf2k (deferred)
fc903000 fc905900 sfloppy (deferred)
fc907000 fc909300 ramdisk (deferred)
fc9bb000 fc9bcb80 kdcom (deferred)
fc9bd000 fc9be100 wmilib (deferred)
fc9bf000 fc9c0200 intelide (deferred)
fc9c1000 fc9c2100 viaide (deferred)
fc9c3000 fc9c4a00 cmdide (deferred)
fc9c5000 fc9c6380 toside (deferred)
fc9c7000 fc9c8480 aliide (deferred)
fc9c9000 fc9ca700 dmload (deferred)
fc9cb000 fc9cc280 usbd (deferred)
fc9cd000 fc9cee00 cd20xrnt (deferred)
fca83000 fca83d80 spddlang (deferred)
fca84000 fca84d80 oprghdlr (deferred)
fca85000 fca85d00 pciide (deferred)

Unloaded modules:

kd> ba e 1 807e984d
kd> g 0xffffffff80964c28
ntkrnlmp!ExpInitializeExecutive+310:
80964c28 8b4358 mov eax,[ebx+0x58]
kd> ba e 1 80964c2e
kd> g
Breakpoint 1 hit
ntkrnlmp!ExpInitializeExecutive+316:
80964c2e 7206 jb ntkrnlmp!ExpInitializeExecutive+0x31e (80964c36)
kd> t
ntkrnlmp!ExpInitializeExecutive+318:
80964c30 53 push ebx
kd> t
ntkrnlmp!ExpInitializeExecutive+319:
80964c31 e8296c0100 call ntkrnlmp!HeadlessInit (8097b85f)
kd> t
ntkrnlmp!HeadlessInit:
8097b85f 55 push ebp
kd> g
Break instruction exception - code 80000003 (first chance)
*******************************************************************************
* *
* You are seeing this message because you pressed either *
* CTRL+C (if you run kd.exe) or, *
* CTRL+BREAK (if you run WinDBG), *
* on your debugger machine's keyboard. *
* *
* THIS IS NOT A BUG OR A SYSTEM CRASH *
* *
* If you did not intend to break into the debugger, press the "g" key, then *
* press the "Enter" key now. This message might immediately reappear. If it *
* does, press "g" and "Enter" again. *
* *
*******************************************************************************
ntkrnlmp!RtlpBreakWithStatusInstruction:
807e984c cc int 3
kd> t
ntkrnlmp!RtlpBreakWithStatusInstruction+1:
807e984d c20400 ret 0x4
kd> t
ntkrnlmp!KeUpdateSystemTime+152:
807efaec ebb3 jmp ntkrnlmp!KeUpdateSystemTime+0x107 (807efaa1)
kd> t
ntkrnlmp!KeUpdateSystemTime+107:
807efaa1 833d1440838000 cmp dword ptr [ntkrnlmp!KiTickOffset (80834014)],0x0
kd> g 0xffffffff801937e2
halapic!HalpReleaseHighLevelLock+2:
801937e2 c3 ret
kd> t
halapic!HalpEnableNMI+5c:
801a7608 5f pop edi
kd> g 0xffffffff801b10d2
halapic!HalInitSystem+434:
801b10d2 b001 mov al,0x1
kd> g 0xffffffff80965298
ntkrnlmp!Phase1Initialization+55:
80965298 84c0 test al,al
kd> t
ntkrnlmp!Phase1Initialization+57:
8096529a 7507 jnz ntkrnlmp!Phase1Initialization+0x60 (809652a3)
kd> t
ntkrnlmp!Phase1Initialization+60:
809652a3 8b4644 mov eax,[esi+0x44]
kd> t
ntkrnlmp!Phase1Initialization+63:
809652a6 3bc3 cmp eax,ebx
kd> t
ntkrnlmp!Phase1Initialization+65:
809652a8 57 push edi
kd> t
ntkrnlmp!Phase1Initialization+66:
809652a9 740b jz ntkrnlmp!Phase1Initialization+0x73 (809652b6)
kd> t
ntkrnlmp!Phase1Initialization+68:
809652ab 50 push eax
kd> t
ntkrnlmp!Phase1Initialization+69:
809652ac e8eba3ebff call ntkrnlmp!_strupr (8081f69c)
kd> p
ntkrnlmp!Phase1Initialization+6e:
809652b1 59 pop ecx
kd> p
ntkrnlmp!Phase1Initialization+6f:
809652b2 8bf8 mov edi,eax
kd> p
ntkrnlmp!Phase1Initialization+71:
809652b4 eb02 jmp ntkrnlmp!Phase1Initialization+0x75 (809652b8)
kd> p
ntkrnlmp!Phase1Initialization+75:
809652b8 3bfb cmp edi,ebx

It seems to behave properly there now. 😁

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member

I have a 386 under Arduino control, if you can conceive of any assembly programs that can test a scenario you want.

I can confirm, however, that the DR7 register is not ignored in real mode - I can hang the CPU by fiddling with the reserved bits like 000004000h

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 4 of 8, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

i have a weird and probably wrong tingling sensation that the debug registers under realmode need to be linearly mapped not to whatever the virtual address is. some old brain memory triggered but I'm probably wrong

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 5 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member
BloodyCactus wrote on 2025-07-31, 23:57:

i have a weird and probably wrong tingling sensation that the debug registers under realmode need to be linearly mapped not to whatever the virtual address is. some old brain memory triggered but I'm probably wrong

how do you "linearly map" a register?

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 6 of 8, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

by that i mean a physical linear/raw address not virtual mapped address.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 7 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member

oh, you're talking about the breakpoints in dr0-dr3?

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 8 of 8, by superfury

User metadata
Rank l33t++
Rank
l33t++

From what I understand, it's always applying at the linear address stage (so after logical address conversion, but before applying paging (if in protected mode and enabled, otherwise it's a physical address (as there is no linear-physical address translation applied))).

Looking at the Bochs source code seems to confirm that.

Managed to set some breakpoints debugging a Windows XP home 2600 CD-ROM boot (Using the usual UniPCemu TCP to UniPCemu, which is connected to COM0COM, where the other serial port on the COM0COM connection is WinDBG that's compatible with the OS required.

Managed to single step and use breakpoint instructions to trap on an address, so the breakpoints should be working (at least in protected mode). I've also removed the condition of it requiring protected mode to apply, thus the breakpoints will apply in virtual 8086 mode (on linear addresses) or real mode (on 'physical' addresses, although effectively performed on linear addresses by my code (the output from the logical to linear address translation, before it's fed into the physical address generation (which takes paging into account)), which aren't translated due to paging being disabled in real mode).

Found some bugs in pre-instruction handling of protection faults. They should be properly operating now (taking the pre-instruction instruction state (things like instruction execution status, REP prefixes being pending to reset etc.) into account properly). If no exception is triggered, stuff like REP still continues the loop, until it either ends normally or throws an exception during execution or pre-instruction.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io