VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCRemoteKd.cpp@ 86327

Last change on this file since 86327 was 86327, checked in by vboxsync, 4 years ago

Debugger: Allow for different I/O providers instead of only TCP

So far TCP was the only option to communicate remotely with the internal debugger, the other option
was to use the console from the GUI directly. This commit reworks basic I/O to allow for different
providers where TCP is just one option. The second one being introduced is an IPC provider using a local
socket or named pipe depending on the platform. This allows for Windows kernel debugging over a pipe
using the KD stub in VirtualBox and WinDbg running on the host (not tested yet).

Furthermore this commit allows multiple stubs to be listening for connections at the same time, so
one can have a GDB stub listening on one TCP port and the native VBox debugger listening on another one
or even using a different I/O provider. Only one session can be active at a time though, because sharing
debugger states is impossible. To configure this the following CFGM keys need to be set for each listener:

"DBGC/<Some unique ID>/Provider" "tcp|ipc"
"DBGC/<Some unique ID>/StubType" "native|gdb|kd"
"DBGC/<Some unique ID>/Address" "<ip>|<local named pipe or socket path>"
"DBGC/<Some unique ID>/Port" "<port>" (for TCP only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 160.2 KB
Line 
1/* $Id: DBGCRemoteKd.cpp 86327 2020-09-28 16:20:50Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Windows Kd Remote Stub.
4 */
5
6/*
7 * Copyright (C) 2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <VBox/dbg.h>
23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/vmapi.h> /* VMR3GetVM() */
25#include <VBox/vmm/hm.h> /* HMR3IsEnabled */
26#include <VBox/vmm/nem.h> /* NEMR3IsEnabled */
27#include <iprt/assertcompile.h>
28#include <iprt/cdefs.h>
29#include <iprt/err.h>
30#include <iprt/list.h>
31#include <iprt/mem.h>
32#include <iprt/sg.h>
33#include <iprt/string.h>
34#include <iprt/time.h>
35#include <iprt/x86.h>
36#include <iprt/formats/pecoff.h>
37#include <iprt/formats/mz.h>
38
39#include <stdlib.h>
40
41#include "DBGCInternal.h"
42
43
44/*********************************************************************************************************************************
45* Defined Constants And Macros *
46*********************************************************************************************************************************/
47
48/** Number of milliseconds we wait for new data to arrive when a new packet was detected. */
49#define DBGC_KD_RECV_TIMEOUT_MS UINT32_C(1000)
50
51/** NT status code - Success. */
52#define NTSTATUS_SUCCESS 0
53/** NT status code - buffer overflow. */
54#define NTSTATUS_BUFFER_OVERFLOW UINT32_C(0x80000005)
55/** NT status code - operation unsuccesful. */
56#define NTSTATUS_UNSUCCESSFUL UINT32_C(0xc0000001)
57/** NT status code - operation not implemented. */
58#define NTSTATUS_NOT_IMPLEMENTED UINT32_C(0xc0000002)
59/** NT status code - Object not found. */
60#define NTSTATUS_NOT_FOUND UINT32_C(0xc0000225)
61
62/** Offset where the KD version block pointer is stored in the KPCR.
63 * From: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kprcb/amd64.htm */
64#define KD_KPCR_VERSION_BLOCK_ADDR_OFF 0x34
65
66
67/*********************************************************************************************************************************
68* Structures and Typedefs *
69*********************************************************************************************************************************/
70
71/**
72 * KD packet header as sent over the wire.
73 */
74typedef struct KDPACKETHDR
75{
76 /** Packet signature (leader) - defines the type of packet. */
77 uint32_t u32Signature;
78 /** Packet (sub) type. */
79 uint16_t u16SubType;
80 /** Size of the packet body in bytes.*/
81 uint16_t cbBody;
82 /** Packet ID. */
83 uint32_t idPacket;
84 /** Checksum of the packet body. */
85 uint32_t u32ChkSum;
86} KDPACKETHDR;
87AssertCompileSize(KDPACKETHDR, 16);
88/** Pointer to a packet header. */
89typedef KDPACKETHDR *PKDPACKETHDR;
90/** Pointer to a const packet header. */
91typedef const KDPACKETHDR *PCKDPACKETHDR;
92
93/** Signature for a data packet. */
94#define KD_PACKET_HDR_SIGNATURE_DATA UINT32_C(0x30303030)
95/** First byte for a data packet header. */
96#define KD_PACKET_HDR_SIGNATURE_DATA_BYTE 0x30
97/** Signature for a control packet. */
98#define KD_PACKET_HDR_SIGNATURE_CONTROL UINT32_C(0x69696969)
99/** First byte for a control packet header. */
100#define KD_PACKET_HDR_SIGNATURE_CONTROL_BYTE 0x69
101/** Signature for a breakin packet. */
102#define KD_PACKET_HDR_SIGNATURE_BREAKIN UINT32_C(0x62626262)
103/** First byte for a breakin packet header. */
104#define KD_PACKET_HDR_SIGNATURE_BREAKIN_BYTE 0x62
105
106/** @name Packet sub types.
107 * @{ */
108#define KD_PACKET_HDR_SUB_TYPE_STATE_CHANGE32 UINT16_C(1)
109#define KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE UINT16_C(2)
110#define KD_PACKET_HDR_SUB_TYPE_DEBUG_IO UINT16_C(3)
111#define KD_PACKET_HDR_SUB_TYPE_ACKNOWLEDGE UINT16_C(4)
112#define KD_PACKET_HDR_SUB_TYPE_RESEND UINT16_C(5)
113#define KD_PACKET_HDR_SUB_TYPE_RESET UINT16_C(6)
114#define KD_PACKET_HDR_SUB_TYPE_STATE_CHANGE64 UINT16_C(7)
115#define KD_PACKET_HDR_SUB_TYPE_POLL_BREAKIN UINT16_C(8)
116#define KD_PACKET_HDR_SUB_TYPE_TRACE_IO UINT16_C(9)
117#define KD_PACKET_HDR_SUB_TYPE_CONTROL_REQUEST UINT16_C(10)
118#define KD_PACKET_HDR_SUB_TYPE_FILE_IO UINT16_C(11)
119#define KD_PACKET_HDR_SUB_TYPE_MAX UINT16_C(12)
120/** @} */
121
122/** Initial packet ID value. */
123#define KD_PACKET_HDR_ID_INITIAL UINT32_C(0x80800800)
124/** Packet ID value after a resync. */
125#define KD_PACKET_HDR_ID_RESET UINT32_C(0x80800000)
126
127/** Trailing byte of a packet. */
128#define KD_PACKET_TRAILING_BYTE 0xaa
129
130
131/** Maximum number of parameters in the exception record. */
132#define KDPACKETEXCP_PARMS_MAX 15
133
134/**
135 * 64bit exception record.
136 */
137typedef struct KDPACKETEXCP64
138{
139 /** The exception code identifying the excpetion. */
140 uint32_t u32ExcpCode;
141 /** Flags associated with the exception. */
142 uint32_t u32ExcpFlags;
143 /** Pointer to a chained exception record. */
144 uint64_t u64PtrExcpRecNested;
145 /** Address where the exception occurred. */
146 uint64_t u64PtrExcpAddr;
147 /** Number of parameters in the exception information array. */
148 uint32_t cExcpParms;
149 /** Alignment. */
150 uint32_t u32Alignment;
151 /** Exception parameters array. */
152 uint64_t au64ExcpParms[KDPACKETEXCP_PARMS_MAX];
153} KDPACKETEXCP64;
154AssertCompileSize(KDPACKETEXCP64, 152);
155/** Pointer to an exception record. */
156typedef KDPACKETEXCP64 *PKDPACKETEXCP64;
157/** Pointer to a const exception record. */
158typedef const KDPACKETEXCP64 *PCKDPACKETEXCP64;
159
160
161/**
162 * amd64 NT context structure.
163 */
164typedef struct NTCONTEXT64
165{
166 /** The P[1-6]Home members. */
167 uint64_t au64PHome[6];
168 /** Context flags indicating the valid bits, see NTCONTEXT_F_XXX. */
169 uint32_t fContext;
170 /** MXCSR register. */
171 uint32_t u32RegMxCsr;
172 /** CS selector. */
173 uint16_t u16SegCs;
174 /** DS selector. */
175 uint16_t u16SegDs;
176 /** ES selector. */
177 uint16_t u16SegEs;
178 /** FS selector. */
179 uint16_t u16SegFs;
180 /** GS selector. */
181 uint16_t u16SegGs;
182 /** SS selector. */
183 uint16_t u16SegSs;
184 /** EFlags register. */
185 uint32_t u32RegEflags;
186 /** DR0 register. */
187 uint64_t u64RegDr0;
188 /** DR1 register. */
189 uint64_t u64RegDr1;
190 /** DR2 register. */
191 uint64_t u64RegDr2;
192 /** DR3 register. */
193 uint64_t u64RegDr3;
194 /** DR6 register. */
195 uint64_t u64RegDr6;
196 /** DR7 register. */
197 uint64_t u64RegDr7;
198 /** RAX register. */
199 uint64_t u64RegRax;
200 /** RCX register. */
201 uint64_t u64RegRcx;
202 /** RDX register. */
203 uint64_t u64RegRdx;
204 /** RBX register. */
205 uint64_t u64RegRbx;
206 /** RSP register. */
207 uint64_t u64RegRsp;
208 /** RBP register. */
209 uint64_t u64RegRbp;
210 /** RSI register. */
211 uint64_t u64RegRsi;
212 /** RDI register. */
213 uint64_t u64RegRdi;
214 /** R8 register. */
215 uint64_t u64RegR8;
216 /** R9 register. */
217 uint64_t u64RegR9;
218 /** R10 register. */
219 uint64_t u64RegR10;
220 /** R11 register. */
221 uint64_t u64RegR11;
222 /** R12 register. */
223 uint64_t u64RegR12;
224 /** R13 register. */
225 uint64_t u64RegR13;
226 /** R14 register. */
227 uint64_t u64RegR14;
228 /** R15 register. */
229 uint64_t u64RegR15;
230 /** RIP register. */
231 uint64_t u64RegRip;
232 /** Extended floating point save area. */
233 X86FXSTATE FxSave;
234 /** AVX(?) vector registers. */
235 RTUINT128U aRegsVec[26];
236 /** Vector control register. */
237 uint64_t u64RegVecCtrl;
238 /** Debug control. */
239 uint64_t u64DbgCtrl;
240 /** @todo */
241 uint64_t u64LastBrToRip;
242 uint64_t u64LastBrFromRip;
243 uint64_t u64LastExcpToRip;
244 uint64_t u64LastExcpFromRip;
245} NTCONTEXT64;
246AssertCompileSize(NTCONTEXT64, 1232);
247AssertCompileMemberOffset(NTCONTEXT64, FxSave, 0x100);
248AssertCompileMemberOffset(NTCONTEXT64, aRegsVec, 0x300);
249/** Pointer to an amd64 NT context. */
250typedef NTCONTEXT64 *PNTCONTEXT64;
251/** Pointer to a const amd64 NT context. */
252typedef const NTCONTEXT64 *PCNTCONTEXT64;
253
254
255/**
256 * 64bit [GI]DT descriptor.
257 */
258typedef struct NTKCONTEXTDESC64
259{
260 /** Alignment. */
261 uint16_t au16Alignment[3];
262 /** Limit. */
263 uint16_t u16Limit;
264 /** Base address. */
265 uint64_t u64PtrBase;
266} NTKCONTEXTDESC64;
267AssertCompileSize(NTKCONTEXTDESC64, 2 * 8);
268/** Pointer to a 64bit [GI]DT descriptor. */
269typedef NTKCONTEXTDESC64 *PNTKCONTEXTDESC64;
270/** Pointer to a const 64bit [GI]DT descriptor. */
271typedef const NTKCONTEXTDESC64 *PCNTKCONTEXTDESC64;
272
273
274/**
275 * Kernel context as queried by KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE
276 */
277typedef struct NTKCONTEXT64
278{
279 /** CR0 register. */
280 uint64_t u64RegCr0;
281 /** CR2 register. */
282 uint64_t u64RegCr2;
283 /** CR3 register. */
284 uint64_t u64RegCr3;
285 /** CR4 register. */
286 uint64_t u64RegCr4;
287 /** DR0 register. */
288 uint64_t u64RegDr0;
289 /** DR1 register. */
290 uint64_t u64RegDr1;
291 /** DR2 register. */
292 uint64_t u64RegDr2;
293 /** DR3 register. */
294 uint64_t u64RegDr3;
295 /** DR6 register. */
296 uint64_t u64RegDr6;
297 /** DR7 register. */
298 uint64_t u64RegDr7;
299 /** GDTR. */
300 NTKCONTEXTDESC64 Gdtr;
301 /** IDTR. */
302 NTKCONTEXTDESC64 Idtr;
303 /** TR register. */
304 uint16_t u16RegTr;
305 /** LDTR register. */
306 uint16_t u16RegLdtr;
307 /** MXCSR register. */
308 uint32_t u32RegMxCsr;
309 /** Debug control. */
310 uint64_t u64DbgCtrl;
311 /** @todo */
312 uint64_t u64LastBrToRip;
313 uint64_t u64LastBrFromRip;
314 uint64_t u64LastExcpToRip;
315 uint64_t u64LastExcpFromRip;
316 /** CR8 register. */
317 uint64_t u64RegCr8;
318 /** GS base MSR register. */
319 uint64_t u64MsrGsBase;
320 /** Kernel GS base MSR register. */
321 uint64_t u64MsrKernelGsBase;
322 /** STAR MSR register. */
323 uint64_t u64MsrStar;
324 /** LSTAR MSR register. */
325 uint64_t u64MsrLstar;
326 /** CSTAR MSR register. */
327 uint64_t u64MsrCstar;
328 /** SFMASK MSR register. */
329 uint64_t u64MsrSfMask;
330 /** XCR0 register. */
331 uint64_t u64RegXcr0;
332 /** Standard context. */
333 NTCONTEXT64 Ctx;
334} NTKCONTEXT64;
335AssertCompileMemberOffset(NTKCONTEXT64, Ctx, 224);
336/** Pointer to an amd64 NT context. */
337typedef NTKCONTEXT64 *PNTKCONTEXT64;
338/** Pointer to a const amd64 NT context. */
339typedef const NTKCONTEXT64 *PCNTKCONTEXT64;
340
341
342/**
343 * 32bit context FPU save area.
344 */
345typedef struct NTCONTEXT32_FPU_SAVE_AREA
346{
347 uint32_t u32CtrlWord;
348 uint32_t u32StatusWord;
349 uint32_t u32TagWord;
350 uint32_t u32ErrorOff;
351 uint32_t u32ErrorSel;
352 uint32_t u32DataOff;
353 uint32_t u32DataSel;
354 uint8_t abRegArea[80];
355 uint32_t u32Cr0Npx;
356} NTCONTEXT32_FPU_SAVE_AREA;
357/** Pointer to an 32bit context FPU save area. */
358typedef NTCONTEXT32_FPU_SAVE_AREA *PNTCONTEXT32_FPU_SAVE_AREA;
359/** Pointer to a const 32bit context FPU save area. */
360typedef const NTCONTEXT32_FPU_SAVE_AREA *PCNTCONTEXT32_FPU_SAVE_AREA;
361
362
363/**
364 * i386 NT context structure.
365 */
366typedef struct NTCONTEXT32
367{
368 /** Context flags indicating the valid bits, see NTCONTEXT_F_XXX. */
369 uint32_t fContext;
370 /** DR0 register. */
371 uint32_t u32RegDr0;
372 /** DR1 register. */
373 uint32_t u32RegDr1;
374 /** DR2 register. */
375 uint32_t u32RegDr2;
376 /** DR3 register. */
377 uint32_t u32RegDr3;
378 /** DR6 register. */
379 uint32_t u32RegDr6;
380 /** DR7 register. */
381 uint32_t u32RegDr7;
382 /** Floating point save area. */
383 NTCONTEXT32_FPU_SAVE_AREA FloatSave;
384 /** GS segment. */
385 uint32_t u32SegGs;
386 /** FS segment. */
387 uint32_t u32SegFs;
388 /** ES segment. */
389 uint32_t u32SegEs;
390 /** DS segment. */
391 uint32_t u32SegDs;
392 /** EDI register. */
393 uint32_t u32RegEdi;
394 /** ESI register. */
395 uint32_t u32RegEsi;
396 /** EBX register. */
397 uint32_t u32RegEbx;
398 /** EDX register. */
399 uint32_t u32RegEdx;
400 /** ECX register. */
401 uint32_t u32RegEcx;
402 /** EAX register. */
403 uint32_t u32RegEax;
404 /** EBP register. */
405 uint32_t u32RegEbp;
406 /** EIP register. */
407 uint32_t u32RegEip;
408 /** CS segment. */
409 uint32_t u32SegCs;
410 /** EFLAGS register. */
411 uint32_t u32RegEflags;
412 /** ESP register. */
413 uint32_t u32RegEsp;
414 /** SS segment. */
415 uint32_t u32SegSs;
416 /** @todo Extended registers */
417 uint8_t abRegsExtended[512];
418} NTCONTEXT32;
419AssertCompileSize(NTCONTEXT32, 716);
420/** Pointer to an i386 NT context. */
421typedef NTCONTEXT32 *PNTCONTEXT32;
422/** Pointer to a const i386 NT context. */
423typedef const NTCONTEXT32 *PCNTCONTEXT32;
424
425
426/**
427 * 32bit [GI]DT descriptor.
428 */
429typedef struct NTKCONTEXTDESC32
430{
431 /** Alignment. */
432 uint16_t u16Alignment;
433 /** Limit. */
434 uint16_t u16Limit;
435 /** Base address. */
436 uint32_t u32PtrBase;
437} NTKCONTEXTDESC32;
438AssertCompileSize(NTKCONTEXTDESC32, 2 * 4);
439/** Pointer to an 32bit [GI]DT descriptor. */
440typedef NTKCONTEXTDESC32 *PNTKCONTEXTDESC32;
441/** Pointer to a const 32bit [GI]DT descriptor. */
442typedef const NTKCONTEXTDESC32 *PCNTKCONTEXTDESC32;
443
444
445/**
446 * 32bit Kernel context as queried by KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE
447 */
448typedef struct NTKCONTEXT32
449{
450 /** CR0 register. */
451 uint32_t u32RegCr0;
452 /** CR2 register. */
453 uint32_t u32RegCr2;
454 /** CR3 register. */
455 uint32_t u32RegCr3;
456 /** CR4 register. */
457 uint32_t u32RegCr4;
458 /** DR0 register. */
459 uint32_t u32RegDr0;
460 /** DR1 register. */
461 uint32_t u32RegDr1;
462 /** DR2 register. */
463 uint32_t u32RegDr2;
464 /** DR3 register. */
465 uint32_t u32RegDr3;
466 /** DR6 register. */
467 uint32_t u32RegDr6;
468 /** DR7 register. */
469 uint32_t u32RegDr7;
470 /** GDTR. */
471 NTKCONTEXTDESC32 Gdtr;
472 /** IDTR. */
473 NTKCONTEXTDESC32 Idtr;
474 /** TR register. */
475 uint16_t u16RegTr;
476 /** LDTR register. */
477 uint16_t u16RegLdtr;
478 /** Padding. */
479 uint8_t abPad[24];
480} NTKCONTEXT32;
481AssertCompileSize(NTKCONTEXT32, 84);
482/** Pointer to an i386 NT context. */
483typedef NTKCONTEXT32 *PNTKCONTEXT32;
484/** Pointer to a const i386 NT context. */
485typedef const NTKCONTEXT32 *PCNTKCONTEXT32;
486
487
488/** x86 context. */
489#define NTCONTEXT_F_X86 UINT32_C(0x00010000)
490/** AMD64 context. */
491#define NTCONTEXT_F_AMD64 UINT32_C(0x00100000)
492/** Control registers valid (CS, (R)SP, (R)IP, FLAGS and BP). */
493#define NTCONTEXT_F_CONTROL RT_BIT_32(0)
494/** Integer registers valid. */
495#define NTCONTEXT_F_INTEGER RT_BIT_32(1)
496/** Segment registers valid. */
497#define NTCONTEXT_F_SEGMENTS RT_BIT_32(2)
498/** Floating point registers valid. */
499#define NTCONTEXT_F_FLOATING_POINT RT_BIT_32(3)
500/** Debug registers valid. */
501#define NTCONTEXT_F_DEBUG RT_BIT_32(4)
502/** Extended registers valid (x86 only). */
503#define NTCONTEXT_F_EXTENDED RT_BIT_32(5)
504/** Full x86 context valid. */
505#define NTCONTEXT32_F_FULL (NTCONTEXT_F_X86 | NTCONTEXT_F_CONTROL | NTCONTEXT_F_INTEGER | NTCONTEXT_F_SEGMENTS)
506/** Full amd64 context valid. */
507#define NTCONTEXT64_F_FULL (NTCONTEXT_F_AMD64 | NTCONTEXT_F_CONTROL | NTCONTEXT_F_INTEGER | NTCONTEXT_F_SEGMENTS)
508
509
510/**
511 * 32bit exception record.
512 */
513typedef struct KDPACKETEXCP32
514{
515 /** The exception code identifying the excpetion. */
516 uint32_t u32ExcpCode;
517 /** Flags associated with the exception. */
518 uint32_t u32ExcpFlags;
519 /** Pointer to a chained exception record. */
520 uint32_t u32PtrExcpRecNested;
521 /** Address where the exception occurred. */
522 uint32_t u32PtrExcpAddr;
523 /** Number of parameters in the exception information array. */
524 uint32_t cExcpParms;
525 /** Exception parameters array. */
526 uint32_t au32ExcpParms[KDPACKETEXCP_PARMS_MAX];
527} KDPACKETEXCP32;
528AssertCompileSize(KDPACKETEXCP32, 80);
529/** Pointer to an exception record. */
530typedef KDPACKETEXCP32 *PKDPACKETEXCP32;
531/** Pointer to a const exception record. */
532typedef const KDPACKETEXCP32 *PCKDPACKETEXCP32;
533
534
535/** @name Exception codes.
536 * @{ */
537/** A breakpoint was hit. */
538#define KD_PACKET_EXCP_CODE_BKPT UINT32_C(0x80000003)
539/** An instruction was single stepped. */
540#define KD_PACKET_EXCP_CODE_SINGLE_STEP UINT32_C(0x80000004)
541/** @} */
542
543
544/** Maximum number of bytes in the instruction stream. */
545#define KD_PACKET_CTRL_REPORT_INSN_STREAM_MAX 16
546
547/**
548 * 64bit control report record.
549 */
550typedef struct KDPACKETCTRLREPORT64
551{
552 /** Value of DR6. */
553 uint64_t u64RegDr6;
554 /** Value of DR7. */
555 uint64_t u64RegDr7;
556 /** EFLAGS. */
557 uint32_t u32RegEflags;
558 /** Number of instruction bytes in the instruction stream. */
559 uint16_t cbInsnStream;
560 /** Report flags. */
561 uint16_t fFlags;
562 /** The instruction stream. */
563 uint8_t abInsn[KD_PACKET_CTRL_REPORT_INSN_STREAM_MAX];
564 /** CS selector. */
565 uint16_t u16SegCs;
566 /** DS selector. */
567 uint16_t u16SegDs;
568 /** ES selector. */
569 uint16_t u16SegEs;
570 /** FS selector. */
571 uint16_t u16SegFs;
572} KDPACKETCTRLREPORT64;
573AssertCompileSize(KDPACKETCTRLREPORT64, 2 * 8 + 4 + 2 * 2 + 16 + 4 * 2);
574/** Pointer to a control report record. */
575typedef KDPACKETCTRLREPORT64 *PKDPACKETCTRLREPORT64;
576/** Pointer to a const control report record. */
577typedef const KDPACKETCTRLREPORT64 *PCKDPACKETCTRLREPORT64;
578
579
580/**
581 * 64bit state change packet body.
582 */
583typedef struct KDPACKETSTATECHANGE64
584{
585 /** The new state. */
586 uint32_t u32StateNew;
587 /** The processor level. */
588 uint16_t u16CpuLvl;
589 /** The processor ID generating the state change. */
590 uint16_t idCpu;
591 /** Number of processors in the system. */
592 uint32_t cCpus;
593 /** Alignment. */
594 uint32_t u32Alignment;
595 /** The thread ID currently executing when the state change occurred. */
596 uint64_t idThread;
597 /** Program counter of the thread. */
598 uint64_t u64RipThread;
599 /** Data based on the state. */
600 union
601 {
602 /** Exception occurred data. */
603 struct
604 {
605 /** The exception record. */
606 KDPACKETEXCP64 ExcpRec;
607 /** First chance(?). */
608 uint32_t u32FirstChance;
609 } Exception;
610 } u;
611 /** The control report */
612 union
613 {
614 /** AMD64 control report. */
615 KDPACKETCTRLREPORT64 Amd64;
616 } uCtrlReport;
617} KDPACKETSTATECHANGE64;
618//AssertCompileSize(KDPACKETSTATECHANGE64, 4 + 2 * 2 + 2 * 4 + 2 * 8 + sizeof(KDPACKETEXCP64) + 4 + sizeof(KDPACKETCTRLREPORT64));
619/** Pointer to a 64bit state change packet body. */
620typedef KDPACKETSTATECHANGE64 *PKDPACKETSTATECHANGE64;
621/** Pointer to a const 64bit state change packet body. */
622typedef const KDPACKETSTATECHANGE64 *PCKDPACKETSTATECHANGE64;
623
624
625/** @name State change state types.
626 * @{ */
627/** Minimum state change type. */
628#define KD_PACKET_STATE_CHANGE_MIN UINT32_C(0x00003030)
629/** An exception occured. */
630#define KD_PACKET_STATE_CHANGE_EXCEPTION KD_PACKET_STATE_CHANGE_MIN
631/** Symbols were loaded(?). */
632#define KD_PACKET_STATE_CHANGE_LOAD_SYMBOLS UINT32_C(0x00003031)
633/** Command string (custom command was executed?). */
634#define KD_PACKET_STATE_CHANGE_CMD_STRING UINT32_C(0x00003032)
635/** Maximum state change type (exclusive). */
636#define KD_PACKET_STATE_CHANGE_MAX UINT32_C(0x00003033)
637/** @} */
638
639
640/**
641 * Debug I/O payload.
642 */
643typedef struct KDPACKETDEBUGIO
644{
645 /** Debug I/O payload type (KD_PACKET_DEBUG_IO_STRING). */
646 uint32_t u32Type;
647 /** The processor level. */
648 uint16_t u16CpuLvl;
649 /** The processor ID generating this packet. */
650 uint16_t idCpu;
651 /** Type dependent data. */
652 union
653 {
654 /** Debug string sent. */
655 struct
656 {
657 /** Length of the string following in bytes. */
658 uint32_t cbStr;
659 /** Some padding it looks like. */
660 uint32_t u32Pad;
661 } Str;
662 /** Debug prompt. */
663 struct
664 {
665 /** Length of prompt. */
666 uint32_t cbPrompt;
667 /** Size of the string returned on success. */
668 uint32_t cbReturn;
669 } Prompt;
670 } u;
671} KDPACKETDEBUGIO;
672AssertCompileSize(KDPACKETDEBUGIO, 16);
673/** Pointer to a Debug I/O payload. */
674typedef KDPACKETDEBUGIO *PKDPACKETDEBUGIO;
675/** Pointer to a const Debug I/O payload. */
676typedef const KDPACKETDEBUGIO *PCKDPACKETDEBUGIO;
677
678
679/** @name Debug I/O types.
680 * @{ */
681/** Debug string output (usually DbgPrint() and friends). */
682#define KD_PACKET_DEBUG_IO_STRING UINT32_C(0x00003230)
683/** Get debug string (DbgPrompt()). */
684#define KD_PACKET_DEBUG_IO_GET_STRING UINT32_C(0x00003231)
685/** @} */
686
687
688/**
689 * 64bit get version manipulate payload.
690 */
691typedef struct KDPACKETMANIPULATE_GETVERSION64
692{
693 /** Major version. */
694 uint16_t u16VersMaj;
695 /** Minor version. */
696 uint16_t u16VersMin;
697 /** Protocol version. */
698 uint8_t u8VersProtocol;
699 /** KD secondary version. */
700 uint8_t u8VersKdSecondary;
701 /** Flags. */
702 uint16_t fFlags;
703 /** Machine type. */
704 uint16_t u16MachineType;
705 /** Maximum packet type. */
706 uint8_t u8MaxPktType;
707 /** Maximum state change */
708 uint8_t u8MaxStateChange;
709 /** Maximum manipulate request ID. */
710 uint8_t u8MaxManipulate;
711 /** Some simulation flag. */
712 uint8_t u8Simulation;
713 /** Padding. */
714 uint16_t u16Padding;
715 /** Kernel base. */
716 uint64_t u64PtrKernBase;
717 /** Pointer of the loaded module list head. */
718 uint64_t u64PtrPsLoadedModuleList;
719 /** Pointer of the debugger data list. */
720 uint64_t u64PtrDebuggerDataList;
721} KDPACKETMANIPULATE_GETVERSION64;
722AssertCompileSize(KDPACKETMANIPULATE_GETVERSION64, 40);
723/** Pointer to a 64bit get version manipulate payload. */
724typedef KDPACKETMANIPULATE_GETVERSION64 *PKDPACKETMANIPULATE_GETVERSION64;
725/** Pointer to a const 64bit get version manipulate payload. */
726typedef const KDPACKETMANIPULATE_GETVERSION64 *PCKDPACKETMANIPULATE_GETVERSION64;
727
728
729/** @name Get version flags.
730 * @{ */
731/** Flag whether this is a multi processor kernel. */
732#define KD_PACKET_MANIPULATE64_GET_VERSION_F_MP RT_BIT_32(0)
733/** Flag whether the pointer is 64bit. */
734#define KD_PACKET_MANIPULATE64_GET_VERSION_F_PTR64 RT_BIT_32(2)
735/** @} */
736
737
738/**
739 * 64bit memory transfer manipulate payload.
740 */
741typedef struct KDPACKETMANIPULATE_XFERMEM64
742{
743 /** Target base address. */
744 uint64_t u64PtrTarget;
745 /** Requested number of bytes to transfer*/
746 uint32_t cbXferReq;
747 /** Number of bytes actually transferred (response). */
748 uint32_t cbXfered;
749 /** Some padding?. */
750 uint64_t au64Pad[3];
751} KDPACKETMANIPULATE_XFERMEM64;
752AssertCompileSize(KDPACKETMANIPULATE_XFERMEM64, 40);
753/** Pointer to a 64bit memory transfer manipulate payload. */
754typedef KDPACKETMANIPULATE_XFERMEM64 *PKDPACKETMANIPULATE_XFERMEM64;
755/** Pointer to a const 64bit memory transfer manipulate payload. */
756typedef const KDPACKETMANIPULATE_XFERMEM64 *PCKDPACKETMANIPULATE_XFERMEM64;
757
758
759/**
760 * 64bit control space transfer manipulate payload.
761 *
762 * @note Same layout as the memory transfer but the pointer has a different meaning so
763 * we moved it into a separate request structure.
764 */
765typedef struct KDPACKETMANIPULATE_XFERCTRLSPACE64
766{
767 /** Identifier of the item to transfer in the control space. */
768 uint64_t u64IdXfer;
769 /** Requested number of bytes to transfer*/
770 uint32_t cbXferReq;
771 /** Number of bytes actually transferred (response). */
772 uint32_t cbXfered;
773 /** Some padding?. */
774 uint64_t au64Pad[3];
775} KDPACKETMANIPULATE_XFERCTRLSPACE64;
776AssertCompileSize(KDPACKETMANIPULATE_XFERCTRLSPACE64, 40);
777/** Pointer to a 64bit memory transfer manipulate payload. */
778typedef KDPACKETMANIPULATE_XFERCTRLSPACE64 *PKDPACKETMANIPULATE_XFERCTRLSPACE64;
779/** Pointer to a const 64bit memory transfer manipulate payload. */
780typedef const KDPACKETMANIPULATE_XFERCTRLSPACE64 *PCKDPACKETMANIPULATE_XFERCTRLSPACE64;
781
782
783/** @name Known control space identifiers.
784 * @{ */
785/** Read/Write KPCR address. */
786#define KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCR UINT64_C(0)
787/** Read/Write KPCRB address. */
788#define KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCRB UINT64_C(1)
789/** Read/Write Kernel context. */
790#define KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KCTX UINT64_C(2)
791/** Read/Write current kernel thread. */
792#define KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KTHRD UINT64_C(3)
793/** @} */
794
795
796/**
797 * 64bit restore breakpoint manipulate payload.
798 */
799typedef struct KDPACKETMANIPULATE_RESTOREBKPT64
800{
801 /** The breakpoint handle to restore. */
802 uint32_t u32HndBkpt;
803 /** Blows up the request to the required size. */
804 uint8_t abPad[36];
805} KDPACKETMANIPULATE_RESTOREBKPT64;
806AssertCompileSize(KDPACKETMANIPULATE_RESTOREBKPT64, 40);
807/** Pointer to a 64bit restore breakpoint manipulate payload. */
808typedef KDPACKETMANIPULATE_RESTOREBKPT64 *PKDPACKETMANIPULATE_RESTOREBKPT64;
809/** Pointer to a const 64bit restore breakpoint manipulate payload. */
810typedef const KDPACKETMANIPULATE_RESTOREBKPT64 *PCKDPACKETMANIPULATE_RESTOREBKPT64;
811
812
813/**
814 * 64bit write breakpoint manipulate payload.
815 */
816typedef struct KDPACKETMANIPULATE_WRITEBKPT64
817{
818 /** Where to write the breakpoint. */
819 uint64_t u64PtrBkpt;
820 /** The breakpoint handle returned in the response. */
821 uint32_t u32HndBkpt;
822 /** Blows up the request to the required size. */
823 uint8_t abPad[28];
824} KDPACKETMANIPULATE_WRITEBKPT64;
825AssertCompileSize(KDPACKETMANIPULATE_WRITEBKPT64, 40);
826/** Pointer to a 64bit write breakpoint manipulate payload. */
827typedef KDPACKETMANIPULATE_WRITEBKPT64 *PKDPACKETMANIPULATE_WRITEBKPT64;
828/** Pointer to a const 64bit write breakpoint manipulate payload. */
829typedef const KDPACKETMANIPULATE_WRITEBKPT64 *PCKDPACKETMANIPULATE_WRITEBKPT64;
830
831
832/**
833 * Context extended manipulate payload.
834 */
835typedef struct KDPACKETMANIPULATE_CONTEXTEX
836{
837 /** Where to start copying the context. */
838 uint32_t offStart;
839 /** Number of bytes to transfer. */
840 uint32_t cbXfer;
841 /** Number of bytes actually transfered. */
842 uint32_t cbXfered;
843 /** Blows up the request to the required size. */
844 uint8_t abPad[28];
845} KDPACKETMANIPULATE_CONTEXTEX;
846AssertCompileSize(KDPACKETMANIPULATE_CONTEXTEX, 40);
847/** Pointer to a context extended manipulate payload. */
848typedef KDPACKETMANIPULATE_CONTEXTEX *PKDPACKETMANIPULATE_CONTEXTEX;
849/** Pointer to a const context extended manipulate payload. */
850typedef const KDPACKETMANIPULATE_CONTEXTEX *PCKDPACKETMANIPULATE_CONTEXTEX;
851
852
853/**
854 * Continue manipulate payload.
855 */
856typedef struct KDPACKETMANIPULATE_CONTINUE
857{
858 /** Continue (status?). */
859 uint32_t u32NtContSts;
860 /** Blows up the request to the required size. */
861 uint8_t abPad[36];
862} KDPACKETMANIPULATE_CONTINUE;
863AssertCompileSize(KDPACKETMANIPULATE_CONTINUE, 40);
864/** Pointer to a continue manipulate payload. */
865typedef KDPACKETMANIPULATE_CONTINUE *PKDPACKETMANIPULATE_CONTINUE;
866/** Pointer to a const continue manipulate payload. */
867typedef const KDPACKETMANIPULATE_CONTINUE *PCKDPACKETMANIPULATE_CONTINUE;
868
869
870/**
871 * Continue 2 manipulate payload.
872 */
873typedef struct KDPACKETMANIPULATE_CONTINUE2
874{
875 /** Continue (status?). */
876 uint32_t u32NtContSts;
877 /** Trace flag. */
878 uint32_t fTrace;
879 /** Bitsize dependent data. */
880 union
881 {
882 /** 32bit. */
883 struct
884 {
885 /** DR7 value to continue with. */
886 uint32_t u32RegDr7;
887 /** @todo (?) */
888 uint32_t u32SymCurStart;
889 uint32_t u32SymCurEnd;
890 } x86;
891 /** 64bit. */
892 struct
893 {
894 /** DR7 value to continue with. */
895 uint64_t u64RegDr7;
896 /** @todo (?) */
897 uint64_t u64SymCurStart;
898 uint64_t u64SymCurEnd;
899 } amd64;
900 } u;
901 /** Blows up the request to the required size. */
902 uint8_t abPad[8];
903} KDPACKETMANIPULATE_CONTINUE2;
904AssertCompileSize(KDPACKETMANIPULATE_CONTINUE2, 40);
905/** Pointer to a continue 2 manipulate payload. */
906typedef KDPACKETMANIPULATE_CONTINUE2 *PKDPACKETMANIPULATE_CONTINUE2;
907/** Pointer to a const continue 2 manipulate payload. */
908typedef const KDPACKETMANIPULATE_CONTINUE2 *PCKDPACKETMANIPULATE_CONTINUE2;
909
910
911/**
912 * Set context manipulate payload.
913 */
914typedef struct KDPACKETMANIPULATE_SETCONTEXT
915{
916 /** Continue (status?). */
917 uint32_t u32CtxFlags;
918 /** Blows up the request to the required size. */
919 uint8_t abPad[36];
920} KDPACKETMANIPULATE_SETCONTEXT;
921AssertCompileSize(KDPACKETMANIPULATE_SETCONTEXT, 40);
922/** Pointer to a set context manipulate payload. */
923typedef KDPACKETMANIPULATE_SETCONTEXT *PKDPACKETMANIPULATE_SETCONTEXT;
924/** Pointer to a const set context manipulate payload. */
925typedef const KDPACKETMANIPULATE_SETCONTEXT *PCKDPACKETMANIPULATE_SETCONTEXT;
926
927
928/**
929 * Query memory properties payload.
930 */
931typedef struct KDPACKETMANIPULATE_QUERYMEMORY
932{
933 /** The address to query the properties for. */
934 uint64_t u64GCPtr;
935 /** Reserved. */
936 uint64_t u64Rsvd;
937 /** Address space type on return. */
938 uint32_t u32AddrSpace;
939 /** Protection flags. */
940 uint32_t u32Flags;
941 /** Blows up the request to the required size. */
942 uint8_t abPad[16];
943} KDPACKETMANIPULATE_QUERYMEMORY;
944AssertCompileSize(KDPACKETMANIPULATE_QUERYMEMORY, 40);
945/** Pointer to a query memory properties payload. */
946typedef KDPACKETMANIPULATE_QUERYMEMORY *PKDPACKETMANIPULATE_QUERYMEMORY;
947/** Pointer to a const query memory properties payload. */
948typedef const KDPACKETMANIPULATE_QUERYMEMORY *PCKDPACKETMANIPULATE_QUERYMEMORY;
949
950
951/** @name Query memory address space identifiers.
952 * @{ */
953/** Process memory space. */
954#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_SPACE_PROCESS UINT32_C(0)
955/** Session memory space. */
956#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_SPACE_SESSION UINT32_C(1)
957/** Kernel memory space. */
958#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_SPACE_KERNEL UINT32_C(2)
959/** @} */
960
961
962/** @name Query memory address protection flags.
963 * @{ */
964/** Readable. */
965#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_READ RT_BIT_32(0)
966/** Writable. */
967#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_WRITE RT_BIT_32(1)
968/** Executable. */
969#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_EXEC RT_BIT_32(2)
970/** Fixed address. */
971#define KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_FIXED RT_BIT_32(3)
972/** @} */
973
974
975/**
976 * Search memory payload.
977 */
978typedef struct KDPACKETMANIPULATE_SEARCHMEMORY
979{
980 /** The address to start searching at on input, found address on output. */
981 uint64_t u64GCPtr;
982 /** Number of bytes to search. */
983 uint64_t cbSearch;
984 /** Length of the pattern to search for following the payload. */
985 uint32_t cbPattern;
986 /** Padding to the required size. */
987 uint32_t au32Pad[5];
988} KDPACKETMANIPULATE_SEARCHMEMORY;
989AssertCompileSize(KDPACKETMANIPULATE_SEARCHMEMORY, 40);
990/** Pointer to a search memory properties payload. */
991typedef KDPACKETMANIPULATE_SEARCHMEMORY *PKDPACKETMANIPULATE_SEARCHMEMORY;
992/** Pointer to a const search memory properties payload. */
993typedef const KDPACKETMANIPULATE_SEARCHMEMORY *PCKDPACKETMANIPULATE_SEARCHMEMORY;
994
995
996/**
997 * Manipulate request packet header (Same for 32bit and 64bit).
998 */
999typedef struct KDPACKETMANIPULATEHDR
1000{
1001 /** The request to execute. */
1002 uint32_t idReq;
1003 /** The processor level to execute the request on. */
1004 uint16_t u16CpuLvl;
1005 /** The processor ID to execute the request on. */
1006 uint16_t idCpu;
1007 /** Return status code. */
1008 uint32_t u32NtStatus;
1009 /** Alignment. */
1010 uint32_t u32Alignment;
1011} KDPACKETMANIPULATEHDR;
1012AssertCompileSize(KDPACKETMANIPULATEHDR, 3 * 4 + 2 * 2);
1013/** Pointer to a manipulate request packet header. */
1014typedef KDPACKETMANIPULATEHDR *PKDPACKETMANIPULATEHDR;
1015/** Pointer to a const manipulate request packet header. */
1016typedef const KDPACKETMANIPULATEHDR *PCPKDPACKETMANIPULATEHDR;
1017
1018
1019/**
1020 * 64bit manipulate state request packet.
1021 */
1022typedef struct KDPACKETMANIPULATE64
1023{
1024 /** Header. */
1025 KDPACKETMANIPULATEHDR Hdr;
1026 /** Request payloads. */
1027 union
1028 {
1029 /** Get Version. */
1030 KDPACKETMANIPULATE_GETVERSION64 GetVersion;
1031 /** Read/Write memory. */
1032 KDPACKETMANIPULATE_XFERMEM64 XferMem;
1033 /** Continue. */
1034 KDPACKETMANIPULATE_CONTINUE Continue;
1035 /** Continue2. */
1036 KDPACKETMANIPULATE_CONTINUE2 Continue2;
1037 /** Set context. */
1038 KDPACKETMANIPULATE_SETCONTEXT SetContext;
1039 /** Read/Write control space. */
1040 KDPACKETMANIPULATE_XFERCTRLSPACE64 XferCtrlSpace;
1041 /** Restore breakpoint. */
1042 KDPACKETMANIPULATE_RESTOREBKPT64 RestoreBkpt;
1043 /** Write breakpoint. */
1044 KDPACKETMANIPULATE_WRITEBKPT64 WriteBkpt;
1045 /** Context extended. */
1046 KDPACKETMANIPULATE_CONTEXTEX ContextEx;
1047 /** Query memory. */
1048 KDPACKETMANIPULATE_QUERYMEMORY QueryMemory;
1049 /** Search memory. */
1050 KDPACKETMANIPULATE_SEARCHMEMORY SearchMemory;
1051 } u;
1052} KDPACKETMANIPULATE64;
1053AssertCompileSize(KDPACKETMANIPULATE64, 16 + 40);
1054/** Pointer to a 64bit manipulate state request packet. */
1055typedef KDPACKETMANIPULATE64 *PKDPACKETMANIPULATE64;
1056/** Pointer to a const 64bit manipulate state request packet. */
1057typedef const KDPACKETMANIPULATE64 *PCKDPACKETMANIPULATE64;
1058
1059/** @name Manipulate requests.
1060 * @{ */
1061/** Minimum available request. */
1062#define KD_PACKET_MANIPULATE_REQ_MIN UINT32_C(0x00003130)
1063/** Read virtual memory request. */
1064#define KD_PACKET_MANIPULATE_REQ_READ_VIRT_MEM KD_PACKET_MANIPULATE_REQ_MIN
1065/** Write virtual memory request. */
1066#define KD_PACKET_MANIPULATE_REQ_WRITE_VIRT_MEM UINT32_C(0x00003131)
1067/** Get context request. */
1068#define KD_PACKET_MANIPULATE_REQ_GET_CONTEXT UINT32_C(0x00003132)
1069/** Set context request. */
1070#define KD_PACKET_MANIPULATE_REQ_SET_CONTEXT UINT32_C(0x00003133)
1071/** Write breakpoint request. */
1072#define KD_PACKET_MANIPULATE_REQ_WRITE_BKPT UINT32_C(0x00003134)
1073/** Restore breakpoint request. */
1074#define KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT UINT32_C(0x00003135)
1075/** Continue request. */
1076#define KD_PACKET_MANIPULATE_REQ_CONTINUE UINT32_C(0x00003136)
1077/** Read control space request. */
1078#define KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE UINT32_C(0x00003137)
1079/** Write control space request. */
1080#define KD_PACKET_MANIPULATE_REQ_WRITE_CTRL_SPACE UINT32_C(0x00003138)
1081/** Read I/O space request. */
1082#define KD_PACKET_MANIPULATE_REQ_READ_IO_SPACE UINT32_C(0x00003139)
1083/** Write I/O space request. */
1084#define KD_PACKET_MANIPULATE_REQ_WRITE_IO_SPACE UINT32_C(0x0000313a)
1085/** Reboot request. */
1086#define KD_PACKET_MANIPULATE_REQ_REBOOT UINT32_C(0x0000313b)
1087/** continue 2nd version request. */
1088#define KD_PACKET_MANIPULATE_REQ_CONTINUE2 UINT32_C(0x0000313c)
1089/** Read physical memory request. */
1090#define KD_PACKET_MANIPULATE_REQ_READ_PHYS_MEM UINT32_C(0x0000313d)
1091/** Write physical memory request. */
1092#define KD_PACKET_MANIPULATE_REQ_WRITE_PHYS_MEM UINT32_C(0x0000313e)
1093/** Query special calls request. */
1094#define KD_PACKET_MANIPULATE_REQ_QUERY_SPEC_CALLS UINT32_C(0x0000313f)
1095/** Set special calls request. */
1096#define KD_PACKET_MANIPULATE_REQ_SET_SPEC_CALLS UINT32_C(0x00003140)
1097/** Clear special calls request. */
1098#define KD_PACKET_MANIPULATE_REQ_CLEAR_SPEC_CALLS UINT32_C(0x00003141)
1099/** Set internal breakpoint request. */
1100#define KD_PACKET_MANIPULATE_REQ_SET_INTERNAL_BKPT UINT32_C(0x00003142)
1101/** Get internal breakpoint request. */
1102#define KD_PACKET_MANIPULATE_REQ_GET_INTERNAL_BKPT UINT32_C(0x00003143)
1103/** Read I/O space extended request. */
1104#define KD_PACKET_MANIPULATE_REQ_READ_IO_SPACE_EX UINT32_C(0x00003144)
1105/** Write I/O space extended request. */
1106#define KD_PACKET_MANIPULATE_REQ_WRITE_IO_SPACE_EX UINT32_C(0x00003145)
1107/** Get version request. */
1108#define KD_PACKET_MANIPULATE_REQ_GET_VERSION UINT32_C(0x00003146)
1109/** Write breakpoint extended request. */
1110#define KD_PACKET_MANIPULATE_REQ_WRITE_BKPT_EX UINT32_C(0x00003147)
1111/** Restore breakpoint extended request. */
1112#define KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT_EX UINT32_C(0x00003148)
1113/** Cause a bugcheck request. */
1114#define KD_PACKET_MANIPULATE_REQ_CAUSE_BUGCHECK UINT32_C(0x00003149)
1115/** Cause a bugcheck request. */
1116#define KD_PACKET_MANIPULATE_REQ_SWITCH_PROCESSOR UINT32_C(0x00003150)
1117/** @todo */
1118/** Search memory for a pattern request. */
1119#define KD_PACKET_MANIPULATE_REQ_SEARCH_MEMORY UINT32_C(0x00003156)
1120/** @todo */
1121/** Clear all internal breakpoints request. */
1122#define KD_PACKET_MANIPULATE_REQ_CLEAR_ALL_INTERNAL_BKPT UINT32_C(0x0000315a)
1123/** Fill memory. */
1124#define KD_PACKET_MANIPULATE_REQ_FILL_MEMORY UINT32_C(0x0000315b)
1125/** Query memory properties. */
1126#define KD_PACKET_MANIPULATE_REQ_QUERY_MEMORY UINT32_C(0x0000315c)
1127/** @todo */
1128/** Get context extended request. */
1129#define KD_PACKET_MANIPULATE_REQ_GET_CONTEXT_EX UINT32_C(0x0000315f)
1130/** @todo */
1131/** Maximum available request (exclusive). */
1132#define KD_PACKET_MANIPULATE_REQ_MAX UINT32_C(0x00003161)
1133/** @} */
1134
1135/**
1136 * KD stub receive state.
1137 */
1138typedef enum KDRECVSTATE
1139{
1140 /** Invalid state. */
1141 KDRECVSTATE_INVALID = 0,
1142 /** Receiving the first byte of the packet header. */
1143 KDRECVSTATE_PACKET_HDR_FIRST_BYTE,
1144 /** Receiving the second byte of the packet header. */
1145 KDRECVSTATE_PACKET_HDR_SECOND_BYTE,
1146 /** Receiving the header. */
1147 KDRECVSTATE_PACKET_HDR,
1148 /** Receiving the packet body. */
1149 KDRECVSTATE_PACKET_BODY,
1150 /** Receiving the trailing byte. */
1151 KDRECVSTATE_PACKET_TRAILER,
1152 /** Blow up the enum to 32bits for easier alignment of members in structs. */
1153 KDRECVSTATE_32BIT_HACK = 0x7fffffff
1154} KDRECVSTATE;
1155
1156
1157/**
1158 * KD emulated hardware breakpoint.
1159 */
1160typedef struct KDCTXHWBP
1161{
1162 /** The DBGF breakpoint handle if active, UINT32_MAX if not active. */
1163 uint32_t iDbgfBp;
1164 /** The linear address of the breakpoint if active. */
1165 RTGCPTR GCPtrBp;
1166 /** Access type of the breakpoint, see X86_DR7_RW_*. */
1167 uint8_t fAcc;
1168 /** Length flags of the breakpoint. */
1169 uint8_t fLen;
1170 /** Flag whether it is a local breakpoint. */
1171 bool fLocal;
1172 /** Flag whether it is a global breakpoint. */
1173 bool fGlobal;
1174 /** Flag whether the breakpoint has triggered since the last time of the reset. */
1175 bool fTriggered;
1176} KDCTXHWBP;
1177/** Pointer to an emulated hardware breakpoint. */
1178typedef KDCTXHWBP *PKDCTXHWBP;
1179/** Pointer to a const emulated hardware breakpoint. */
1180typedef const KDCTXHWBP *PCKDCTXHWBP;
1181
1182
1183/**
1184 * KD context data.
1185 */
1186typedef struct KDCTX
1187{
1188 /** Internal debugger console data. */
1189 DBGC Dbgc;
1190 /** Number of bytes received left for the current state. */
1191 size_t cbRecvLeft;
1192 /** Pointer where to write the next received data. */
1193 uint8_t *pbRecv;
1194 /** The current state when receiving a new packet. */
1195 KDRECVSTATE enmState;
1196 /** The timeout waiting for new data. */
1197 RTMSINTERVAL msRecvTimeout;
1198 /** Timestamp when we last received data from the remote end. */
1199 uint64_t tsRecvLast;
1200 /** Packet header being received. */
1201 union
1202 {
1203 KDPACKETHDR Fields;
1204 uint8_t ab[16];
1205 } PktHdr;
1206 /** The next packet ID to send. */
1207 uint32_t idPktNext;
1208 /** Offset into the body receive buffer. */
1209 size_t offBodyRecv;
1210 /** Body data. */
1211 uint8_t abBody[_4K];
1212 /** The trailer byte storage. */
1213 uint8_t bTrailer;
1214 /** Flag whether a breakin packet was received since the last time it was reset. */
1215 bool fBreakinRecv;
1216 /** Flag whether we entered the native VBox hypervisor through a bugcheck request. */
1217 bool fInVBoxDbg;
1218
1219 /** Emulated hardware breakpoint handling. */
1220 KDCTXHWBP aHwBp[4];
1221 /** Flag whether a single step completed since last time this was cleared. */
1222 bool fSingleStepped;
1223
1224 /** Pointer to the OS digger WinNt interface if a matching guest was detected. */
1225 PDBGFOSIWINNT pIfWinNt;
1226 /** Flag whether the detected guest is 32bit (false if 64bit). */
1227 bool f32Bit;
1228} KDCTX;
1229/** Pointer to the KD context data. */
1230typedef KDCTX *PKDCTX;
1231/** Pointer to const KD context data. */
1232typedef const KDCTX *PCKDCTX;
1233/** Pointer to a KD context data pointer. */
1234typedef PKDCTX *PPKDCTX;
1235
1236
1237/** Creates a possibly sign extended guest context pointer which is required for 32bit targets. */
1238#define KD_PTR_CREATE(a_pThis, a_GCPtr) ((a_pThis)->f32Bit && ((a_GCPtr) & RT_BIT_32(31)) ? (a_GCPtr) | UINT64_C(0xffffffff00000000) : (a_GCPtr))
1239/** Returns the value of a possibly sign extended guest context pointer received for 32bit targets. */
1240#define KD_PTR_GET(a_pThis, a_GCPtr) ((a_pThis)->f32Bit ? (a_GCPtr) & ~UINT64_C(0xffffffff00000000) : (a_GCPtr))
1241
1242
1243/*********************************************************************************************************************************
1244* Internal Functions *
1245*********************************************************************************************************************************/
1246
1247static void dbgcKdCtxMsgSend(PKDCTX pThis, bool fWarning, const char *pszMsg);
1248
1249
1250#ifdef LOG_ENABLED
1251/**
1252 * Returns a human readable string of the given packet sub type.
1253 *
1254 * @returns Pointer to sub type string.
1255 * @param u16SubType The sub type to convert to a string.
1256 */
1257static const char *dbgcKdPktDumpSubTypeToStr(uint16_t u16SubType)
1258{
1259 switch (u16SubType)
1260 {
1261 case KD_PACKET_HDR_SUB_TYPE_STATE_CHANGE32: return "StateChange32";
1262 case KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE: return "Manipulate";
1263 case KD_PACKET_HDR_SUB_TYPE_DEBUG_IO: return "DebugIo";
1264 case KD_PACKET_HDR_SUB_TYPE_ACKNOWLEDGE: return "Ack";
1265 case KD_PACKET_HDR_SUB_TYPE_RESEND: return "Resend";
1266 case KD_PACKET_HDR_SUB_TYPE_RESET: return "Reset";
1267 case KD_PACKET_HDR_SUB_TYPE_STATE_CHANGE64: return "StateChange64";
1268 case KD_PACKET_HDR_SUB_TYPE_POLL_BREAKIN: return "PollBreakin";
1269 case KD_PACKET_HDR_SUB_TYPE_TRACE_IO: return "TraceIo";
1270 case KD_PACKET_HDR_SUB_TYPE_CONTROL_REQUEST: return "ControlRequest";
1271 case KD_PACKET_HDR_SUB_TYPE_FILE_IO: return "FileIo";
1272 default: break;
1273 }
1274
1275 return "<UNKNOWN>";
1276}
1277
1278
1279/**
1280 * Returns a human readable string of the given manipulate request ID.
1281 *
1282 * @returns nothing.
1283 * @param idReq Request ID (API number in KD speak).
1284 */
1285static const char *dbgcKdPktDumpManipulateReqToStr(uint32_t idReq)
1286{
1287 switch (idReq)
1288 {
1289 case KD_PACKET_MANIPULATE_REQ_READ_VIRT_MEM: return "ReadVirtMem";
1290 case KD_PACKET_MANIPULATE_REQ_WRITE_VIRT_MEM: return "WriteVirtMem";
1291 case KD_PACKET_MANIPULATE_REQ_GET_CONTEXT: return "GetContext";
1292 case KD_PACKET_MANIPULATE_REQ_SET_CONTEXT: return "SetContext";
1293 case KD_PACKET_MANIPULATE_REQ_WRITE_BKPT: return "WriteBkpt";
1294 case KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT: return "RestoreBkpt";
1295 case KD_PACKET_MANIPULATE_REQ_CONTINUE: return "Continue";
1296 case KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE: return "ReadCtrlSpace";
1297 case KD_PACKET_MANIPULATE_REQ_WRITE_CTRL_SPACE: return "WriteCtrlSpace";
1298 case KD_PACKET_MANIPULATE_REQ_READ_IO_SPACE: return "ReadIoSpace";
1299 case KD_PACKET_MANIPULATE_REQ_WRITE_IO_SPACE: return "WriteIoSpace";
1300 case KD_PACKET_MANIPULATE_REQ_REBOOT: return "Reboot";
1301 case KD_PACKET_MANIPULATE_REQ_CONTINUE2: return "Continue2";
1302 case KD_PACKET_MANIPULATE_REQ_READ_PHYS_MEM: return "ReadPhysMem";
1303 case KD_PACKET_MANIPULATE_REQ_WRITE_PHYS_MEM: return "WritePhysMem";
1304 case KD_PACKET_MANIPULATE_REQ_QUERY_SPEC_CALLS: return "QuerySpecCalls";
1305 case KD_PACKET_MANIPULATE_REQ_SET_SPEC_CALLS: return "SetSpecCalls";
1306 case KD_PACKET_MANIPULATE_REQ_CLEAR_SPEC_CALLS: return "ClrSpecCalls";
1307 case KD_PACKET_MANIPULATE_REQ_SET_INTERNAL_BKPT: return "SetIntBkpt";
1308 case KD_PACKET_MANIPULATE_REQ_GET_INTERNAL_BKPT: return "GetIntBkpt";
1309 case KD_PACKET_MANIPULATE_REQ_READ_IO_SPACE_EX: return "ReadIoSpaceEx";
1310 case KD_PACKET_MANIPULATE_REQ_WRITE_IO_SPACE_EX: return "WriteIoSpaceEx";
1311 case KD_PACKET_MANIPULATE_REQ_GET_VERSION: return "GetVersion";
1312 case KD_PACKET_MANIPULATE_REQ_CLEAR_ALL_INTERNAL_BKPT: return "ClrAllIntBkpt";
1313 case KD_PACKET_MANIPULATE_REQ_GET_CONTEXT_EX: return "GetContextEx";
1314 case KD_PACKET_MANIPULATE_REQ_QUERY_MEMORY: return "QueryMemory";
1315 case KD_PACKET_MANIPULATE_REQ_CAUSE_BUGCHECK: return "CauseBugCheck";
1316 case KD_PACKET_MANIPULATE_REQ_SWITCH_PROCESSOR: return "SwitchProcessor";
1317 case KD_PACKET_MANIPULATE_REQ_SEARCH_MEMORY: return "SearchMemory";
1318 default: break;
1319 }
1320
1321 return "<UNKNOWN>";
1322}
1323
1324
1325/**
1326 * Dumps the content of a manipulate packet.
1327 *
1328 * @returns nothing.
1329 * @param pSgBuf S/G buffer containing the manipulate packet payload.
1330 */
1331static void dbgcKdPktDumpManipulate(PRTSGBUF pSgBuf)
1332{
1333 KDPACKETMANIPULATEHDR Hdr;
1334 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, &Hdr, sizeof(Hdr));
1335
1336 if (cbCopied == sizeof(Hdr))
1337 {
1338 const char *pszReq = dbgcKdPktDumpManipulateReqToStr(Hdr.idReq);
1339
1340 Log3((" MANIPULATE(%#x (%s), %#x, %u, %#x)\n",
1341 Hdr.idReq, pszReq, Hdr.u16CpuLvl, Hdr.idCpu, Hdr.u32NtStatus));
1342
1343 switch (Hdr.idReq)
1344 {
1345 case KD_PACKET_MANIPULATE_REQ_READ_VIRT_MEM:
1346 case KD_PACKET_MANIPULATE_REQ_WRITE_VIRT_MEM:
1347 case KD_PACKET_MANIPULATE_REQ_READ_PHYS_MEM:
1348 case KD_PACKET_MANIPULATE_REQ_WRITE_PHYS_MEM:
1349 {
1350 KDPACKETMANIPULATE_XFERMEM64 XferMem64;
1351 cbCopied = RTSgBufCopyToBuf(pSgBuf, &XferMem64, sizeof(XferMem64));
1352 if (cbCopied == sizeof(XferMem64))
1353 {
1354 Log3((" u64PtrTarget: %RX64\n"
1355 " cbXferReq: %RX32\n"
1356 " cbXfered: %RX32\n",
1357 XferMem64.u64PtrTarget, XferMem64.cbXferReq, XferMem64.cbXfered));
1358 }
1359 else
1360 Log3((" Payload to small, expected %u, got %zu\n", sizeof(XferMem64), cbCopied));
1361 break;
1362 }
1363 case KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT:
1364 {
1365 KDPACKETMANIPULATE_RESTOREBKPT64 RestoreBkpt64;
1366 cbCopied = RTSgBufCopyToBuf(pSgBuf, &RestoreBkpt64, sizeof(RestoreBkpt64));
1367 if (cbCopied == sizeof(RestoreBkpt64))
1368 Log3((" u32HndBkpt: %RX32\n", RestoreBkpt64.u32HndBkpt));
1369 else
1370 Log3((" Payload to small, expected %u, got %zu\n", sizeof(RestoreBkpt64), cbCopied));
1371 break;
1372 }
1373 case KD_PACKET_MANIPULATE_REQ_WRITE_BKPT:
1374 {
1375 KDPACKETMANIPULATE_WRITEBKPT64 WriteBkpt64;
1376 cbCopied = RTSgBufCopyToBuf(pSgBuf, &WriteBkpt64, sizeof(WriteBkpt64));
1377 if (cbCopied == sizeof(WriteBkpt64))
1378 Log3((" u64PtrBkpt: %RX64\n"
1379 " u32HndBkpt: %RX32\n",
1380 WriteBkpt64.u64PtrBkpt, WriteBkpt64.u32HndBkpt));
1381 else
1382 Log3((" Payload to small, expected %u, got %zu\n", sizeof(WriteBkpt64), cbCopied));
1383 break;
1384 }
1385 case KD_PACKET_MANIPULATE_REQ_CONTINUE:
1386 {
1387 KDPACKETMANIPULATE_CONTINUE Continue;
1388 cbCopied = RTSgBufCopyToBuf(pSgBuf, &Continue, sizeof(Continue));
1389 if (cbCopied == sizeof(Continue))
1390 Log3((" u32NtContSts: %RX32\n", Continue.u32NtContSts));
1391 else
1392 Log3((" Payload to small, expected %u, got %zu\n", sizeof(Continue), cbCopied));
1393 break;
1394 }
1395 case KD_PACKET_MANIPULATE_REQ_CONTINUE2:
1396 {
1397 KDPACKETMANIPULATE_CONTINUE2 Continue;
1398 cbCopied = RTSgBufCopyToBuf(pSgBuf, &Continue, sizeof(Continue));
1399 if (cbCopied == sizeof(Continue))
1400 Log3((" u32NtContSts: %RX32\n"
1401 " fTrace: %RX32\n",
1402 Continue.u32NtContSts, Continue.fTrace));
1403 else
1404 Log3((" Payload to small, expected %u, got %zu\n", sizeof(Continue), cbCopied));
1405 break;
1406 }
1407 case KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE:
1408 case KD_PACKET_MANIPULATE_REQ_WRITE_CTRL_SPACE:
1409 {
1410 KDPACKETMANIPULATE_XFERCTRLSPACE64 XferCtrlSpace64;
1411 cbCopied = RTSgBufCopyToBuf(pSgBuf, &XferCtrlSpace64, sizeof(XferCtrlSpace64));
1412 if (cbCopied == sizeof(XferCtrlSpace64))
1413 {
1414 Log3((" u64IdXfer: %RX64\n"
1415 " cbXferReq: %RX32\n"
1416 " cbXfered: %RX32\n",
1417 XferCtrlSpace64.u64IdXfer, XferCtrlSpace64.cbXferReq, XferCtrlSpace64.cbXfered));
1418 }
1419 else
1420 Log3((" Payload to small, expected %u, got %zu\n", sizeof(XferCtrlSpace64), cbCopied));
1421 break;
1422 }
1423 case KD_PACKET_MANIPULATE_REQ_GET_CONTEXT_EX:
1424 {
1425 KDPACKETMANIPULATE_CONTEXTEX GetContextEx;
1426 cbCopied = RTSgBufCopyToBuf(pSgBuf, &GetContextEx, sizeof(GetContextEx));
1427 if (cbCopied == sizeof(GetContextEx))
1428 {
1429 Log3((" offStart: %RX32\n"
1430 " cbXferReq: %RX32\n"
1431 " cbXfered: %RX32\n",
1432 GetContextEx.offStart, GetContextEx.cbXfer, GetContextEx.cbXfered));
1433 }
1434 else
1435 Log3((" Payload to small, expected %u, got %zu\n", sizeof(GetContextEx), cbCopied));
1436 break;
1437 }
1438 case KD_PACKET_MANIPULATE_REQ_QUERY_MEMORY:
1439 {
1440 KDPACKETMANIPULATE_QUERYMEMORY QueryMemory;
1441 cbCopied = RTSgBufCopyToBuf(pSgBuf, &QueryMemory, sizeof(QueryMemory));
1442 if (cbCopied == sizeof(QueryMemory))
1443 {
1444 Log3((" u64GCPtr: %RX64\n"
1445 " u32AddrSpace: %RX32\n"
1446 " u32Flags: %RX32\n",
1447 QueryMemory.u64GCPtr, QueryMemory.u32AddrSpace, QueryMemory.u32Flags));
1448 }
1449 else
1450 Log3((" Payload to small, expected %u, got %zu\n", sizeof(QueryMemory), cbCopied));
1451 break;
1452 }
1453 case KD_PACKET_MANIPULATE_REQ_SEARCH_MEMORY:
1454 {
1455 KDPACKETMANIPULATE_SEARCHMEMORY SearchMemory;
1456 cbCopied = RTSgBufCopyToBuf(pSgBuf, &SearchMemory, sizeof(SearchMemory));
1457 if (cbCopied == sizeof(SearchMemory))
1458 {
1459 Log3((" u64GCPtr: %RX64\n"
1460 " cbSearch: %RX64\n"
1461 " cbPattern: %RX32\n",
1462 SearchMemory.u64GCPtr, SearchMemory.cbSearch, SearchMemory.cbPattern));
1463 }
1464 else
1465 Log3((" Payload to small, expected %u, got %zu\n", sizeof(SearchMemory), cbCopied));
1466 break;
1467 }
1468 case KD_PACKET_MANIPULATE_REQ_SWITCH_PROCESSOR:
1469 default:
1470 break;
1471 }
1472 }
1473 else
1474 Log3((" MANIPULATE(Header too small, expected %u, got %zu)\n", sizeof(Hdr), cbCopied));
1475}
1476
1477
1478/**
1479 * Dumps the received packet to the debug log.
1480 *
1481 * @returns VBox status code.
1482 * @param pPktHdr The packet header to dump.
1483 * @param fRx Flag whether the packet was received (false indicates an outgoing packet).
1484 */
1485static void dbgcKdPktDump(PCKDPACKETHDR pPktHdr, PCRTSGSEG paSegs, uint32_t cSegs, bool fRx)
1486{
1487 RTSGBUF SgBuf;
1488
1489 RTSgBufInit(&SgBuf, paSegs, cSegs);
1490
1491 Log3(("%s KDPKTHDR(%#x, %#x (%s), %u, %#x, %#x)\n",
1492 fRx ? "=>" : "<=",
1493 pPktHdr->u32Signature, pPktHdr->u16SubType, dbgcKdPktDumpSubTypeToStr(pPktHdr->u16SubType),
1494 pPktHdr->cbBody, pPktHdr->idPacket, pPktHdr->u32ChkSum));
1495 switch (pPktHdr->u16SubType)
1496 {
1497 case KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE:
1498 dbgcKdPktDumpManipulate(&SgBuf);
1499 break;
1500 default:
1501 break;
1502 }
1503}
1504#endif
1505
1506
1507/**
1508 * Resets the emulated hardware breakpoint state to a state similar after a reboot.
1509 *
1510 * @returns nothing.
1511 * @param pThis The KD context.
1512 */
1513static void dbgcKdCtxHwBpReset(PKDCTX pThis)
1514{
1515 pThis->fSingleStepped = false;
1516
1517 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aHwBp); i++)
1518 {
1519 PKDCTXHWBP pBp = &pThis->aHwBp[i];
1520
1521 if (pBp->iDbgfBp != UINT32_MAX)
1522 {
1523 int rc = DBGFR3BpClear(pThis->Dbgc.pUVM, pBp->iDbgfBp);
1524 AssertRC(rc);
1525 }
1526
1527 pBp->iDbgfBp = UINT32_MAX;
1528 pBp->GCPtrBp = 0;
1529 pBp->fAcc = 0;
1530 pBp->fLen = 0;
1531 pBp->fLocal = false;
1532 pBp->fGlobal = false;
1533 pBp->fTriggered = false;
1534 }
1535}
1536
1537
1538/**
1539 * Updates the given breakpoint with the given properties.
1540 *
1541 * @returns VBox status code.
1542 * @param pThis The KD context.
1543 * @param pBp The breakpoint to update.
1544 * @param fAcc Access mode.
1545 * @param fLen Access length.
1546 * @param fGlobal Global breakpoint.
1547 * @param fLocal Local breakpoint.
1548 * @param GCPtrBp Linear address of the breakpoint.
1549 */
1550static int dbgcKdCtxHwBpUpdate(PKDCTX pThis, PKDCTXHWBP pBp, uint8_t fAcc, uint8_t fLen,
1551 bool fGlobal, bool fLocal, RTGCPTR GCPtrBp)
1552{
1553 int rc = VINF_SUCCESS;
1554
1555 /* Did anything actually change?. */
1556 if ( pBp->fAcc != fAcc
1557 || pBp->fLen != fLen
1558 || pBp->fGlobal != fGlobal
1559 || pBp->fLocal != fLocal
1560 || pBp->GCPtrBp != GCPtrBp)
1561 {
1562 /* Clear the old breakpoint. */
1563 if (pBp->iDbgfBp != UINT32_MAX)
1564 {
1565 rc = DBGFR3BpClear(pThis->Dbgc.pUVM, pBp->iDbgfBp);
1566 AssertRC(rc);
1567 pBp->iDbgfBp = UINT32_MAX;
1568 }
1569
1570 pBp->fAcc = fAcc;
1571 pBp->fLen = fLen;
1572 pBp->fGlobal = fGlobal;
1573 pBp->fLocal = fLocal;
1574 pBp->GCPtrBp = GCPtrBp;
1575 if (pBp->fGlobal || pBp->fLocal)
1576 {
1577 DBGFADDRESS AddrBp;
1578 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrBp, GCPtrBp);
1579
1580 uint8_t cb = 0;
1581 switch (pBp->fLen)
1582 {
1583 case X86_DR7_LEN_BYTE:
1584 cb = 1;
1585 break;
1586 case X86_DR7_LEN_WORD:
1587 cb = 2;
1588 break;
1589 case X86_DR7_LEN_DWORD:
1590 cb = 4;
1591 break;
1592 case X86_DR7_LEN_QWORD:
1593 cb = 8;
1594 break;
1595 default:
1596 AssertFailed();
1597 return VERR_NET_PROTOCOL_ERROR;
1598 }
1599
1600 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &AddrBp, 0 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/,
1601 pBp->fAcc, cb, &pBp->iDbgfBp);
1602 }
1603 }
1604
1605 return rc;
1606}
1607
1608
1609/**
1610 * Updates emulated hardware breakpoints based on the written DR7 value.
1611 *
1612 * @returns VBox status code.
1613 * @param pThis The KD context.
1614 * @param uDr7 The DR7 value which is written.
1615 */
1616static int dbgcKdCtxHwBpDr7Update(PKDCTX pThis, uint32_t uDr7)
1617{
1618 int rc = VINF_SUCCESS;
1619
1620 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aHwBp); i++)
1621 {
1622 PKDCTXHWBP pBp = &pThis->aHwBp[i];
1623 uint8_t fAcc = X86_DR7_GET_RW(uDr7, i);
1624 uint8_t fLen = X86_DR7_GET_LEN(uDr7, i);
1625 bool fGlobal = (uDr7 & RT_BIT_32(1 + i * 2)) ? true : false;
1626 bool fLocal = (uDr7 & RT_BIT_32(i * 2)) ? true : false;
1627
1628 int rc2 = dbgcKdCtxHwBpUpdate(pThis, pBp, fAcc, fLen, fGlobal, fLocal, pThis->aHwBp[i].GCPtrBp);
1629 if ( RT_FAILURE(rc2)
1630 && RT_SUCCESS(rc))
1631 rc = rc2;
1632 }
1633
1634 return rc;
1635}
1636
1637
1638/**
1639 * Updates the linear guest pointer for the given hardware breakpoint.
1640 *
1641 * @returns VBox status code.
1642 * @param pThis The KD context.
1643 * @param pBp The breakpoint to update.
1644 * @param GCPtrBp The linear breakpoint address.
1645 */
1646DECLINLINE(int) dbgcKdCtxHwBpGCPtrUpdate(PKDCTX pThis, PKDCTXHWBP pBp, RTGCPTR GCPtrBp)
1647{
1648 return dbgcKdCtxHwBpUpdate(pThis, pBp, pBp->fAcc, pBp->fLen, pBp->fGlobal, pBp->fLocal, GCPtrBp);
1649}
1650
1651
1652/**
1653 * Calculates the DR7 value based on the emulated hardware breakpoint state and returns it.
1654 *
1655 * @returns The emulated DR7 value.
1656 * @param pThis The KD context.
1657 */
1658static uint32_t dbgcKdCtxHwBpDr7Get(PKDCTX pThis)
1659{
1660 uint32_t uDr7 = 0;
1661
1662 uDr7 |= X86_DR7_RW(0, pThis->aHwBp[0].fAcc);
1663 uDr7 |= X86_DR7_RW(1, pThis->aHwBp[1].fAcc);
1664 uDr7 |= X86_DR7_RW(2, pThis->aHwBp[2].fAcc);
1665 uDr7 |= X86_DR7_RW(3, pThis->aHwBp[3].fAcc);
1666
1667 uDr7 |= X86_DR7_LEN(0, pThis->aHwBp[0].fLen);
1668 uDr7 |= X86_DR7_LEN(1, pThis->aHwBp[1].fLen);
1669 uDr7 |= X86_DR7_LEN(2, pThis->aHwBp[2].fLen);
1670 uDr7 |= X86_DR7_LEN(3, pThis->aHwBp[3].fLen);
1671
1672 uDr7 |= pThis->aHwBp[0].fGlobal ? X86_DR7_G(0) : 0;
1673 uDr7 |= pThis->aHwBp[1].fGlobal ? X86_DR7_G(1) : 0;
1674 uDr7 |= pThis->aHwBp[2].fGlobal ? X86_DR7_G(2) : 0;
1675 uDr7 |= pThis->aHwBp[3].fGlobal ? X86_DR7_G(3) : 0;
1676
1677 uDr7 |= pThis->aHwBp[0].fLocal ? X86_DR7_L(0) : 0;
1678 uDr7 |= pThis->aHwBp[1].fLocal ? X86_DR7_L(1) : 0;
1679 uDr7 |= pThis->aHwBp[2].fLocal ? X86_DR7_L(2) : 0;
1680 uDr7 |= pThis->aHwBp[3].fLocal ? X86_DR7_L(3) : 0;
1681
1682 return uDr7;
1683}
1684
1685
1686/**
1687 * Updates emulated hardware breakpoints based on the written DR6 value.
1688 *
1689 * @returns nothing.
1690 * @param pThis The KD context.
1691 * @param uDr6 The DR7 value which is written.
1692 */
1693static void dbgcKdCtxHwBpDr6Update(PKDCTX pThis, uint32_t uDr6)
1694{
1695 pThis->aHwBp[0].fTriggered = (uDr6 & X86_DR6_B0) ? true : false;
1696 pThis->aHwBp[1].fTriggered = (uDr6 & X86_DR6_B1) ? true : false;
1697 pThis->aHwBp[2].fTriggered = (uDr6 & X86_DR6_B2) ? true : false;
1698 pThis->aHwBp[3].fTriggered = (uDr6 & X86_DR6_B3) ? true : false;
1699 pThis->fSingleStepped = (uDr6 & X86_DR6_BS) ? true : false;
1700}
1701
1702
1703/**
1704 * Calculates the DR6 value based on the emulated hardware breakpoint state and returns it.
1705 *
1706 * @returns The emulated DR6 value.
1707 * @param pThis The KD context.
1708 */
1709static uint32_t dbgcKdCtxHwBpDr6Get(PKDCTX pThis)
1710{
1711 uint32_t uDr6 = 0;
1712
1713 if (pThis->aHwBp[0].fTriggered)
1714 uDr6 |= X86_DR6_B0;
1715 if (pThis->aHwBp[1].fTriggered)
1716 uDr6 |= X86_DR6_B1;
1717 if (pThis->aHwBp[2].fTriggered)
1718 uDr6 |= X86_DR6_B2;
1719 if (pThis->aHwBp[3].fTriggered)
1720 uDr6 |= X86_DR6_B3;
1721 if (pThis->fSingleStepped)
1722 uDr6 |= X86_DR6_BS;
1723
1724 return uDr6;
1725}
1726
1727
1728/**
1729 * Wrapper for the I/O interface write callback.
1730 *
1731 * @returns Status code.
1732 * @param pThis The KD context.
1733 * @param pvPkt The packet data to send.
1734 * @param cbPkt Size of the packet in bytes.
1735 */
1736DECLINLINE(int) dbgcKdCtxWrite(PKDCTX pThis, const void *pvPkt, size_t cbPkt)
1737{
1738 return pThis->Dbgc.pIo->pfnWrite(pThis->Dbgc.pIo, pvPkt, cbPkt, NULL /*pcbWritten*/);
1739}
1740
1741
1742/**
1743 * Fills in the given 64bit NT context structure with the requested values.
1744 *
1745 * @returns VBox status code.
1746 * @param pThis The KD context.
1747 * @param idCpu The CPU to query the context for.
1748 * @param pNtCtx The NT context structure to fill in.
1749 * @param fCtxFlags Combination of NTCONTEXT_F_XXX determining what to fill in.
1750 */
1751static int dbgcKdCtxQueryNtCtx64(PKDCTX pThis, VMCPUID idCpu, PNTCONTEXT64 pNtCtx, uint32_t fCtxFlags)
1752{
1753 RT_BZERO(pNtCtx, sizeof(*pNtCtx));
1754
1755 pNtCtx->fContext = NTCONTEXT_F_AMD64;
1756 int rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_MXCSR, &pNtCtx->u32RegMxCsr);
1757
1758 if ( RT_SUCCESS(rc)
1759 && fCtxFlags & NTCONTEXT_F_CONTROL)
1760 {
1761 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_CS, &pNtCtx->u16SegCs);
1762 if (RT_SUCCESS(rc))
1763 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_SS, &pNtCtx->u16SegSs);
1764 if (RT_SUCCESS(rc))
1765 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RIP, &pNtCtx->u64RegRip);
1766 if (RT_SUCCESS(rc))
1767 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RSP, &pNtCtx->u64RegRsp);
1768 if (RT_SUCCESS(rc))
1769 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RBP, &pNtCtx->u64RegRbp);
1770 if (RT_SUCCESS(rc))
1771 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EFLAGS, &pNtCtx->u32RegEflags);
1772 if (RT_SUCCESS(rc))
1773 pNtCtx->fContext |= NTCONTEXT_F_CONTROL;
1774 }
1775
1776 if ( RT_SUCCESS(rc)
1777 && fCtxFlags & NTCONTEXT_F_INTEGER)
1778 {
1779 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RAX, &pNtCtx->u64RegRax);
1780 if (RT_SUCCESS(rc))
1781 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RCX, &pNtCtx->u64RegRcx);
1782 if (RT_SUCCESS(rc))
1783 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RDX, &pNtCtx->u64RegRdx);
1784 if (RT_SUCCESS(rc))
1785 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RBX, &pNtCtx->u64RegRbx);
1786 if (RT_SUCCESS(rc))
1787 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RSI, &pNtCtx->u64RegRsi);
1788 if (RT_SUCCESS(rc))
1789 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_RDI, &pNtCtx->u64RegRdi);
1790 if (RT_SUCCESS(rc))
1791 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R8, &pNtCtx->u64RegR8);
1792 if (RT_SUCCESS(rc))
1793 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R9, &pNtCtx->u64RegR9);
1794 if (RT_SUCCESS(rc))
1795 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R10, &pNtCtx->u64RegR10);
1796 if (RT_SUCCESS(rc))
1797 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R11, &pNtCtx->u64RegR11);
1798 if (RT_SUCCESS(rc))
1799 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R12, &pNtCtx->u64RegR12);
1800 if (RT_SUCCESS(rc))
1801 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R13, &pNtCtx->u64RegR13);
1802 if (RT_SUCCESS(rc))
1803 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R14, &pNtCtx->u64RegR14);
1804 if (RT_SUCCESS(rc))
1805 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_R15, &pNtCtx->u64RegR15);
1806 if (RT_SUCCESS(rc))
1807 pNtCtx->fContext |= NTCONTEXT_F_INTEGER;
1808 }
1809
1810 if ( RT_SUCCESS(rc)
1811 && fCtxFlags & NTCONTEXT_F_SEGMENTS)
1812 {
1813 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_DS, &pNtCtx->u16SegDs);
1814 if (RT_SUCCESS(rc))
1815 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_ES, &pNtCtx->u16SegEs);
1816 if (RT_SUCCESS(rc))
1817 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_FS, &pNtCtx->u16SegFs);
1818 if (RT_SUCCESS(rc))
1819 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_GS, &pNtCtx->u16SegGs);
1820 if (RT_SUCCESS(rc))
1821 pNtCtx->fContext |= NTCONTEXT_F_SEGMENTS;
1822 }
1823
1824 if ( RT_SUCCESS(rc)
1825 && fCtxFlags & NTCONTEXT_F_FLOATING_POINT)
1826 {
1827 /** @todo. */
1828 }
1829
1830 if ( RT_SUCCESS(rc)
1831 && fCtxFlags & NTCONTEXT_F_DEBUG)
1832 {
1833 /** @todo */
1834 }
1835
1836 return rc;
1837}
1838
1839
1840/**
1841 * Fills in the given 32bit NT context structure with the requested values.
1842 *
1843 * @returns VBox status code.
1844 * @param pThis The KD context.
1845 * @param idCpu The CPU to query the context for.
1846 * @param pNtCtx The NT context structure to fill in.
1847 * @param fCtxFlags Combination of NTCONTEXT_F_XXX determining what to fill in.
1848 */
1849static int dbgcKdCtxQueryNtCtx32(PKDCTX pThis, VMCPUID idCpu, PNTCONTEXT32 pNtCtx, uint32_t fCtxFlags)
1850{
1851 RT_BZERO(pNtCtx, sizeof(*pNtCtx));
1852
1853 pNtCtx->fContext = NTCONTEXT_F_X86;
1854
1855 int rc = VINF_SUCCESS;
1856 if (fCtxFlags & NTCONTEXT_F_CONTROL)
1857 {
1858 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_CS, &pNtCtx->u32SegCs);
1859 if (RT_SUCCESS(rc))
1860 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_SS, &pNtCtx->u32SegSs);
1861 if (RT_SUCCESS(rc))
1862 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EIP, &pNtCtx->u32RegEip);
1863 if (RT_SUCCESS(rc))
1864 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_ESP, &pNtCtx->u32RegEsp);
1865 if (RT_SUCCESS(rc))
1866 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EBP, &pNtCtx->u32RegEbp);
1867 if (RT_SUCCESS(rc))
1868 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EFLAGS, &pNtCtx->u32RegEflags);
1869 if (RT_SUCCESS(rc))
1870 pNtCtx->fContext |= NTCONTEXT_F_CONTROL;
1871 }
1872
1873 if ( RT_SUCCESS(rc)
1874 && fCtxFlags & NTCONTEXT_F_INTEGER)
1875 {
1876 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EAX, &pNtCtx->u32RegEax);
1877 if (RT_SUCCESS(rc))
1878 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_ECX, &pNtCtx->u32RegEcx);
1879 if (RT_SUCCESS(rc))
1880 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EDX, &pNtCtx->u32RegEdx);
1881 if (RT_SUCCESS(rc))
1882 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EBX, &pNtCtx->u32RegEbx);
1883 if (RT_SUCCESS(rc))
1884 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_ESI, &pNtCtx->u32RegEsi);
1885 if (RT_SUCCESS(rc))
1886 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_EDI, &pNtCtx->u32RegEdi);
1887 if (RT_SUCCESS(rc))
1888 pNtCtx->fContext |= NTCONTEXT_F_INTEGER;
1889 }
1890
1891 if ( RT_SUCCESS(rc)
1892 && fCtxFlags & NTCONTEXT_F_SEGMENTS)
1893 {
1894 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DS, &pNtCtx->u32SegDs);
1895 if (RT_SUCCESS(rc))
1896 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_ES, &pNtCtx->u32SegEs);
1897 if (RT_SUCCESS(rc))
1898 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_FS, &pNtCtx->u32SegFs);
1899 if (RT_SUCCESS(rc))
1900 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_GS, &pNtCtx->u32SegGs);
1901 if (RT_SUCCESS(rc))
1902 pNtCtx->fContext |= NTCONTEXT_F_SEGMENTS;
1903 }
1904
1905 if ( RT_SUCCESS(rc)
1906 && fCtxFlags & NTCONTEXT_F_FLOATING_POINT)
1907 {
1908 /** @todo. */
1909 }
1910
1911 if ( RT_SUCCESS(rc)
1912 && fCtxFlags & NTCONTEXT_F_DEBUG)
1913 {
1914 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DR0, &pNtCtx->u32RegDr0);
1915 if (RT_SUCCESS(rc))
1916 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DR1, &pNtCtx->u32RegDr1);
1917 if (RT_SUCCESS(rc))
1918 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DR3, &pNtCtx->u32RegDr3);
1919 if (RT_SUCCESS(rc))
1920 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DR6, &pNtCtx->u32RegDr6);
1921 if (RT_SUCCESS(rc))
1922 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_DR7, &pNtCtx->u32RegDr7);
1923 if (RT_SUCCESS(rc))
1924 pNtCtx->fContext |= NTCONTEXT_F_DEBUG;
1925 }
1926
1927 return rc;
1928}
1929
1930
1931#define KD_REG_INIT(a_pszName, a_enmType, a_ValMember, a_Val) \
1932 do \
1933 { \
1934 aRegsSet[idxReg].pszName = a_pszName; \
1935 aRegsSet[idxReg].enmType = a_enmType; \
1936 aRegsSet[idxReg].Val.a_ValMember = a_Val; \
1937 idxReg++; \
1938 } while (0)
1939#define KD_REG_INIT_DTR(a_pszName, a_Base, a_Limit) \
1940 do \
1941 { \
1942 aRegsSet[idxReg].pszName = a_pszName; \
1943 aRegsSet[idxReg].enmType = DBGFREGVALTYPE_DTR; \
1944 aRegsSet[idxReg].Val.dtr.u64Base = a_Base; \
1945 aRegsSet[idxReg].Val.dtr.u32Limit = a_Limit; \
1946 idxReg++; \
1947 } while (0)
1948#define KD_REG_INIT_U16(a_pszName, a_Val) KD_REG_INIT(a_pszName, DBGFREGVALTYPE_U16, u16, a_Val)
1949#define KD_REG_INIT_U32(a_pszName, a_Val) KD_REG_INIT(a_pszName, DBGFREGVALTYPE_U32, u32, a_Val)
1950#define KD_REG_INIT_U64(a_pszName, a_Val) KD_REG_INIT(a_pszName, DBGFREGVALTYPE_U64, u64, a_Val)
1951
1952
1953/**
1954 * Writes the indicated values from the given context structure to the guests register set.
1955 *
1956 * @returns VBox status code.
1957 * @param pThis The KD context.
1958 * @param idCpu The CPU to query the context for.
1959 * @param pNtCtx The NT context structure to set.
1960 * @param fCtxFlags Combination of NTCONTEXT_F_XXX determining what to set.
1961 */
1962static int dbgcKdCtxSetNtCtx64(PKDCTX pThis, VMCPUID idCpu, PCNTCONTEXT64 pNtCtx, uint32_t fCtxFlags)
1963{
1964 uint32_t idxReg = 0;
1965 DBGFREGENTRYNM aRegsSet[64]; /** @todo Verify that this is enough when fully implemented. */
1966
1967 KD_REG_INIT_U32("mxcsr", pNtCtx->u32RegMxCsr);
1968
1969 if (fCtxFlags & NTCONTEXT_F_CONTROL)
1970 {
1971#if 0 /** @todo CPUM returns VERR_NOT_IMPLEMENTED */
1972 KD_REG_INIT_U16("cs", pNtCtx->u16SegCs);
1973 KD_REG_INIT_U16("ss", pNtCtx->u16SegSs);
1974#endif
1975 KD_REG_INIT_U64("rip", pNtCtx->u64RegRip);
1976 KD_REG_INIT_U64("rsp", pNtCtx->u64RegRsp);
1977 KD_REG_INIT_U64("rbp", pNtCtx->u64RegRbp);
1978 KD_REG_INIT_U32("rflags", pNtCtx->u32RegEflags);
1979 }
1980
1981 if (fCtxFlags & NTCONTEXT_F_INTEGER)
1982 {
1983 KD_REG_INIT_U64("rax", pNtCtx->u64RegRax);
1984 KD_REG_INIT_U64("rcx", pNtCtx->u64RegRcx);
1985 KD_REG_INIT_U64("rdx", pNtCtx->u64RegRdx);
1986 KD_REG_INIT_U64("rbx", pNtCtx->u64RegRbx);
1987 KD_REG_INIT_U64("rsi", pNtCtx->u64RegRsi);
1988 KD_REG_INIT_U64("rdi", pNtCtx->u64RegRdi);
1989 KD_REG_INIT_U64("r8", pNtCtx->u64RegR8);
1990 KD_REG_INIT_U64("r9", pNtCtx->u64RegR9);
1991 KD_REG_INIT_U64("r10", pNtCtx->u64RegR10);
1992 KD_REG_INIT_U64("r11", pNtCtx->u64RegR11);
1993 KD_REG_INIT_U64("r12", pNtCtx->u64RegR12);
1994 KD_REG_INIT_U64("r13", pNtCtx->u64RegR13);
1995 KD_REG_INIT_U64("r14", pNtCtx->u64RegR14);
1996 KD_REG_INIT_U64("r15", pNtCtx->u64RegR15);
1997 }
1998
1999 if (fCtxFlags & NTCONTEXT_F_SEGMENTS)
2000 {
2001#if 0 /** @todo CPUM returns VERR_NOT_IMPLEMENTED */
2002 KD_REG_INIT_U16("ds", pNtCtx->u16SegDs);
2003 KD_REG_INIT_U16("es", pNtCtx->u16SegEs);
2004 KD_REG_INIT_U16("fs", pNtCtx->u16SegFs);
2005 KD_REG_INIT_U16("gs", pNtCtx->u16SegGs);
2006#endif
2007 }
2008
2009 if (fCtxFlags & NTCONTEXT_F_FLOATING_POINT)
2010 {
2011 /** @todo. */
2012 }
2013
2014 if (fCtxFlags & NTCONTEXT_F_DEBUG)
2015 dbgcKdCtxMsgSend(pThis, true /*fWarning*/, "Setting local DR registers does not work!");
2016
2017 return DBGFR3RegNmSetBatch(pThis->Dbgc.pUVM, idCpu, &aRegsSet[0], idxReg);
2018}
2019
2020
2021/**
2022 * Fills in the given 64bit NT kernel context structure with the requested values.
2023 *
2024 * @returns VBox status code.
2025 * @param pThis The KD context.
2026 * @param idCpu The CPU to query the context for.
2027 * @param pKNtCtx The NT context structure to fill in.
2028 * @param fCtxFlags Combination of NTCONTEXT_F_XXX determining what to fill in.
2029 */
2030static int dbgcKdCtxQueryNtKCtx64(PKDCTX pThis, VMCPUID idCpu, PNTKCONTEXT64 pKNtCtx, uint32_t fCtxFlags)
2031{
2032 RT_BZERO(pKNtCtx, sizeof(*pKNtCtx));
2033
2034 int rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR0, &pKNtCtx->u64RegCr0);
2035 if (RT_SUCCESS(rc))
2036 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR2, &pKNtCtx->u64RegCr2);
2037 if (RT_SUCCESS(rc))
2038 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR3, &pKNtCtx->u64RegCr3);
2039 if (RT_SUCCESS(rc))
2040 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR4, &pKNtCtx->u64RegCr4);
2041 if (RT_SUCCESS(rc))
2042 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR8, &pKNtCtx->u64RegCr8);
2043 if (RT_SUCCESS(rc))
2044 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_GDTR_LIMIT, &pKNtCtx->Gdtr.u16Limit);
2045 if (RT_SUCCESS(rc))
2046 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_GDTR_BASE, &pKNtCtx->Gdtr.u64PtrBase);
2047 if (RT_SUCCESS(rc))
2048 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_IDTR_LIMIT, &pKNtCtx->Idtr.u16Limit);
2049 if (RT_SUCCESS(rc))
2050 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_IDTR_BASE, &pKNtCtx->Idtr.u64PtrBase);
2051 if (RT_SUCCESS(rc))
2052 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_TR, &pKNtCtx->u16RegTr);
2053 if (RT_SUCCESS(rc))
2054 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_LDTR, &pKNtCtx->u16RegLdtr);
2055 if (RT_SUCCESS(rc))
2056 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_MXCSR, &pKNtCtx->u32RegMxCsr);
2057
2058 if (RT_SUCCESS(rc))
2059 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K8_GS_BASE, &pKNtCtx->u64MsrGsBase);
2060 if (RT_SUCCESS(rc))
2061 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K8_KERNEL_GS_BASE, &pKNtCtx->u64MsrKernelGsBase);
2062 if (RT_SUCCESS(rc))
2063 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K6_STAR, &pKNtCtx->u64MsrStar);
2064 if (RT_SUCCESS(rc))
2065 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K8_LSTAR, &pKNtCtx->u64MsrLstar);
2066 if (RT_SUCCESS(rc))
2067 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K8_CSTAR, &pKNtCtx->u64MsrCstar);
2068 if (RT_SUCCESS(rc))
2069 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, idCpu, DBGFREG_MSR_K8_SF_MASK, &pKNtCtx->u64MsrSfMask);
2070 /** @todo XCR0 */
2071
2072 /* Get the emulated DR register state. */
2073 pKNtCtx->u64RegDr0 = pThis->aHwBp[0].GCPtrBp;
2074 pKNtCtx->u64RegDr1 = pThis->aHwBp[1].GCPtrBp;
2075 pKNtCtx->u64RegDr2 = pThis->aHwBp[2].GCPtrBp;
2076 pKNtCtx->u64RegDr3 = pThis->aHwBp[3].GCPtrBp;
2077 pKNtCtx->u64RegDr6 = dbgcKdCtxHwBpDr6Get(pThis);
2078 pKNtCtx->u64RegDr7 = dbgcKdCtxHwBpDr7Get(pThis);
2079
2080 if (RT_SUCCESS(rc))
2081 rc = dbgcKdCtxQueryNtCtx64(pThis, idCpu, &pKNtCtx->Ctx, fCtxFlags);
2082
2083 return rc;
2084}
2085
2086
2087/**
2088 * Fills in the given 32bit NT kernel context structure with the requested values.
2089 *
2090 * @returns VBox status code.
2091 * @param pThis The KD context.
2092 * @param idCpu The CPU to query the context for.
2093 * @param pKNtCtx The NT context structure to fill in.
2094 */
2095static int dbgcKdCtxQueryNtKCtx32(PKDCTX pThis, VMCPUID idCpu, PNTKCONTEXT32 pKNtCtx)
2096{
2097 RT_BZERO(pKNtCtx, sizeof(*pKNtCtx));
2098
2099 int rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR0, &pKNtCtx->u32RegCr0);
2100 if (RT_SUCCESS(rc))
2101 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR2, &pKNtCtx->u32RegCr2);
2102 if (RT_SUCCESS(rc))
2103 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR3, &pKNtCtx->u32RegCr3);
2104 if (RT_SUCCESS(rc))
2105 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_CR4, &pKNtCtx->u32RegCr4);
2106
2107 if (RT_SUCCESS(rc))
2108 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_GDTR_LIMIT, &pKNtCtx->Gdtr.u16Limit);
2109 if (RT_SUCCESS(rc))
2110 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_GDTR_BASE, &pKNtCtx->Gdtr.u32PtrBase);
2111 if (RT_SUCCESS(rc))
2112 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_IDTR_LIMIT, &pKNtCtx->Idtr.u16Limit);
2113 if (RT_SUCCESS(rc))
2114 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, idCpu, DBGFREG_IDTR_BASE, &pKNtCtx->Idtr.u32PtrBase);
2115 if (RT_SUCCESS(rc))
2116 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_TR, &pKNtCtx->u16RegTr);
2117 if (RT_SUCCESS(rc))
2118 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, idCpu, DBGFREG_LDTR, &pKNtCtx->u16RegLdtr);
2119
2120 /* Get the emulated DR register state. */
2121 pKNtCtx->u32RegDr0 = (uint32_t)pThis->aHwBp[0].GCPtrBp;
2122 pKNtCtx->u32RegDr1 = (uint32_t)pThis->aHwBp[1].GCPtrBp;
2123 pKNtCtx->u32RegDr2 = (uint32_t)pThis->aHwBp[2].GCPtrBp;
2124 pKNtCtx->u32RegDr3 = (uint32_t)pThis->aHwBp[3].GCPtrBp;
2125 pKNtCtx->u32RegDr6 = dbgcKdCtxHwBpDr6Get(pThis);
2126 pKNtCtx->u32RegDr7 = dbgcKdCtxHwBpDr7Get(pThis);
2127
2128 return rc;
2129}
2130
2131
2132/**
2133 * Fills in the given 64bit NT kernel context structure with the requested values.
2134 *
2135 * @returns VBox status code.
2136 * @param pThis The KD context.
2137 * @param idCpu The CPU to query the context for.
2138 * @param pKNtCtx The NT context structure to fill in.
2139 * @param cbSet How many bytes of the context are valid.
2140 */
2141static int dbgcKdCtxSetNtKCtx64(PKDCTX pThis, VMCPUID idCpu, PCNTKCONTEXT64 pKNtCtx, size_t cbSet)
2142{
2143 AssertReturn(cbSet >= RT_UOFFSETOF(NTKCONTEXT64, Ctx), VERR_INVALID_PARAMETER);
2144
2145 uint32_t idxReg = 0;
2146 DBGFREGENTRYNM aRegsSet[64]; /** @todo Verify that this is enough when fully implemented. */
2147
2148 KD_REG_INIT_U64("cr0", pKNtCtx->u64RegCr0);
2149 KD_REG_INIT_U64("cr2", pKNtCtx->u64RegCr2);
2150 KD_REG_INIT_U64("cr3", pKNtCtx->u64RegCr3);
2151 KD_REG_INIT_U64("cr4", pKNtCtx->u64RegCr4);
2152 KD_REG_INIT_U64("cr8", pKNtCtx->u64RegCr8);
2153
2154 KD_REG_INIT_DTR("gdtr", pKNtCtx->Gdtr.u64PtrBase, pKNtCtx->Gdtr.u16Limit);
2155 KD_REG_INIT_DTR("idtr", pKNtCtx->Idtr.u64PtrBase, pKNtCtx->Idtr.u16Limit);
2156
2157#if 0 /** @todo CPUM returns VERR_NOT_IMPLEMENTED */
2158 KD_REG_INIT_U16("tr", pKNtCtx->u16RegTr);
2159 KD_REG_INIT_U16("ldtr", pKNtCtx->u16RegLdtr);
2160#endif
2161 KD_REG_INIT_U32("mxcsr", pKNtCtx->u32RegMxCsr);
2162
2163 KD_REG_INIT_U64("msr_gs_base", pKNtCtx->u64MsrGsBase);
2164 KD_REG_INIT_U64("krnl_gs_base", pKNtCtx->u64MsrKernelGsBase);
2165 KD_REG_INIT_U64("star", pKNtCtx->u64MsrStar);
2166 KD_REG_INIT_U64("lstar", pKNtCtx->u64MsrLstar);
2167 KD_REG_INIT_U64("cstar", pKNtCtx->u64MsrCstar);
2168 KD_REG_INIT_U64("sf_mask", pKNtCtx->u64MsrSfMask);
2169
2170 int rc = DBGFR3RegNmSetBatch(pThis->Dbgc.pUVM, idCpu, &aRegsSet[0], idxReg);
2171 if ( RT_SUCCESS(rc)
2172 && cbSet > RT_UOFFSETOF(NTKCONTEXT64, Ctx)) /** @todo Probably wrong. */
2173 rc = dbgcKdCtxSetNtCtx64(pThis, idCpu, &pKNtCtx->Ctx, pKNtCtx->Ctx.fContext);
2174
2175 if (RT_SUCCESS(rc))
2176 {
2177 /* Update emulated hardware breakpoint state. */
2178 dbgcKdCtxHwBpDr6Update(pThis, (uint32_t)pKNtCtx->u64RegDr6);
2179 rc = dbgcKdCtxHwBpDr7Update(pThis, (uint32_t)pKNtCtx->u64RegDr7);
2180 if (RT_SUCCESS(rc))
2181 rc = dbgcKdCtxHwBpGCPtrUpdate(pThis, &pThis->aHwBp[0], pKNtCtx->u64RegDr0);
2182 if (RT_SUCCESS(rc))
2183 rc = dbgcKdCtxHwBpGCPtrUpdate(pThis, &pThis->aHwBp[1], pKNtCtx->u64RegDr1);
2184 if (RT_SUCCESS(rc))
2185 rc = dbgcKdCtxHwBpGCPtrUpdate(pThis, &pThis->aHwBp[2], pKNtCtx->u64RegDr2);
2186 if (RT_SUCCESS(rc))
2187 rc = dbgcKdCtxHwBpGCPtrUpdate(pThis, &pThis->aHwBp[3], pKNtCtx->u64RegDr3);
2188 }
2189
2190 return rc;
2191}
2192
2193#undef KD_REG_INIT_64
2194#undef KD_REG_INIT_32
2195#undef KD_REG_INIT_16
2196#undef KD_REG_INIT_DTR
2197#undef KD_REG_INIT
2198
2199
2200/**
2201 * Validates the given KD packet header.
2202 *
2203 * @returns Flag whether the packet header is valid, false if invalid.
2204 * @param pPktHdr The packet header to validate.
2205 */
2206static bool dbgcKdPktHdrValidate(PCKDPACKETHDR pPktHdr)
2207{
2208 if ( pPktHdr->u32Signature != KD_PACKET_HDR_SIGNATURE_DATA
2209 && pPktHdr->u32Signature != KD_PACKET_HDR_SIGNATURE_CONTROL
2210 && pPktHdr->u32Signature != KD_PACKET_HDR_SIGNATURE_BREAKIN)
2211 return false;
2212
2213 if (pPktHdr->u16SubType >= KD_PACKET_HDR_SUB_TYPE_MAX)
2214 return false;
2215
2216 uint32_t idPacket = pPktHdr->idPacket & UINT32_C(0xfffffffe);
2217 if ( idPacket != KD_PACKET_HDR_ID_INITIAL
2218 && idPacket != KD_PACKET_HDR_ID_RESET
2219 && idPacket != 0 /* Happens on the very first packet */)
2220 return false;
2221
2222 return true;
2223}
2224
2225
2226/**
2227 * Generates a checksum from the given buffer.
2228 *
2229 * @returns Generated checksum.
2230 * @param pv The data to generate a checksum from.
2231 * @param cb Number of bytes to checksum.
2232 */
2233static uint32_t dbgcKdPktChkSumGen(const void *pv, size_t cb)
2234{
2235 const uint8_t *pb = (const uint8_t *)pv;
2236 uint32_t u32ChkSum = 0;
2237
2238 while (cb--)
2239 u32ChkSum += *pb++;
2240
2241 return u32ChkSum;
2242}
2243
2244
2245/**
2246 * Generates a checksum from the given segments.
2247 *
2248 * @returns Generated checksum.
2249 * @param paSegs Pointer to the array of segments containing the data.
2250 * @param cSegs Number of segments.
2251 * @param pcbChkSum Where to store the number of bytes checksummed, optional.
2252 */
2253static uint32_t dbgcKdPktChkSumGenSg(PCRTSGSEG paSegs, uint32_t cSegs, size_t *pcbChkSum)
2254{
2255 size_t cbChkSum = 0;
2256 uint32_t u32ChkSum = 0;
2257
2258 for (uint32_t i = 0; i < cSegs; i++)
2259 {
2260 u32ChkSum += dbgcKdPktChkSumGen(paSegs[i].pvSeg, paSegs[i].cbSeg);
2261 cbChkSum += paSegs[i].cbSeg;
2262 }
2263
2264 if (pcbChkSum)
2265 *pcbChkSum = cbChkSum;
2266
2267 return u32ChkSum;
2268}
2269
2270
2271/**
2272 * Waits for an acknowledgment.
2273 *
2274 * @returns VBox status code.
2275 * @param pThis The KD context.
2276 * @param msWait Maximum number of milliseconds to wait for an acknowledge.
2277 * @param pfResend Where to store the resend requested flag on success.
2278 */
2279static int dbgcKdCtxPktWaitForAck(PKDCTX pThis, RTMSINTERVAL msWait, bool *pfResend)
2280{
2281 KDPACKETHDR PktAck;
2282 uint8_t *pbCur = (uint8_t *)&PktAck;
2283 size_t cbLeft = sizeof(PktAck);
2284 uint64_t tsStartMs = RTTimeMilliTS();
2285 int rc = VINF_SUCCESS;
2286
2287 LogFlowFunc(("pThis=%p msWait=%u pfResend=%p\n", pThis, msWait, pfResend));
2288
2289 RT_ZERO(PktAck);
2290
2291 /* There might be breakin packets in the queue, read until we get something else. */
2292 while ( msWait
2293 && RT_SUCCESS(rc))
2294 {
2295 if (pThis->Dbgc.pIo->pfnInput(pThis->Dbgc.pIo, msWait))
2296 {
2297 size_t cbRead = 0;
2298 rc = pThis->Dbgc.pIo->pfnRead(pThis->Dbgc.pIo, pbCur, 1, &cbRead);
2299 if ( RT_SUCCESS(rc)
2300 && cbRead == 1)
2301 {
2302 uint64_t tsSpanMs = RTTimeMilliTS() - tsStartMs;
2303 msWait -= RT_MIN(msWait, tsSpanMs);
2304 tsStartMs = RTTimeMilliTS();
2305
2306 if (*pbCur == KD_PACKET_HDR_SIGNATURE_BREAKIN_BYTE)
2307 pThis->fBreakinRecv = true;
2308 else
2309 {
2310 pbCur++;
2311 cbLeft--;
2312 break;
2313 }
2314 }
2315 }
2316 else
2317 rc = VERR_TIMEOUT;
2318 }
2319
2320 if ( RT_SUCCESS(rc)
2321 && !msWait)
2322 rc = VERR_TIMEOUT;
2323
2324 if (RT_SUCCESS(rc))
2325 {
2326 while ( msWait
2327 && RT_SUCCESS(rc)
2328 && cbLeft)
2329 {
2330 if (pThis->Dbgc.pIo->pfnInput(pThis->Dbgc.pIo, msWait))
2331 {
2332 size_t cbRead = 0;
2333 rc = pThis->Dbgc.pIo->pfnRead(pThis->Dbgc.pIo, pbCur, cbLeft, &cbRead);
2334 if (RT_SUCCESS(rc))
2335 {
2336 uint64_t tsSpanMs = RTTimeMilliTS() - tsStartMs;
2337 msWait -= RT_MIN(msWait, tsSpanMs);
2338 tsStartMs = RTTimeMilliTS();
2339
2340 cbLeft -= cbRead;
2341 pbCur += cbRead;
2342 }
2343 }
2344 else
2345 rc = VERR_TIMEOUT;
2346 }
2347
2348 if (RT_SUCCESS(rc))
2349 {
2350 if (PktAck.u32Signature == KD_PACKET_HDR_SIGNATURE_CONTROL)
2351 {
2352 if (PktAck.u16SubType == KD_PACKET_HDR_SUB_TYPE_ACKNOWLEDGE)
2353 rc = VINF_SUCCESS;
2354 else if (PktAck.u16SubType == KD_PACKET_HDR_SUB_TYPE_RESEND)
2355 {
2356 *pfResend = true;
2357 rc = VINF_SUCCESS;
2358 }
2359 else
2360 rc = VERR_NET_PROTOCOL_ERROR;
2361 }
2362 else
2363 rc = VERR_NET_PROTOCOL_ERROR;
2364 }
2365 }
2366
2367 LogFlowFunc(("returns rc=%Rrc *pfResend=%RTbool\n", rc, *pfResend));
2368 return rc;
2369}
2370
2371
2372/**
2373 * Sends the given packet header and optional segmented body (the trailing byte is sent automatically).
2374 *
2375 * @returns VBox status code.
2376 * @param pThis The KD context.
2377 * @param u32Signature The signature to send.
2378 * @param u16SubType The sub type to send.
2379 * @param paSegs Pointer to the array of segments to send in the body, optional.
2380 * @param cSegs Number of segments.
2381 * @param fAck Flag whether to wait for an acknowledge.
2382 */
2383static int dbgcKdCtxPktSendSg(PKDCTX pThis, uint32_t u32Signature, uint16_t u16SubType,
2384 PCRTSGSEG paSegs, uint32_t cSegs, bool fAck)
2385{
2386 int rc = VINF_SUCCESS;
2387 uint32_t cRetriesLeft = 3;
2388 uint8_t bTrailer = KD_PACKET_TRAILING_BYTE;
2389 KDPACKETHDR Hdr;
2390
2391 size_t cbChkSum = 0;
2392 uint32_t u32ChkSum = dbgcKdPktChkSumGenSg(paSegs, cSegs, &cbChkSum);
2393
2394 Hdr.u32Signature = u32Signature;
2395 Hdr.u16SubType = u16SubType;
2396 Hdr.cbBody = (uint16_t)cbChkSum;
2397 Hdr.idPacket = pThis->idPktNext;
2398 Hdr.u32ChkSum = u32ChkSum;
2399
2400#ifdef LOG_ENABLED
2401 dbgcKdPktDump(&Hdr, paSegs, cSegs, false /*fRx*/);
2402#endif
2403
2404 while (cRetriesLeft--)
2405 {
2406 bool fResend = false;
2407
2408 rc = dbgcKdCtxWrite(pThis, &Hdr, sizeof(Hdr));
2409 if ( RT_SUCCESS(rc)
2410 && paSegs
2411 && cSegs)
2412 {
2413 for (uint32_t i = 0; i < cSegs && RT_SUCCESS(rc); i++)
2414 rc = dbgcKdCtxWrite(pThis, paSegs[i].pvSeg, paSegs[i].cbSeg);
2415
2416 if (RT_SUCCESS(rc))
2417 rc = dbgcKdCtxWrite(pThis, &bTrailer, sizeof(bTrailer));
2418 }
2419
2420 if (RT_SUCCESS(rc))
2421 {
2422 if (fAck)
2423 rc = dbgcKdCtxPktWaitForAck(pThis, 10 * 1000, &fResend);
2424
2425 if ( RT_SUCCESS(rc)
2426 && !fResend)
2427 break;
2428 }
2429 }
2430
2431 return rc;
2432}
2433
2434
2435/**
2436 * Sends the given packet header and optional body (the trailing byte is sent automatically).
2437 *
2438 * @returns VBox status code.
2439 * @param pThis The KD context.
2440 * @param u32Signature The signature to send.
2441 * @param u16SubType The sub type to send.
2442 * @param pvBody The body to send, optional.
2443 * @param cbBody Body size in bytes.
2444 * @param fAck Flag whether to wait for an acknowledge.
2445 */
2446DECLINLINE(int) dbgcKdCtxPktSend(PKDCTX pThis, uint32_t u32Signature, uint16_t u16SubType,
2447 const void *pvBody, size_t cbBody,
2448 bool fAck)
2449{
2450 RTSGSEG Seg;
2451
2452 Seg.pvSeg = (void *)pvBody;
2453 Seg.cbSeg = cbBody;
2454 return dbgcKdCtxPktSendSg(pThis, u32Signature, u16SubType, cbBody ? &Seg : NULL, cbBody ? 1 : 0, fAck);
2455}
2456
2457
2458/**
2459 * Sends a resend packet answer.
2460 *
2461 * @returns VBox status code.
2462 * @param pThis The KD context.
2463 */
2464DECLINLINE(int) dbgcKdCtxPktSendResend(PKDCTX pThis)
2465{
2466 return dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_CONTROL, KD_PACKET_HDR_SUB_TYPE_RESEND,
2467 NULL /*pvBody*/, 0 /*cbBody*/, false /*fAck*/);
2468}
2469
2470
2471/**
2472 * Sends a resend packet answer.
2473 *
2474 * @returns VBox status code.
2475 * @param pThis The KD context.
2476 */
2477DECLINLINE(int) dbgcKdCtxPktSendReset(PKDCTX pThis)
2478{
2479 pThis->idPktNext = KD_PACKET_HDR_ID_INITIAL;
2480 return dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_CONTROL, KD_PACKET_HDR_SUB_TYPE_RESET,
2481 NULL /*pvBody*/, 0 /*cbBody*/, false /*fAck*/);
2482}
2483
2484
2485/**
2486 * Sends an acknowledge packet answer.
2487 *
2488 * @returns VBox status code.
2489 * @param pThis The KD context.
2490 */
2491DECLINLINE(int) dbgcKdCtxPktSendAck(PKDCTX pThis)
2492{
2493 return dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_CONTROL, KD_PACKET_HDR_SUB_TYPE_ACKNOWLEDGE,
2494 NULL /*pvBody*/, 0 /*cbBody*/, false /*fAck*/);
2495}
2496
2497
2498/**
2499 * Resets the packet receive state machine.
2500 *
2501 * @returns nothing.
2502 * @param pThis The KD context.
2503 */
2504static void dbgcKdCtxPktRecvReset(PKDCTX pThis)
2505{
2506 pThis->enmState = KDRECVSTATE_PACKET_HDR_FIRST_BYTE;
2507 pThis->pbRecv = &pThis->PktHdr.ab[0];
2508 pThis->cbRecvLeft = sizeof(pThis->PktHdr.ab[0]);
2509 pThis->msRecvTimeout = RT_INDEFINITE_WAIT;
2510 pThis->tsRecvLast = RTTimeMilliTS();
2511}
2512
2513
2514/**
2515 * Sends a Debug I/O string packet.
2516 *
2517 * @returns VBox status code.
2518 * @param pThis The KD context data.
2519 * @param idCpu The CPU ID generating this packet.
2520 * @param pachChars The characters to send (ASCII).
2521 * @param cbChars Number of characters to send.
2522 */
2523static int dbgcKdCtxDebugIoStrSend(PKDCTX pThis, VMCPUID idCpu, const char *pachChars, size_t cbChars)
2524{
2525 KDPACKETDEBUGIO DebugIo;
2526 RT_ZERO(DebugIo);
2527
2528 /* Fix your damn log strings if this exceeds 4GB... */
2529 if (cbChars != (uint32_t)cbChars)
2530 return VERR_BUFFER_OVERFLOW;
2531
2532 DebugIo.u32Type = KD_PACKET_DEBUG_IO_STRING;
2533 DebugIo.u16CpuLvl = 0x6;
2534 DebugIo.idCpu = (uint16_t)idCpu;
2535 DebugIo.u.Str.cbStr = (uint32_t)cbChars;
2536
2537 RTSGSEG aRespSegs[2];
2538
2539 aRespSegs[0].pvSeg = &DebugIo;
2540 aRespSegs[0].cbSeg = sizeof(DebugIo);
2541 aRespSegs[1].pvSeg = (void *)pachChars;
2542 aRespSegs[1].cbSeg = cbChars;
2543
2544 int rc = dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_DEBUG_IO,
2545 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
2546 if (RT_SUCCESS(rc))
2547 pThis->idPktNext ^= 0x1;
2548
2549 return rc;
2550}
2551
2552
2553/**
2554 * Sends a message to the remotes end.
2555 *
2556 * @returns nothing.
2557 * @param pThis The KD context data.
2558 * @param fWarning Flag whether this is a warning or an informational message.
2559 * @param pszMsg The message to send.
2560 */
2561static void dbgcKdCtxMsgSend(PKDCTX pThis, bool fWarning, const char *pszMsg)
2562{
2563 size_t cchMsg = strlen(pszMsg);
2564
2565 KDPACKETDEBUGIO DebugIo;
2566 RT_ZERO(DebugIo);
2567
2568 DebugIo.u32Type = KD_PACKET_DEBUG_IO_STRING;
2569 DebugIo.u16CpuLvl = 0x6;
2570 DebugIo.idCpu = 0;
2571
2572 RTSGSEG aRespSegs[5];
2573
2574 aRespSegs[0].pvSeg = &DebugIo;
2575 aRespSegs[0].cbSeg = sizeof(DebugIo);
2576 aRespSegs[1].pvSeg = (void *)"VBoxDbg ";
2577 aRespSegs[1].cbSeg = sizeof("VBoxDbg ") - 1;
2578 if (fWarning)
2579 {
2580 aRespSegs[2].pvSeg = (void *)"WARNING ";
2581 aRespSegs[2].cbSeg = sizeof("WARNING ") - 1;
2582 }
2583 else
2584 {
2585 aRespSegs[2].pvSeg = (void *)"INFO ";
2586 aRespSegs[2].cbSeg = sizeof("INFO ") - 1;
2587 }
2588 aRespSegs[3].pvSeg = (void *)pszMsg;
2589 aRespSegs[3].cbSeg = cchMsg;
2590 aRespSegs[4].pvSeg = (void *)"\r\n";
2591 aRespSegs[4].cbSeg = 2;
2592
2593 DebugIo.u.Str.cbStr = (uint32_t)( aRespSegs[1].cbSeg
2594 + aRespSegs[2].cbSeg
2595 + aRespSegs[3].cbSeg
2596 + aRespSegs[4].cbSeg);
2597
2598 int rc = dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_DEBUG_IO,
2599 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
2600 if (RT_SUCCESS(rc))
2601 pThis->idPktNext ^= 0x1;
2602}
2603
2604
2605/**
2606 * Queries some user input from the remotes end.
2607 *
2608 * @returns VBox status code.
2609 * @param pThis The KD context data.
2610 * @param idCpu The CPU ID generating this packet.
2611 * @param pachPrompt The prompt to send (ASCII).
2612 * @param cbPrompt Number of characters to send for the prompt.
2613 * @param cbResponseMax Maximum size for the response.
2614 */
2615static int dbgcKdCtxDebugIoGetStrSend(PKDCTX pThis, VMCPUID idCpu, const char *pachPrompt, size_t cbPrompt,
2616 size_t cbResponseMax)
2617{
2618 KDPACKETDEBUGIO DebugIo;
2619 RT_ZERO(DebugIo);
2620
2621 /* Fix your damn log strings if this exceeds 4GB... */
2622 if ( cbPrompt != (uint32_t)cbPrompt
2623 || cbResponseMax != (uint32_t)cbResponseMax)
2624 return VERR_BUFFER_OVERFLOW;
2625
2626 DebugIo.u32Type = KD_PACKET_DEBUG_IO_GET_STRING;
2627 DebugIo.u16CpuLvl = 0x6;
2628 DebugIo.idCpu = (uint16_t)idCpu;
2629 DebugIo.u.Prompt.cbPrompt = (uint32_t)cbPrompt;
2630 DebugIo.u.Prompt.cbReturn = (uint32_t)cbResponseMax;
2631
2632 RTSGSEG aRespSegs[2];
2633
2634 aRespSegs[0].pvSeg = &DebugIo;
2635 aRespSegs[0].cbSeg = sizeof(DebugIo);
2636 aRespSegs[1].pvSeg = (void *)pachPrompt;
2637 aRespSegs[1].cbSeg = cbPrompt;
2638
2639 int rc = dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_DEBUG_IO,
2640 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
2641 if (RT_SUCCESS(rc))
2642 pThis->idPktNext ^= 0x1;
2643
2644 return rc;
2645}
2646
2647
2648/**
2649 * Sends a state change event packet.
2650 *
2651 * @returns VBox status code.
2652 * @param pThis The KD context data.
2653 * @param enmType The event type.
2654 */
2655static int dbgcKdCtxStateChangeSend(PKDCTX pThis, DBGFEVENTTYPE enmType)
2656{
2657 LogFlowFunc(("pThis=%p enmType=%u\n", pThis, enmType));
2658
2659 /* Select the record to send based on the CPU mode. */
2660 int rc = VINF_SUCCESS;
2661 KDPACKETSTATECHANGE64 StateChange64;
2662 RT_ZERO(StateChange64);
2663
2664 StateChange64.u32StateNew = KD_PACKET_STATE_CHANGE_EXCEPTION;
2665 StateChange64.u16CpuLvl = 0x6; /** @todo Figure this one out. */
2666 StateChange64.idCpu = pThis->Dbgc.idCpu;
2667 StateChange64.cCpus = (uint16_t)DBGFR3CpuGetCount(pThis->Dbgc.pUVM);
2668 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_RIP, &StateChange64.u64RipThread);
2669 if (RT_SUCCESS(rc))
2670 {
2671 DBGFADDRESS AddrRip;
2672 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrRip, StateChange64.u64RipThread);
2673
2674 StateChange64.u64RipThread = KD_PTR_CREATE(pThis, StateChange64.u64RipThread);
2675
2676 /** @todo Properly fill in the exception record. */
2677 switch (enmType)
2678 {
2679 case DBGFEVENT_HALT_DONE:
2680 case DBGFEVENT_BREAKPOINT:
2681 case DBGFEVENT_BREAKPOINT_IO:
2682 case DBGFEVENT_BREAKPOINT_MMIO:
2683 case DBGFEVENT_BREAKPOINT_HYPER:
2684 StateChange64.u.Exception.ExcpRec.u32ExcpCode = KD_PACKET_EXCP_CODE_BKPT;
2685 break;
2686 case DBGFEVENT_STEPPED:
2687 case DBGFEVENT_STEPPED_HYPER:
2688 pThis->fSingleStepped = true; /* For emulation of DR6. */
2689 StateChange64.u.Exception.ExcpRec.u32ExcpCode = KD_PACKET_EXCP_CODE_SINGLE_STEP;
2690 break;
2691 default:
2692 AssertMsgFailed(("Invalid DBGF event type for state change %d!\n", enmType));
2693 }
2694
2695 StateChange64.u.Exception.ExcpRec.cExcpParms = 3;
2696 StateChange64.u.Exception.u32FirstChance = 0x1;
2697
2698 /** @todo Properly fill in the control report. */
2699 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_DR6, &StateChange64.uCtrlReport.Amd64.u64RegDr6);
2700 if (RT_SUCCESS(rc))
2701 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_DR7, &StateChange64.uCtrlReport.Amd64.u64RegDr7);
2702 if (RT_SUCCESS(rc))
2703 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_RFLAGS, &StateChange64.uCtrlReport.Amd64.u32RegEflags);
2704 if (RT_SUCCESS(rc))
2705 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_CS, &StateChange64.uCtrlReport.Amd64.u16SegCs);
2706 if (RT_SUCCESS(rc))
2707 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_DS, &StateChange64.uCtrlReport.Amd64.u16SegDs);
2708 if (RT_SUCCESS(rc))
2709 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_ES, &StateChange64.uCtrlReport.Amd64.u16SegEs);
2710 if (RT_SUCCESS(rc))
2711 rc = DBGFR3RegCpuQueryU16(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGFREG_FS, &StateChange64.uCtrlReport.Amd64.u16SegFs);
2712
2713 /* Read instruction bytes. */
2714 StateChange64.uCtrlReport.Amd64.cbInsnStream = sizeof(StateChange64.uCtrlReport.Amd64.abInsn);
2715 rc = DBGFR3MemRead(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrRip,
2716 &StateChange64.uCtrlReport.Amd64.abInsn[0], StateChange64.uCtrlReport.Amd64.cbInsnStream);
2717 if (RT_SUCCESS(rc))
2718 {
2719 pThis->idPktNext = KD_PACKET_HDR_ID_INITIAL;
2720 rc = dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_CHANGE64,
2721 &StateChange64, sizeof(StateChange64), false /*fAck*/);
2722 }
2723 }
2724
2725 LogFlowFunc(("returns %Rrc\n", rc));
2726 return rc;
2727}
2728
2729
2730/**
2731 * Processes a get version 64 request.
2732 *
2733 * @returns VBox status code.
2734 * @param pThis The KD context.
2735 * @param pPktManip The manipulate packet request.
2736 */
2737static int dbgcKdCtxPktManipulate64GetVersion(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2738{
2739 KDPACKETMANIPULATE64 Resp;
2740 RT_ZERO(Resp);
2741
2742 /* Fill in the generic part. */
2743 Resp.Hdr.idReq = KD_PACKET_MANIPULATE_REQ_GET_VERSION;
2744 Resp.Hdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
2745 Resp.Hdr.idCpu = pPktManip->Hdr.idCpu;
2746 Resp.Hdr.u32NtStatus = NTSTATUS_SUCCESS;
2747
2748 /* Build our own response in case there is no Windows interface available. */
2749 uint32_t NtBuildNumber = 0x0f2800; /* Used when there is no NT interface available, which probably breaks symbol loading. */
2750 bool f32Bit = false;
2751 if (pThis->pIfWinNt)
2752 {
2753 int rc = pThis->pIfWinNt->pfnQueryVersion(pThis->pIfWinNt, pThis->Dbgc.pUVM,
2754 NULL /*puVersMajor*/, NULL /*puVersMinor*/,
2755 &NtBuildNumber, &f32Bit);
2756 if (RT_SUCCESS(rc))
2757 rc = pThis->pIfWinNt->pfnQueryKernelPtrs(pThis->pIfWinNt, pThis->Dbgc.pUVM, &Resp.u.GetVersion.u64PtrKernBase,
2758 &Resp.u.GetVersion.u64PtrPsLoadedModuleList);
2759 }
2760
2761 /* Fill in the request specific part. */
2762 Resp.u.GetVersion.u16VersMaj = NtBuildNumber >> 16;
2763 Resp.u.GetVersion.u16VersMin = NtBuildNumber & UINT32_C(0xffff);
2764 Resp.u.GetVersion.u8VersProtocol = 0x6; /* From a Windows 10 guest. */
2765 Resp.u.GetVersion.u8VersKdSecondary = pThis->f32Bit ? 0 : 0x2; /* amd64 has a versioned context (0 and 1 are obsolete). */
2766 Resp.u.GetVersion.fFlags = KD_PACKET_MANIPULATE64_GET_VERSION_F_MP;
2767 Resp.u.GetVersion.u8MaxPktType = KD_PACKET_HDR_SUB_TYPE_MAX;
2768 Resp.u.GetVersion.u8MaxStateChange = KD_PACKET_STATE_CHANGE_MAX - KD_PACKET_STATE_CHANGE_MIN;
2769 Resp.u.GetVersion.u8MaxManipulate = KD_PACKET_MANIPULATE_REQ_MAX - KD_PACKET_MANIPULATE_REQ_MIN;
2770 Resp.u.GetVersion.u64PtrDebuggerDataList = 0;
2771
2772 if (f32Bit)
2773 {
2774 Resp.u.GetVersion.u16MachineType = IMAGE_FILE_MACHINE_I386;
2775 Resp.u.GetVersion.u64PtrKernBase = KD_PTR_CREATE(pThis, Resp.u.GetVersion.u64PtrKernBase);
2776 Resp.u.GetVersion.u64PtrPsLoadedModuleList = KD_PTR_CREATE(pThis, Resp.u.GetVersion.u64PtrPsLoadedModuleList);
2777 }
2778 else
2779 {
2780 Resp.u.GetVersion.u16MachineType = IMAGE_FILE_MACHINE_AMD64;
2781 Resp.u.GetVersion.fFlags |= KD_PACKET_MANIPULATE64_GET_VERSION_F_PTR64;
2782 }
2783
2784 return dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
2785 &Resp, sizeof(Resp), true /*fAck*/);
2786}
2787
2788
2789/**
2790 * Processes a read memory 64 request.
2791 *
2792 * @returns VBox status code.
2793 * @param pThis The KD context.
2794 * @param pPktManip The manipulate packet request.
2795 */
2796static int dbgcKdCtxPktManipulate64ReadMem(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2797{
2798 KDPACKETMANIPULATEHDR RespHdr;
2799 KDPACKETMANIPULATE_XFERMEM64 XferMem64;
2800 uint8_t abMem[_4K];
2801 RT_ZERO(RespHdr); RT_ZERO(XferMem64);
2802
2803 DBGFADDRESS AddrRead;
2804 uint32_t cbRead = RT_MIN(sizeof(abMem), pPktManip->u.XferMem.cbXferReq);
2805 if (pPktManip->Hdr.idReq == KD_PACKET_MANIPULATE_REQ_READ_VIRT_MEM)
2806 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrRead, KD_PTR_GET(pThis, pPktManip->u.XferMem.u64PtrTarget));
2807 else
2808 DBGFR3AddrFromPhys(pThis->Dbgc.pUVM, &AddrRead, KD_PTR_GET(pThis, pPktManip->u.XferMem.u64PtrTarget));
2809
2810 RTSGSEG aRespSegs[3];
2811 uint32_t cSegs = 2; /* Gets incremented when read is successful. */
2812 RespHdr.idReq = pPktManip->Hdr.idReq;
2813 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
2814 RespHdr.idCpu = pPktManip->Hdr.idCpu;
2815 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
2816
2817 XferMem64.u64PtrTarget = pPktManip->u.XferMem.u64PtrTarget;
2818 XferMem64.cbXferReq = pPktManip->u.XferMem.cbXferReq;
2819 XferMem64.cbXfered = (uint32_t)cbRead;
2820
2821 aRespSegs[0].pvSeg = &RespHdr;
2822 aRespSegs[0].cbSeg = sizeof(RespHdr);
2823 aRespSegs[1].pvSeg = &XferMem64;
2824 aRespSegs[1].cbSeg = sizeof(XferMem64);
2825
2826 int rc = DBGFR3MemRead(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrRead, &abMem[0], cbRead);
2827 if (RT_SUCCESS(rc))
2828 {
2829 cSegs++;
2830 aRespSegs[2].pvSeg = &abMem[0];
2831 aRespSegs[2].cbSeg = cbRead;
2832 }
2833 else
2834 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Convert to an appropriate NT status code. */
2835
2836 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
2837 &aRespSegs[0], cSegs, true /*fAck*/);
2838}
2839
2840
2841/**
2842 * Processes a write memory 64 request.
2843 *
2844 * @returns VBox status code.
2845 * @param pThis The KD context.
2846 * @param pPktManip The manipulate packet request.
2847 */
2848static int dbgcKdCtxPktManipulate64WriteMem(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2849{
2850 KDPACKETMANIPULATEHDR RespHdr;
2851 KDPACKETMANIPULATE_XFERMEM64 XferMem64;
2852 RT_ZERO(RespHdr); RT_ZERO(XferMem64);
2853
2854 DBGFADDRESS AddrWrite;
2855 const void *pv = &pThis->abBody[sizeof(*pPktManip)]; /* Data comes directly after the manipulate state body. */
2856 uint32_t cbWrite = RT_MIN(sizeof(pThis->abBody) - sizeof(*pPktManip), pPktManip->u.XferMem.cbXferReq);
2857 if (pPktManip->Hdr.idReq == KD_PACKET_MANIPULATE_REQ_WRITE_VIRT_MEM)
2858 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrWrite, KD_PTR_GET(pThis, pPktManip->u.XferMem.u64PtrTarget));
2859 else
2860 DBGFR3AddrFromPhys(pThis->Dbgc.pUVM, &AddrWrite, KD_PTR_GET(pThis, pPktManip->u.XferMem.u64PtrTarget));
2861
2862 RTSGSEG aRespSegs[2];
2863 uint32_t cSegs = 2;
2864 RespHdr.idReq = pPktManip->Hdr.idReq;
2865 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
2866 RespHdr.idCpu = pPktManip->Hdr.idCpu;
2867 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
2868
2869 XferMem64.u64PtrTarget = pPktManip->u.XferMem.u64PtrTarget;
2870 XferMem64.cbXferReq = pPktManip->u.XferMem.cbXferReq;
2871 XferMem64.cbXfered = (uint32_t)cbWrite;
2872
2873 aRespSegs[0].pvSeg = &RespHdr;
2874 aRespSegs[0].cbSeg = sizeof(RespHdr);
2875 aRespSegs[1].pvSeg = &XferMem64;
2876 aRespSegs[1].cbSeg = sizeof(XferMem64);
2877
2878 int rc = DBGFR3MemWrite(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrWrite, pv, cbWrite);
2879 if (RT_FAILURE(rc))
2880 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Convert to an appropriate NT status code. */
2881
2882 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
2883 &aRespSegs[0], cSegs, true /*fAck*/);
2884}
2885
2886
2887/**
2888 * Processes a continue request.
2889 *
2890 * @returns VBox status code.
2891 * @param pThis The KD context.
2892 * @param pPktManip The manipulate packet request.
2893 */
2894static int dbgcKdCtxPktManipulate64Continue(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2895{
2896 RT_NOREF(pPktManip);
2897 int rc = VINF_SUCCESS;
2898
2899 /* No response, just resume. */
2900 if (DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
2901 rc = DBGFR3Resume(pThis->Dbgc.pUVM, VMCPUID_ALL);
2902
2903 return rc;
2904}
2905
2906
2907/**
2908 * Processes a continue request.
2909 *
2910 * @returns VBox status code.
2911 * @param pThis The KD context.
2912 * @param pPktManip The manipulate packet request.
2913 */
2914static int dbgcKdCtxPktManipulate64Continue2(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2915{
2916 int rc = VINF_SUCCESS;
2917
2918 /* Update DR7. */
2919 if (pThis->f32Bit)
2920 rc = dbgcKdCtxHwBpDr7Update(pThis, pPktManip->u.Continue2.u.x86.u32RegDr7);
2921 else
2922 rc = dbgcKdCtxHwBpDr7Update(pThis, (uint32_t)pPktManip->u.Continue2.u.amd64.u64RegDr7);
2923
2924 /* Resume if not single stepping, the single step will get a state change when the VM stepped. */
2925 if (pPktManip->u.Continue2.fTrace)
2926 {
2927 PDBGFADDRESS pStackPop = NULL;
2928 RTGCPTR cbStackPop = 0;
2929 rc = DBGFR3StepEx(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGF_STEP_F_INTO, NULL,
2930 pStackPop, cbStackPop, 1 /*cMaxSteps*/);
2931 }
2932 else if (DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
2933 rc = DBGFR3Resume(pThis->Dbgc.pUVM, VMCPUID_ALL);
2934
2935 return rc;
2936}
2937
2938
2939/**
2940 * Processes a set context request.
2941 *
2942 * @returns VBox status code.
2943 * @param pThis The KD context.
2944 * @param pPktManip The manipulate packet request.
2945 */
2946static int dbgcKdCtxPktManipulate64SetContext(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2947{
2948 KDPACKETMANIPULATEHDR RespHdr;
2949 KDPACKETMANIPULATE_SETCONTEXT SetContext;
2950 RT_ZERO(RespHdr); RT_ZERO(SetContext);
2951
2952 PCNTCONTEXT64 pNtCtx = (PCNTCONTEXT64)&pThis->abBody[sizeof(*pPktManip)]; /* Data comes directly after the manipulate state body. */
2953
2954 RTSGSEG aRespSegs[2];
2955 uint32_t cSegs = 2;
2956 RespHdr.idReq = pPktManip->Hdr.idReq;
2957 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
2958 RespHdr.idCpu = pPktManip->Hdr.idCpu;
2959 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
2960
2961 /** @todo What do these flags mean? Can't be the context state to set because the valid one is
2962 * in NTCONTEXT64::fContext (observed with WinDbg). */
2963 SetContext.u32CtxFlags = pPktManip->u.SetContext.u32CtxFlags;
2964
2965 aRespSegs[0].pvSeg = &RespHdr;
2966 aRespSegs[0].cbSeg = sizeof(RespHdr);
2967 aRespSegs[1].pvSeg = &SetContext;
2968 aRespSegs[1].cbSeg = sizeof(SetContext);
2969
2970 int rc = dbgcKdCtxSetNtCtx64(pThis, pPktManip->Hdr.idCpu, pNtCtx, pNtCtx->fContext);
2971 if (RT_FAILURE(rc))
2972 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Convert to an appropriate NT status code. */
2973
2974 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
2975 &aRespSegs[0], cSegs, true /*fAck*/);
2976}
2977
2978
2979/**
2980 * Processes a read control space 64 request.
2981 *
2982 * @returns VBox status code.
2983 * @param pThis The KD context.
2984 * @param pPktManip The manipulate packet request.
2985 */
2986static int dbgcKdCtxPktManipulate64ReadCtrlSpace(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
2987{
2988 KDPACKETMANIPULATEHDR RespHdr;
2989 KDPACKETMANIPULATE_XFERCTRLSPACE64 XferCtrlSpace64;
2990 uint8_t abResp[sizeof(NTKCONTEXT64)];
2991 uint32_t cbData = 0;
2992 RT_ZERO(RespHdr); RT_ZERO(XferCtrlSpace64);
2993 RT_ZERO(abResp);
2994
2995 RTSGSEG aRespSegs[3];
2996 uint32_t cSegs = 2; /* Gets incremented when read is successful. */
2997 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE;
2998 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
2999 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3000 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3001
3002 XferCtrlSpace64.u64IdXfer = pPktManip->u.XferCtrlSpace.u64IdXfer;
3003 XferCtrlSpace64.cbXferReq = pPktManip->u.XferCtrlSpace.cbXferReq;
3004
3005 aRespSegs[0].pvSeg = &RespHdr;
3006 aRespSegs[0].cbSeg = sizeof(RespHdr);
3007 aRespSegs[1].pvSeg = &XferCtrlSpace64;
3008 aRespSegs[1].cbSeg = sizeof(XferCtrlSpace64);
3009
3010 int rc = VINF_SUCCESS;
3011 if (pThis->f32Bit)
3012 {
3013 if (pPktManip->u.XferCtrlSpace.u64IdXfer == sizeof(NTCONTEXT32))
3014 {
3015 /* Queries the kernel context. */
3016 rc = dbgcKdCtxQueryNtKCtx32(pThis, RespHdr.idCpu, (PNTKCONTEXT32)&abResp[0]);
3017 if (RT_SUCCESS(rc))
3018 cbData = sizeof(NTKCONTEXT32);
3019 }
3020 }
3021 else
3022 {
3023 switch (pPktManip->u.XferCtrlSpace.u64IdXfer)
3024 {
3025 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCR:
3026 {
3027 if (pThis->pIfWinNt)
3028 {
3029 RTGCUINTPTR GCPtrKpcr = 0;
3030
3031 rc = pThis->pIfWinNt->pfnQueryKpcrForVCpu(pThis->pIfWinNt, pThis->Dbgc.pUVM, RespHdr.idCpu,
3032 &GCPtrKpcr, NULL /*pKpcrb*/);
3033 if (RT_SUCCESS(rc))
3034 memcpy(&abResp[0], &GCPtrKpcr, sizeof(GCPtrKpcr));
3035 }
3036
3037 cbData = sizeof(RTGCUINTPTR);
3038 break;
3039 }
3040 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCRB:
3041 {
3042 if (pThis->pIfWinNt)
3043 {
3044 RTGCUINTPTR GCPtrKpcrb = 0;
3045
3046 rc = pThis->pIfWinNt->pfnQueryKpcrForVCpu(pThis->pIfWinNt, pThis->Dbgc.pUVM, RespHdr.idCpu,
3047 NULL /*pKpcr*/, &GCPtrKpcrb);
3048 if (RT_SUCCESS(rc))
3049 memcpy(&abResp[0], &GCPtrKpcrb, sizeof(GCPtrKpcrb));
3050 }
3051
3052 cbData = sizeof(RTGCUINTPTR);
3053 break;
3054 }
3055 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KCTX:
3056 {
3057 rc = dbgcKdCtxQueryNtKCtx64(pThis, RespHdr.idCpu, (PNTKCONTEXT64)&abResp[0], NTCONTEXT64_F_FULL);
3058 if (RT_SUCCESS(rc))
3059 cbData = sizeof(NTKCONTEXT64);
3060 break;
3061 }
3062 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KTHRD:
3063 {
3064 if (pThis->pIfWinNt)
3065 {
3066 RTGCUINTPTR GCPtrCurThrd = 0;
3067
3068 rc = pThis->pIfWinNt->pfnQueryCurThrdForVCpu(pThis->pIfWinNt, pThis->Dbgc.pUVM, RespHdr.idCpu,
3069 &GCPtrCurThrd);
3070 if (RT_SUCCESS(rc))
3071 memcpy(&abResp[0], &GCPtrCurThrd, sizeof(GCPtrCurThrd));
3072 }
3073
3074 cbData = sizeof(RTGCUINTPTR);
3075 break;
3076 }
3077 default:
3078 rc = VERR_NOT_SUPPORTED;
3079 break;
3080 }
3081 }
3082
3083 if ( RT_SUCCESS(rc)
3084 && cbData)
3085 {
3086 XferCtrlSpace64.cbXfered = RT_MIN(cbData, XferCtrlSpace64.cbXferReq);
3087
3088 cSegs++;
3089 aRespSegs[2].pvSeg = &abResp[0];
3090 aRespSegs[2].cbSeg = cbData;
3091 }
3092 else if (RT_FAILURE(rc))
3093 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Convert to an appropriate NT status code. */
3094
3095 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3096 &aRespSegs[0], cSegs, true /*fAck*/);
3097}
3098
3099
3100/**
3101 * Processes a write control space 64 request.
3102 *
3103 * @returns VBox status code.
3104 * @param pThis The KD context.
3105 * @param pPktManip The manipulate packet request.
3106 */
3107static int dbgcKdCtxPktManipulate64WriteCtrlSpace(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3108{
3109 KDPACKETMANIPULATEHDR RespHdr;
3110 KDPACKETMANIPULATE_XFERCTRLSPACE64 XferCtrlSpace64;
3111 uint32_t cbData = 0;
3112 RT_ZERO(RespHdr); RT_ZERO(XferCtrlSpace64);
3113
3114 RTSGSEG aRespSegs[2];
3115 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_WRITE_CTRL_SPACE;
3116 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3117 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3118 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3119
3120 XferCtrlSpace64.u64IdXfer = pPktManip->u.XferCtrlSpace.u64IdXfer;
3121 XferCtrlSpace64.cbXferReq = pPktManip->u.XferCtrlSpace.cbXferReq;
3122
3123 aRespSegs[0].pvSeg = &RespHdr;
3124 aRespSegs[0].cbSeg = sizeof(RespHdr);
3125 aRespSegs[1].pvSeg = &XferCtrlSpace64;
3126 aRespSegs[1].cbSeg = sizeof(XferCtrlSpace64);
3127
3128 int rc = VINF_SUCCESS;
3129 switch (pPktManip->u.XferCtrlSpace.u64IdXfer)
3130 {
3131 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KCTX:
3132 {
3133 PCNTKCONTEXT64 pNtKCtx = (PCNTKCONTEXT64)&pThis->abBody[sizeof(*pPktManip)]; /* Data comes directly after the manipulate state body. */
3134 rc = dbgcKdCtxSetNtKCtx64(pThis, RespHdr.idCpu, pNtKCtx, XferCtrlSpace64.cbXferReq);
3135 if (RT_SUCCESS(rc))
3136 cbData = RT_MIN(XferCtrlSpace64.cbXferReq, sizeof(NTKCONTEXT64));
3137 break;
3138 }
3139 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCR:
3140 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KPCRB:
3141 case KD_PACKET_MANIPULATE64_CTRL_SPACE_ID_KTHRD:
3142 default:
3143 rc = VERR_NOT_SUPPORTED;
3144 break;
3145 }
3146
3147 if (RT_FAILURE(rc))
3148 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Convert to an appropriate NT status code. */
3149 else
3150 XferCtrlSpace64.cbXfered = cbData;
3151
3152 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3153 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
3154}
3155
3156
3157/**
3158 * Processes a restore breakpoint 64 request.
3159 *
3160 * @returns VBox status code.
3161 * @param pThis The KD context.
3162 * @param pPktManip The manipulate packet request.
3163 */
3164static int dbgcKdCtxPktManipulate64RestoreBkpt(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3165{
3166 KDPACKETMANIPULATEHDR RespHdr;
3167 KDPACKETMANIPULATE_RESTOREBKPT64 RestoreBkpt64;
3168 RT_ZERO(RespHdr); RT_ZERO(RestoreBkpt64);
3169
3170 RTSGSEG aRespSegs[2];
3171 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT;
3172 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3173 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3174 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3175
3176 RestoreBkpt64.u32HndBkpt = pPktManip->u.RestoreBkpt.u32HndBkpt;
3177
3178 aRespSegs[0].pvSeg = &RespHdr;
3179 aRespSegs[0].cbSeg = sizeof(RespHdr);
3180 aRespSegs[1].pvSeg = &RestoreBkpt64;
3181 aRespSegs[1].cbSeg = sizeof(RestoreBkpt64);
3182
3183 int rc = DBGFR3BpClear(pThis->Dbgc.pUVM, pPktManip->u.RestoreBkpt.u32HndBkpt);
3184 if (RT_SUCCESS(rc))
3185 {
3186 rc = dbgcBpDelete(&pThis->Dbgc, pPktManip->u.RestoreBkpt.u32HndBkpt);
3187 AssertRC(rc);
3188 }
3189 else if (rc != VERR_DBGF_BP_NOT_FOUND)
3190 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL;
3191
3192 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3193 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
3194}
3195
3196
3197/**
3198 * Processes a write breakpoint 64 request.
3199 *
3200 * @returns VBox status code.
3201 * @param pThis The KD context.
3202 * @param pPktManip The manipulate packet request.
3203 */
3204static int dbgcKdCtxPktManipulate64WriteBkpt(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3205{
3206 KDPACKETMANIPULATEHDR RespHdr;
3207 KDPACKETMANIPULATE_WRITEBKPT64 WriteBkpt64;
3208 RT_ZERO(RespHdr); RT_ZERO(WriteBkpt64);
3209
3210 RTSGSEG aRespSegs[2];
3211 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_WRITE_BKPT;
3212 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3213 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3214 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3215
3216 aRespSegs[0].pvSeg = &RespHdr;
3217 aRespSegs[0].cbSeg = sizeof(RespHdr);
3218 aRespSegs[1].pvSeg = &WriteBkpt64;
3219 aRespSegs[1].cbSeg = sizeof(WriteBkpt64);
3220
3221 WriteBkpt64.u64PtrBkpt = pPktManip->u.WriteBkpt.u64PtrBkpt;
3222
3223 DBGFADDRESS BpAddr;
3224 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &BpAddr, KD_PTR_GET(pThis, pPktManip->u.WriteBkpt.u64PtrBkpt));
3225 int rc = DBGFR3BpSetInt3(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &BpAddr,
3226 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, &WriteBkpt64.u32HndBkpt);
3227 if (RT_SUCCESS(rc))
3228 {
3229 rc = dbgcBpAdd(&pThis->Dbgc, WriteBkpt64.u32HndBkpt, NULL /*pszCmd*/);
3230 if (RT_FAILURE(rc))
3231 DBGFR3BpClear(pThis->Dbgc.pUVM, WriteBkpt64.u32HndBkpt);
3232 }
3233 else
3234 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL;
3235
3236 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3237 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
3238}
3239
3240
3241/**
3242 * Processes a get context extended 64 request.
3243 *
3244 * @returns VBox status code.
3245 * @param pThis The KD context.
3246 * @param pPktManip The manipulate packet request.
3247 */
3248static int dbgcKdCtxPktManipulate64GetContextEx(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3249{
3250 KDPACKETMANIPULATEHDR RespHdr;
3251 KDPACKETMANIPULATE_CONTEXTEX ContextEx;
3252 union
3253 {
3254 NTCONTEXT64 v64;
3255 NTCONTEXT32 v32;
3256 } NtCtx;
3257 RT_ZERO(RespHdr); RT_ZERO(ContextEx); RT_ZERO(NtCtx);
3258
3259 RTSGSEG aRespSegs[3];
3260 uint32_t cSegs = 2;
3261 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_GET_CONTEXT_EX;
3262 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3263 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3264 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL;
3265
3266 ContextEx.offStart = pPktManip->u.ContextEx.offStart;
3267 ContextEx.cbXfer = pPktManip->u.ContextEx.cbXfer;
3268 ContextEx.cbXfered = 0;
3269
3270 aRespSegs[0].pvSeg = &RespHdr;
3271 aRespSegs[0].cbSeg = sizeof(RespHdr);
3272 aRespSegs[1].pvSeg = &ContextEx;
3273 aRespSegs[1].cbSeg = sizeof(ContextEx);
3274
3275 int rc = VINF_SUCCESS;
3276 uint32_t cbCtx = pThis->f32Bit ? sizeof(NtCtx.v32) : sizeof(NtCtx.v64);
3277 if (pThis->f32Bit)
3278 dbgcKdCtxQueryNtCtx32(pThis, pPktManip->Hdr.idCpu, &NtCtx.v32, NTCONTEXT32_F_FULL);
3279 else
3280 dbgcKdCtxQueryNtCtx64(pThis, pPktManip->Hdr.idCpu, &NtCtx.v64, NTCONTEXT64_F_FULL);
3281 if ( RT_SUCCESS(rc)
3282 && pPktManip->u.ContextEx.offStart < cbCtx)
3283 {
3284 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3285 ContextEx.cbXfered = RT_MIN(cbCtx - ContextEx.offStart, ContextEx.cbXfer);
3286
3287 aRespSegs[2].pvSeg = (uint8_t *)&NtCtx + ContextEx.offStart;
3288 aRespSegs[2].cbSeg = ContextEx.cbXfered;
3289 cSegs++;
3290 }
3291
3292 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3293 &aRespSegs[0], cSegs, true /*fAck*/);
3294}
3295
3296
3297/**
3298 * Processes a query memory 64 request.
3299 *
3300 * @returns VBox status code.
3301 * @param pThis The KD context.
3302 * @param pPktManip The manipulate packet request.
3303 */
3304static int dbgcKdCtxPktManipulate64QueryMemory(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3305{
3306 KDPACKETMANIPULATEHDR RespHdr;
3307 KDPACKETMANIPULATE_QUERYMEMORY QueryMemory;
3308 RT_ZERO(RespHdr); RT_ZERO(QueryMemory);
3309
3310 RTSGSEG aRespSegs[2];
3311 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_QUERY_MEMORY;
3312 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3313 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3314 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3315
3316 /** @todo Need DBGF API to query protection and privilege level from guest page tables. */
3317 QueryMemory.u64GCPtr = pPktManip->u.QueryMemory.u64GCPtr;
3318 QueryMemory.u32AddrSpace = KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_SPACE_KERNEL;
3319 QueryMemory.u32Flags = KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_READ
3320 | KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_WRITE
3321 | KD_PACKET_MANIPULATE64_QUERY_MEMORY_ADDR_F_EXEC;
3322
3323 aRespSegs[0].pvSeg = &RespHdr;
3324 aRespSegs[0].cbSeg = sizeof(RespHdr);
3325 aRespSegs[1].pvSeg = &QueryMemory;
3326 aRespSegs[1].cbSeg = sizeof(QueryMemory);
3327
3328 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3329 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
3330}
3331
3332
3333/**
3334 * Processes a search memory 64 request.
3335 *
3336 * @returns VBox status code.
3337 * @param pThis The KD context.
3338 * @param pPktManip The manipulate packet request.
3339 */
3340static int dbgcKdCtxPktManipulate64SearchMemory(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3341{
3342 KDPACKETMANIPULATEHDR RespHdr;
3343 KDPACKETMANIPULATE_SEARCHMEMORY SearchMemory;
3344 RT_ZERO(RespHdr); RT_ZERO(SearchMemory);
3345
3346 RTSGSEG aRespSegs[2];
3347 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_SEARCH_MEMORY;
3348 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3349 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3350 RespHdr.u32NtStatus = NTSTATUS_SUCCESS;
3351
3352 SearchMemory.u64GCPtr = pPktManip->u.SearchMemory.u64GCPtr;
3353 SearchMemory.cbSearch = pPktManip->u.SearchMemory.cbSearch;
3354 SearchMemory.cbPattern = pPktManip->u.SearchMemory.cbPattern;
3355
3356 /* Validate the pattern length and start searching. */
3357 if (pPktManip->u.SearchMemory.cbPattern < sizeof(pThis->abBody) - sizeof(*pPktManip))
3358 {
3359 DBGFADDRESS StartAddress;
3360 DBGFADDRESS HitAddress;
3361 VMCPUID idCpu = pPktManip->Hdr.idCpu;
3362 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &StartAddress, pPktManip->u.SearchMemory.u64GCPtr);
3363
3364 /** @todo WindDbg sends CPU ID 32 sometimes, maybe that means continue search on last used CPU?. */
3365 if (idCpu >= DBGFR3CpuGetCount(pThis->Dbgc.pUVM))
3366 idCpu = pThis->Dbgc.idCpu;
3367
3368 int rc = DBGFR3MemScan(pThis->Dbgc.pUVM, idCpu, &StartAddress, pPktManip->u.SearchMemory.cbSearch, 1,
3369 &pThis->abBody[sizeof(*pPktManip)], pPktManip->u.SearchMemory.cbPattern, &HitAddress);
3370 if (RT_SUCCESS(rc))
3371 SearchMemory.u64GCPtr = HitAddress.FlatPtr;
3372 else if (rc == VERR_DBGF_MEM_NOT_FOUND)
3373 RespHdr.u32NtStatus = NTSTATUS_NOT_FOUND;
3374 else
3375 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL;
3376 }
3377 else
3378 RespHdr.u32NtStatus = NTSTATUS_BUFFER_OVERFLOW;
3379
3380 aRespSegs[0].pvSeg = &RespHdr;
3381 aRespSegs[0].cbSeg = sizeof(RespHdr);
3382 aRespSegs[1].pvSeg = &SearchMemory;
3383 aRespSegs[1].cbSeg = sizeof(SearchMemory);
3384
3385 return dbgcKdCtxPktSendSg(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3386 &aRespSegs[0], RT_ELEMENTS(aRespSegs), true /*fAck*/);
3387}
3388
3389
3390/**
3391 * Processes a cause bugcheck 64 request.
3392 *
3393 * @returns VBox status code.
3394 * @param pThis The KD context.
3395 * @param pPktManip The manipulate packet request.
3396 *
3397 * @note We abuse this request to initiate a native VBox debugger command prompt from the remote end
3398 * (There is monitor/Rcmd equivalent like with GDB unfortunately).
3399 */
3400static int dbgcKdCtxPktManipulate64CauseBugCheck(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3401{
3402 RT_NOREF(pPktManip);
3403 pThis->fInVBoxDbg = true;
3404 return dbgcKdCtxDebugIoGetStrSend(pThis, pThis->Dbgc.idCpu, "VBoxDbg>", sizeof("VBoxDbg>") - 1,
3405 512 /*cbResponseMax*/);
3406}
3407
3408
3409/**
3410 * Processes a switch processor request.
3411 *
3412 * @returns VBox status code.
3413 * @param pThis The KD context.
3414 * @param pPktManip The manipulate packet request.
3415 */
3416static int dbgcKdCtxPktManipulate64SwitchProcessor(PKDCTX pThis, PCKDPACKETMANIPULATE64 pPktManip)
3417{
3418 int rc = VINF_SUCCESS;
3419
3420 if (RT_UNLIKELY(pPktManip->Hdr.idCpu >= DBGFR3CpuGetCount(pThis->Dbgc.pUVM)))
3421 {
3422 KDPACKETMANIPULATEHDR RespHdr;
3423 RT_ZERO(RespHdr);
3424
3425 RespHdr.idReq = KD_PACKET_MANIPULATE_REQ_SWITCH_PROCESSOR;
3426 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3427 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3428 RespHdr.u32NtStatus = NTSTATUS_UNSUCCESSFUL; /** @todo Test this path. */
3429 rc = dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3430 &RespHdr, sizeof(RespHdr), true /*fAck*/);
3431 }
3432 else
3433 {
3434 pThis->Dbgc.idCpu = pPktManip->Hdr.idCpu;
3435 rc = dbgcKdCtxStateChangeSend(pThis, DBGFEVENT_HALT_DONE);
3436 }
3437
3438 return rc;
3439}
3440
3441
3442/**
3443 * Processes a manipulate packet.
3444 *
3445 * @returns VBox status code.
3446 * @param pThis The KD context.
3447 */
3448static int dbgcKdCtxPktManipulate64Process(PKDCTX pThis)
3449{
3450 int rc = VINF_SUCCESS;
3451 PCKDPACKETMANIPULATE64 pPktManip = (PCKDPACKETMANIPULATE64)&pThis->abBody[0];
3452
3453 switch (pPktManip->Hdr.idReq)
3454 {
3455 case KD_PACKET_MANIPULATE_REQ_GET_VERSION:
3456 {
3457 rc = dbgcKdCtxPktManipulate64GetVersion(pThis, pPktManip);
3458 break;
3459 }
3460 case KD_PACKET_MANIPULATE_REQ_READ_VIRT_MEM:
3461 case KD_PACKET_MANIPULATE_REQ_READ_PHYS_MEM:
3462 {
3463 rc = dbgcKdCtxPktManipulate64ReadMem(pThis, pPktManip);
3464 break;
3465 }
3466 case KD_PACKET_MANIPULATE_REQ_WRITE_VIRT_MEM:
3467 case KD_PACKET_MANIPULATE_REQ_WRITE_PHYS_MEM:
3468 {
3469 rc = dbgcKdCtxPktManipulate64WriteMem(pThis, pPktManip);
3470 break;
3471 }
3472 case KD_PACKET_MANIPULATE_REQ_CONTINUE:
3473 {
3474 rc = dbgcKdCtxPktManipulate64Continue(pThis, pPktManip);
3475 break;
3476 }
3477 case KD_PACKET_MANIPULATE_REQ_CONTINUE2:
3478 {
3479 rc = dbgcKdCtxPktManipulate64Continue2(pThis, pPktManip);
3480 break;
3481 }
3482 case KD_PACKET_MANIPULATE_REQ_SET_CONTEXT:
3483 {
3484 rc = dbgcKdCtxPktManipulate64SetContext(pThis, pPktManip);
3485 break;
3486 }
3487 case KD_PACKET_MANIPULATE_REQ_READ_CTRL_SPACE:
3488 {
3489 rc = dbgcKdCtxPktManipulate64ReadCtrlSpace(pThis, pPktManip);
3490 break;
3491 }
3492 case KD_PACKET_MANIPULATE_REQ_WRITE_CTRL_SPACE:
3493 {
3494 rc = dbgcKdCtxPktManipulate64WriteCtrlSpace(pThis, pPktManip);
3495 break;
3496 }
3497 case KD_PACKET_MANIPULATE_REQ_RESTORE_BKPT:
3498 {
3499 rc = dbgcKdCtxPktManipulate64RestoreBkpt(pThis, pPktManip);
3500 break;
3501 }
3502 case KD_PACKET_MANIPULATE_REQ_WRITE_BKPT:
3503 {
3504 rc = dbgcKdCtxPktManipulate64WriteBkpt(pThis, pPktManip);
3505 break;
3506 }
3507 case KD_PACKET_MANIPULATE_REQ_CLEAR_ALL_INTERNAL_BKPT:
3508 /* WinDbg doesn't seem to expect an answer apart from the ACK here. */
3509 break;
3510 case KD_PACKET_MANIPULATE_REQ_GET_CONTEXT_EX:
3511 {
3512 rc = dbgcKdCtxPktManipulate64GetContextEx(pThis, pPktManip);
3513 break;
3514 }
3515 case KD_PACKET_MANIPULATE_REQ_QUERY_MEMORY:
3516 {
3517 rc = dbgcKdCtxPktManipulate64QueryMemory(pThis, pPktManip);
3518 break;
3519 }
3520 case KD_PACKET_MANIPULATE_REQ_SEARCH_MEMORY:
3521 {
3522 rc = dbgcKdCtxPktManipulate64SearchMemory(pThis, pPktManip);
3523 break;
3524 }
3525 case KD_PACKET_MANIPULATE_REQ_CAUSE_BUGCHECK:
3526 {
3527 rc = dbgcKdCtxPktManipulate64CauseBugCheck(pThis, pPktManip);
3528 break;
3529 }
3530 case KD_PACKET_MANIPULATE_REQ_SWITCH_PROCESSOR:
3531 {
3532 rc = dbgcKdCtxPktManipulate64SwitchProcessor(pThis, pPktManip);
3533 break;
3534 }
3535 case KD_PACKET_MANIPULATE_REQ_REBOOT:
3536 {
3537 rc = VMR3Reset(pThis->Dbgc.pUVM); /* Doesn't expect an answer here. */
3538 if ( RT_SUCCESS(rc)
3539 && DBGFR3IsHalted(pThis->Dbgc.pUVM, VMCPUID_ALL))
3540 rc = DBGFR3Resume(pThis->Dbgc.pUVM, VMCPUID_ALL);
3541 break;
3542 }
3543 default:
3544 KDPACKETMANIPULATEHDR RespHdr;
3545 RT_ZERO(RespHdr);
3546
3547 RespHdr.idReq = pPktManip->Hdr.idReq;
3548 RespHdr.u16CpuLvl = pPktManip->Hdr.u16CpuLvl;
3549 RespHdr.idCpu = pPktManip->Hdr.idCpu;
3550 RespHdr.u32NtStatus = NTSTATUS_NOT_IMPLEMENTED;
3551 rc = dbgcKdCtxPktSend(pThis, KD_PACKET_HDR_SIGNATURE_DATA, KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE,
3552 &RespHdr, sizeof(RespHdr), true /*fAck*/);
3553 break;
3554 }
3555
3556 return rc;
3557}
3558
3559
3560/**
3561 * Tries to detect the guest OS running in the VM looking specifically for the Windows NT kind.
3562 *
3563 * @returns Nothing.
3564 * @param pThis The KD context.
3565 */
3566static void dbgcKdCtxDetectGstOs(PKDCTX pThis)
3567{
3568 pThis->pIfWinNt = NULL;
3569
3570 /* Try detecting a Windows NT guest. */
3571 char szName[64];
3572 int rc = DBGFR3OSDetect(pThis->Dbgc.pUVM, szName, sizeof(szName));
3573 if (RT_SUCCESS(rc))
3574 {
3575 pThis->pIfWinNt = (PDBGFOSIWINNT)DBGFR3OSQueryInterface(pThis->Dbgc.pUVM, DBGFOSINTERFACE_WINNT);
3576 if (pThis->pIfWinNt)
3577 LogRel(("DBGC/Kd: Detected Windows NT guest OS (%s)\n", &szName[0]));
3578 else
3579 LogRel(("DBGC/Kd: Detected guest OS is not of the Windows NT kind (%s)\n", &szName[0]));
3580 }
3581 else
3582 {
3583 LogRel(("DBGC/Kd: Unable to detect any guest operating system type, rc=%Rrc\n", rc));
3584 rc = VINF_SUCCESS; /* Try to continue nevertheless. */
3585 }
3586
3587 if (pThis->pIfWinNt)
3588 {
3589 rc = pThis->pIfWinNt->pfnQueryVersion(pThis->pIfWinNt, pThis->Dbgc.pUVM,
3590 NULL /*puVersMajor*/, NULL /*puVersMinor*/,
3591 NULL /*puBuildNumber*/, &pThis->f32Bit);
3592 AssertRC(rc);
3593 }
3594 else
3595 {
3596 /*
3597 * Try to detect bitness based on the current CPU mode which might fool us (32bit process running
3598 * inside of 64bit host).
3599 */
3600 CPUMMODE enmMode = DBGCCmdHlpGetCpuMode(&pThis->Dbgc.CmdHlp);
3601 if (enmMode == CPUMMODE_PROTECTED)
3602 pThis->f32Bit = true;
3603 else if (enmMode == CPUMMODE_LONG)
3604 pThis->f32Bit = false;
3605 else
3606 LogRel(("DBGC/Kd: Heh, trying to debug real mode code with WinDbg are we? Good luck with that...\n"));
3607 }
3608}
3609
3610
3611/**
3612 * Processes a fully received packet.
3613 *
3614 * @returns VBox status code.
3615 * @param pThis The KD context.
3616 */
3617static int dbgcKdCtxPktProcess(PKDCTX pThis)
3618{
3619 int rc = VINF_SUCCESS;
3620
3621 pThis->fBreakinRecv = false;
3622
3623 /* Verify checksum. */
3624 if (dbgcKdPktChkSumGen(&pThis->abBody[0], pThis->PktHdr.Fields.cbBody) == pThis->PktHdr.Fields.u32ChkSum)
3625 {
3626 /** @todo Check packet id. */
3627 if (pThis->PktHdr.Fields.u16SubType != KD_PACKET_HDR_SUB_TYPE_RESET)
3628 {
3629 pThis->idPktNext = pThis->PktHdr.Fields.idPacket;
3630 rc = dbgcKdCtxPktSendAck(pThis);
3631 }
3632 if (RT_SUCCESS(rc))
3633 {
3634#ifdef LOG_ENABLED
3635 RTSGSEG Seg;
3636 Seg.pvSeg = &pThis->abBody[0];
3637 Seg.cbSeg = pThis->PktHdr.Fields.cbBody;
3638 dbgcKdPktDump(&pThis->PktHdr.Fields, &Seg, 1 /*cSegs*/, true /*fRx*/);
3639#endif
3640
3641 switch (pThis->PktHdr.Fields.u16SubType)
3642 {
3643 case KD_PACKET_HDR_SUB_TYPE_RESET:
3644 {
3645 dbgcKdCtxDetectGstOs(pThis);
3646
3647 pThis->idPktNext = 0;
3648 rc = dbgcKdCtxPktSendReset(pThis);
3649 if (RT_SUCCESS(rc))
3650 {
3651 rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
3652 if (rc == VWRN_DBGF_ALREADY_HALTED)
3653 rc = dbgcKdCtxStateChangeSend(pThis, DBGFEVENT_HALT_DONE);
3654 }
3655 pThis->idPktNext = KD_PACKET_HDR_ID_RESET;
3656 break;
3657 }
3658 case KD_PACKET_HDR_SUB_TYPE_STATE_MANIPULATE:
3659 {
3660 pThis->idPktNext = pThis->PktHdr.Fields.idPacket ^ 0x1;
3661 rc = dbgcKdCtxPktManipulate64Process(pThis);
3662 break;
3663 }
3664 case KD_PACKET_HDR_SUB_TYPE_ACKNOWLEDGE:
3665 case KD_PACKET_HDR_SUB_TYPE_RESEND:
3666 {
3667 /* Don't do anything. */
3668 rc = VINF_SUCCESS;
3669 break;
3670 }
3671 case KD_PACKET_HDR_SUB_TYPE_DEBUG_IO:
3672 {
3673 if (pThis->fInVBoxDbg)
3674 {
3675 pThis->idPktNext = pThis->PktHdr.Fields.idPacket ^ 0x1;
3676 /* Get the string and execute it. */
3677 PCKDPACKETDEBUGIO pPktDbgIo = (PCKDPACKETDEBUGIO)&pThis->abBody[0];
3678 if ( pPktDbgIo->u32Type == KD_PACKET_DEBUG_IO_GET_STRING
3679 && pPktDbgIo->u.Prompt.cbReturn <= sizeof(pThis->abBody) - sizeof(*pPktDbgIo) - 1)
3680 {
3681 if (pPktDbgIo->u.Prompt.cbReturn)
3682 {
3683 /* Terminate return value. */
3684 pThis->abBody[sizeof(*pPktDbgIo) + pPktDbgIo->u.Prompt.cbReturn] = '\0';
3685
3686 const char *pszCmd = (const char *)&pThis->abBody[sizeof(*pPktDbgIo)];
3687 /* Filter out 'exit' which is handled here directly and exits the debug loop. */
3688 if (!strcmp(pszCmd, "exit"))
3689 pThis->fInVBoxDbg = false;
3690 else
3691 {
3692 rc = pThis->Dbgc.CmdHlp.pfnExec(&pThis->Dbgc.CmdHlp, pszCmd);
3693 if (RT_SUCCESS(rc))
3694 rc = dbgcKdCtxDebugIoGetStrSend(pThis, pThis->Dbgc.idCpu, "VBoxDbg>", sizeof("VBoxDbg>") - 1,
3695 512 /*cbResponseMax*/);
3696 else
3697 LogRel(("DBGC/Kd: Executing command \"%s\" failed with rc=%Rrc\n", pszCmd, rc));
3698 }
3699 }
3700 else
3701 rc = dbgcKdCtxDebugIoGetStrSend(pThis, pThis->Dbgc.idCpu, "VBoxDbg>", sizeof("VBoxDbg>") - 1,
3702 512 /*cbResponseMax*/);
3703 }
3704 else
3705 LogRel(("DBGC/Kd: Received invalid DEBUG_IO packet from remote end, ignoring\n"));
3706 }
3707 else
3708 LogRel(("DBGC/Kd: Received out of band DEBUG_IO packet from remote end, ignoring\n"));
3709 break;
3710 }
3711 default:
3712 rc = VERR_NOT_IMPLEMENTED;
3713 }
3714 }
3715 }
3716 else
3717 {
3718 pThis->idPktNext = pThis->PktHdr.Fields.idPacket;
3719 rc = dbgcKdCtxPktSendResend(pThis);
3720 }
3721
3722 if (pThis->fBreakinRecv)
3723 {
3724 pThis->fBreakinRecv = false;
3725 rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
3726 if (rc == VWRN_DBGF_ALREADY_HALTED)
3727 rc = dbgcKdCtxStateChangeSend(pThis, DBGFEVENT_HALT_DONE);
3728 }
3729
3730 /* Next packet. */
3731 dbgcKdCtxPktRecvReset(pThis);
3732 return rc;
3733}
3734
3735
3736/**
3737 * Processes the received data based on the current state.
3738 *
3739 * @returns VBox status code.
3740 * @param pThis The KD context.
3741 */
3742static int dbgcKdCtxRecvDataProcess(PKDCTX pThis)
3743{
3744 int rc = VINF_SUCCESS;
3745
3746 switch (pThis->enmState)
3747 {
3748 case KDRECVSTATE_PACKET_HDR_FIRST_BYTE:
3749 {
3750 /* Does it look like a valid packet start?. */
3751 if ( pThis->PktHdr.ab[0] == KD_PACKET_HDR_SIGNATURE_DATA_BYTE
3752 || pThis->PktHdr.ab[0] == KD_PACKET_HDR_SIGNATURE_CONTROL_BYTE)
3753 {
3754 pThis->pbRecv = &pThis->PktHdr.ab[1];
3755 pThis->cbRecvLeft = sizeof(pThis->PktHdr.ab[1]);
3756 pThis->enmState = KDRECVSTATE_PACKET_HDR_SECOND_BYTE;
3757 pThis->msRecvTimeout = DBGC_KD_RECV_TIMEOUT_MS;
3758 }
3759 else if (pThis->PktHdr.ab[0] == KD_PACKET_HDR_SIGNATURE_BREAKIN_BYTE)
3760 {
3761 rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
3762 if (rc == VWRN_DBGF_ALREADY_HALTED)
3763 rc = dbgcKdCtxStateChangeSend(pThis, DBGFEVENT_HALT_DONE);
3764 dbgcKdCtxPktRecvReset(pThis);
3765 }
3766 /* else: Ignore and continue. */
3767 break;
3768 }
3769 case KDRECVSTATE_PACKET_HDR_SECOND_BYTE:
3770 {
3771 /*
3772 * If the first and second byte differ there might be a single breakin
3773 * packet byte received and this is actually the start of a new packet.
3774 */
3775 if (pThis->PktHdr.ab[0] != pThis->PktHdr.ab[1])
3776 {
3777 if (pThis->PktHdr.ab[0] == KD_PACKET_HDR_SIGNATURE_BREAKIN_BYTE)
3778 {
3779 /* Halt the VM and rearrange the packet receiving state machine. */
3780 LogFlow(("DbgKd: Halting VM!\n"));
3781
3782 rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
3783 pThis->PktHdr.ab[0] = pThis->PktHdr.ab[1]; /* Overwrite the first byte with the new start. */
3784 pThis->pbRecv = &pThis->PktHdr.ab[1];
3785 pThis->cbRecvLeft = sizeof(pThis->PktHdr.ab[1]);
3786 }
3787 else
3788 rc = VERR_NET_PROTOCOL_ERROR; /* Refuse talking to the remote end any further. */
3789 }
3790 else
3791 {
3792 /* Normal packet receive continues with the rest of the header. */
3793 pThis->pbRecv = &pThis->PktHdr.ab[2];
3794 pThis->cbRecvLeft = sizeof(pThis->PktHdr.Fields) - 2;
3795 pThis->enmState = KDRECVSTATE_PACKET_HDR;
3796 }
3797 break;
3798 }
3799 case KDRECVSTATE_PACKET_HDR:
3800 {
3801 if ( dbgcKdPktHdrValidate(&pThis->PktHdr.Fields)
3802 && pThis->PktHdr.Fields.cbBody <= sizeof(pThis->abBody))
3803 {
3804 /* Start receiving the body. */
3805 if (pThis->PktHdr.Fields.cbBody)
3806 {
3807 pThis->pbRecv = &pThis->abBody[0];
3808 pThis->cbRecvLeft = pThis->PktHdr.Fields.cbBody;
3809 pThis->enmState = KDRECVSTATE_PACKET_BODY;
3810 }
3811 else /* No body means no trailer byte it looks like. */
3812 rc = dbgcKdCtxPktProcess(pThis);
3813 }
3814 else
3815 rc = VERR_NET_PROTOCOL_ERROR;
3816 break;
3817 }
3818 case KDRECVSTATE_PACKET_BODY:
3819 {
3820 pThis->enmState = KDRECVSTATE_PACKET_TRAILER;
3821 pThis->bTrailer = 0;
3822 pThis->pbRecv = &pThis->bTrailer;
3823 pThis->cbRecvLeft = sizeof(pThis->bTrailer);
3824 break;
3825 }
3826 case KDRECVSTATE_PACKET_TRAILER:
3827 {
3828 if (pThis->bTrailer == KD_PACKET_TRAILING_BYTE)
3829 rc = dbgcKdCtxPktProcess(pThis);
3830 else
3831 rc = VERR_NET_PROTOCOL_ERROR;
3832 break;
3833 }
3834 default:
3835 AssertMsgFailed(("Invalid receive state %d\n", pThis->enmState));
3836 }
3837
3838 return rc;
3839}
3840
3841
3842/**
3843 * Receive data and processes complete packets.
3844 *
3845 * @returns Status code.
3846 * @param pThis The KD context.
3847 */
3848static int dbgcKdCtxRecv(PKDCTX pThis)
3849{
3850 int rc = VINF_SUCCESS;
3851
3852 LogFlowFunc(("pThis=%p{.cbRecvLeft=%zu}\n", pThis, pThis->cbRecvLeft));
3853
3854 if (pThis->cbRecvLeft)
3855 {
3856 size_t cbRead = 0;
3857 rc = pThis->Dbgc.pIo->pfnRead(pThis->Dbgc.pIo, pThis->pbRecv, pThis->cbRecvLeft, &cbRead);
3858 if (RT_SUCCESS(rc))
3859 {
3860 pThis->tsRecvLast = RTTimeMilliTS();
3861 pThis->cbRecvLeft -= cbRead;
3862 pThis->pbRecv += cbRead;
3863 if (!pThis->cbRecvLeft)
3864 rc = dbgcKdCtxRecvDataProcess(pThis);
3865 }
3866 }
3867
3868 LogFlowFunc(("returns rc=%Rrc\n", rc));
3869 return rc;
3870}
3871
3872
3873/**
3874 * Processes debugger events.
3875 *
3876 * @returns VBox status code.
3877 * @param pThis The KD context data.
3878 * @param pEvent Pointer to event data.
3879 */
3880static int dbgcKdCtxProcessEvent(PKDCTX pThis, PCDBGFEVENT pEvent)
3881{
3882 /*
3883 * Process the event.
3884 */
3885 PDBGC pDbgc = &pThis->Dbgc;
3886 pThis->Dbgc.pszScratch = &pThis->Dbgc.achInput[0];
3887 pThis->Dbgc.iArg = 0;
3888 int rc = VINF_SUCCESS;
3889 VMCPUID idCpuOld = pDbgc->idCpu;
3890 pDbgc->idCpu = pEvent->idCpu;
3891 switch (pEvent->enmType)
3892 {
3893 /*
3894 * The first part is events we have initiated with commands.
3895 */
3896 case DBGFEVENT_HALT_DONE:
3897 {
3898 rc = dbgcKdCtxStateChangeSend(pThis, pEvent->enmType);
3899 break;
3900 }
3901
3902 /*
3903 * The second part is events which can occur at any time.
3904 */
3905 case DBGFEVENT_FATAL_ERROR:
3906 {
3907 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
3908 dbgcGetEventCtx(pEvent->enmCtx));
3909 if (RT_SUCCESS(rc))
3910 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
3911 break;
3912 }
3913
3914 case DBGFEVENT_BREAKPOINT:
3915 case DBGFEVENT_BREAKPOINT_IO:
3916 case DBGFEVENT_BREAKPOINT_MMIO:
3917 case DBGFEVENT_BREAKPOINT_HYPER:
3918 {
3919 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
3920 switch (rc)
3921 {
3922 case VERR_DBGC_BP_NOT_FOUND:
3923 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
3924 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
3925 break;
3926
3927 case VINF_DBGC_BP_NO_COMMAND:
3928 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
3929 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
3930 break;
3931
3932 case VINF_BUFFER_OVERFLOW:
3933 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
3934 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
3935 break;
3936
3937 default:
3938 break;
3939 }
3940 if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM, VMCPUID_ALL))
3941 {
3942 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
3943
3944 /* Set the resume flag to ignore the breakpoint when resuming execution. */
3945 if ( RT_SUCCESS(rc)
3946 && pEvent->enmType == DBGFEVENT_BREAKPOINT)
3947 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r eflags.rf = 1");
3948 }
3949
3950 /* Figure out the breakpoint and set the triggered flag for emulation of DR6. */
3951 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aHwBp); i++)
3952 {
3953 if (pThis->aHwBp[i].iDbgfBp == pEvent->u.Bp.iBp)
3954 {
3955 pThis->aHwBp[i].fTriggered = true;
3956 break;
3957 }
3958 }
3959
3960 rc = dbgcKdCtxStateChangeSend(pThis, pEvent->enmType);
3961 break;
3962 }
3963
3964 case DBGFEVENT_STEPPED:
3965 case DBGFEVENT_STEPPED_HYPER:
3966 {
3967 pThis->fSingleStepped = true; /* For emulation of DR6. */
3968 rc = dbgcKdCtxStateChangeSend(pThis, pEvent->enmType);
3969 break;
3970 }
3971
3972 case DBGFEVENT_ASSERTION_HYPER:
3973 {
3974 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
3975 "\ndbgf event: Hypervisor Assertion! (%s)\n"
3976 "%s"
3977 "%s"
3978 "\n",
3979 dbgcGetEventCtx(pEvent->enmCtx),
3980 pEvent->u.Assert.pszMsg1,
3981 pEvent->u.Assert.pszMsg2);
3982 if (RT_SUCCESS(rc))
3983 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
3984 break;
3985 }
3986
3987 case DBGFEVENT_DEV_STOP:
3988 {
3989 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
3990 "\n"
3991 "dbgf event: DBGFSTOP (%s)\n"
3992 "File: %s\n"
3993 "Line: %d\n"
3994 "Function: %s\n",
3995 dbgcGetEventCtx(pEvent->enmCtx),
3996 pEvent->u.Src.pszFile,
3997 pEvent->u.Src.uLine,
3998 pEvent->u.Src.pszFunction);
3999 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
4000 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
4001 "Message: %s\n",
4002 pEvent->u.Src.pszMessage);
4003 if (RT_SUCCESS(rc))
4004 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
4005 break;
4006 }
4007
4008
4009 case DBGFEVENT_INVALID_COMMAND:
4010 {
4011 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
4012 break;
4013 }
4014
4015 case DBGFEVENT_POWERING_OFF:
4016 {
4017 pThis->Dbgc.fReady = false;
4018 pThis->Dbgc.pIo->pfnSetReady(pThis->Dbgc.pIo, false);
4019 rc = VERR_GENERAL_FAILURE;
4020 break;
4021 }
4022
4023 default:
4024 {
4025 /*
4026 * Probably a generic event. Look it up to find its name.
4027 */
4028 PCDBGCSXEVT pEvtDesc = dbgcEventLookup(pEvent->enmType);
4029 if (pEvtDesc)
4030 {
4031 if (pEvtDesc->enmKind == kDbgcSxEventKind_Interrupt)
4032 {
4033 Assert(pEvtDesc->pszDesc);
4034 Assert(pEvent->u.Generic.cArgs == 1);
4035 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s no %#llx! (%s)\n",
4036 pEvtDesc->pszDesc, pEvent->u.Generic.auArgs[0], pEvtDesc->pszName);
4037 }
4038 else if (pEvtDesc->fFlags & DBGCSXEVT_F_BUGCHECK)
4039 {
4040 Assert(pEvent->u.Generic.cArgs >= 5);
4041 char szDetails[512];
4042 DBGFR3FormatBugCheck(pDbgc->pUVM, szDetails, sizeof(szDetails), pEvent->u.Generic.auArgs[0],
4043 pEvent->u.Generic.auArgs[1], pEvent->u.Generic.auArgs[2],
4044 pEvent->u.Generic.auArgs[3], pEvent->u.Generic.auArgs[4]);
4045 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s %s%s!\n%s", pEvtDesc->pszName,
4046 pEvtDesc->pszDesc ? "- " : "", pEvtDesc->pszDesc ? pEvtDesc->pszDesc : "",
4047 szDetails);
4048 }
4049 else if ( (pEvtDesc->fFlags & DBGCSXEVT_F_TAKE_ARG)
4050 || pEvent->u.Generic.cArgs > 1
4051 || ( pEvent->u.Generic.cArgs == 1
4052 && pEvent->u.Generic.auArgs[0] != 0))
4053 {
4054 if (pEvtDesc->pszDesc)
4055 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!",
4056 pEvtDesc->pszName, pEvtDesc->pszDesc);
4057 else
4058 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!", pEvtDesc->pszName);
4059 if (pEvent->u.Generic.cArgs <= 1)
4060 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " arg=%#llx\n", pEvent->u.Generic.auArgs[0]);
4061 else
4062 {
4063 for (uint32_t i = 0; i < pEvent->u.Generic.cArgs; i++)
4064 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " args[%u]=%#llx", i, pEvent->u.Generic.auArgs[i]);
4065 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");
4066 }
4067 }
4068 else
4069 {
4070 if (pEvtDesc->pszDesc)
4071 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!\n",
4072 pEvtDesc->pszName, pEvtDesc->pszDesc);
4073 else
4074 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!\n", pEvtDesc->pszName);
4075 }
4076 }
4077 else
4078 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
4079 break;
4080 }
4081 }
4082
4083 pDbgc->idCpu = idCpuOld;
4084 return rc;
4085}
4086
4087
4088/**
4089 * Handle a receive timeout.
4090 *
4091 * @returns VBox status code.
4092 * @param pThis Pointer to the KD context.
4093 */
4094static int dbgcKdCtxRecvTimeout(PKDCTX pThis)
4095{
4096 int rc = VINF_SUCCESS;
4097
4098 LogFlowFunc(("pThis=%p\n", pThis));
4099
4100 /*
4101 * If a single breakin packet byte was received but the header is otherwise incomplete
4102 * the VM is halted and a state change will be sent in the event processing loop.
4103 */
4104 if ( pThis->enmState == KDRECVSTATE_PACKET_HDR_SECOND_BYTE
4105 && pThis->PktHdr.ab[0] == KD_PACKET_HDR_SIGNATURE_BREAKIN_BYTE)
4106 {
4107 LogFlow(("DbgKd: Halting VM!\n"));
4108 rc = DBGFR3Halt(pThis->Dbgc.pUVM, VMCPUID_ALL);
4109 }
4110 else /* Send a reset packet (@todo Figure out the semantics in this case exactly). */
4111 rc = dbgcKdCtxPktSendReset(pThis);
4112
4113 dbgcKdCtxPktRecvReset(pThis);
4114
4115 LogFlowFunc(("rc=%Rrc\n", rc));
4116 return rc;
4117}
4118
4119
4120/**
4121 * @copydoc DBGC::pfnOutput
4122 */
4123static DECLCALLBACK(int) dbgcKdOutput(void *pvUser, const char *pachChars, size_t cbChars)
4124{
4125 PKDCTX pThis = (PKDCTX)pvUser;
4126
4127 return dbgcKdCtxDebugIoStrSend(pThis, pThis->Dbgc.idCpu, pachChars, cbChars);
4128}
4129
4130
4131/**
4132 * Run the debugger console.
4133 *
4134 * @returns VBox status code.
4135 * @param pThis Pointer to the KD context.
4136 */
4137int dbgcKdRun(PKDCTX pThis)
4138{
4139 /*
4140 * We're ready for commands now.
4141 */
4142 pThis->Dbgc.fReady = true;
4143 pThis->Dbgc.pIo->pfnSetReady(pThis->Dbgc.pIo, true);
4144
4145 /*
4146 * Main Debugger Loop.
4147 *
4148 * This loop will either block on waiting for input or on waiting on
4149 * debug events. If we're forwarding the log we cannot wait for long
4150 * before we must flush the log.
4151 */
4152 int rc;
4153 for (;;)
4154 {
4155 rc = VERR_SEM_OUT_OF_TURN;
4156 if (pThis->Dbgc.pUVM)
4157 rc = DBGFR3QueryWaitable(pThis->Dbgc.pUVM);
4158
4159 if (RT_SUCCESS(rc))
4160 {
4161 /*
4162 * Wait for a debug event.
4163 */
4164 DBGFEVENT Evt;
4165 rc = DBGFR3EventWait(pThis->Dbgc.pUVM, 32, &Evt);
4166 if (RT_SUCCESS(rc))
4167 {
4168 rc = dbgcKdCtxProcessEvent(pThis, &Evt);
4169 if (RT_FAILURE(rc))
4170 break;
4171 }
4172 else if (rc != VERR_TIMEOUT)
4173 break;
4174
4175 /*
4176 * Check for input.
4177 */
4178 if (pThis->Dbgc.pIo->pfnInput(pThis->Dbgc.pIo, 0))
4179 {
4180 rc = dbgcKdCtxRecv(pThis);
4181 if (RT_FAILURE(rc))
4182 break;
4183 }
4184 }
4185 else if (rc == VERR_SEM_OUT_OF_TURN)
4186 {
4187 /*
4188 * Wait for input.
4189 */
4190 if (pThis->Dbgc.pIo->pfnInput(pThis->Dbgc.pIo, 1000))
4191 {
4192 rc = dbgcKdCtxRecv(pThis);
4193 if (RT_FAILURE(rc))
4194 break;
4195 }
4196 else if ( pThis->msRecvTimeout != RT_INDEFINITE_WAIT
4197 && (RTTimeMilliTS() - pThis->tsRecvLast >= pThis->msRecvTimeout))
4198 rc = dbgcKdCtxRecvTimeout(pThis);
4199 }
4200 else
4201 break;
4202 }
4203
4204 return rc;
4205}
4206
4207
4208/**
4209 * Creates a KD context instance with the given backend.
4210 *
4211 * @returns VBox status code.
4212 * @param ppKdCtx Where to store the pointer to the KD stub context instance on success.
4213 * @param pIo Pointer to the I/O callback table.
4214 * @param fFlags Flags controlling the behavior.
4215 */
4216static int dbgcKdCtxCreate(PPKDCTX ppKdCtx, PCDBGCIO pIo, unsigned fFlags)
4217{
4218 /*
4219 * Validate input.
4220 */
4221 AssertPtrReturn(pIo, VERR_INVALID_POINTER);
4222 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
4223
4224 /*
4225 * Allocate and initialize.
4226 */
4227 PKDCTX pThis = (PKDCTX)RTMemAllocZ(sizeof(*pThis));
4228 if (!pThis)
4229 return VERR_NO_MEMORY;
4230
4231 dbgcInitCmdHlp(&pThis->Dbgc);
4232 /*
4233 * This is compied from the native debug console (will be used for monitor commands)
4234 * in DBGCConsole.cpp. Try to keep both functions in sync.
4235 */
4236 pThis->Dbgc.pIo = pIo;
4237 pThis->Dbgc.pfnOutput = dbgcKdOutput;
4238 pThis->Dbgc.pvOutputUser = pThis;
4239 pThis->Dbgc.pVM = NULL;
4240 pThis->Dbgc.pUVM = NULL;
4241 pThis->Dbgc.idCpu = 0;
4242 pThis->Dbgc.hDbgAs = DBGF_AS_GLOBAL;
4243 pThis->Dbgc.pszEmulation = "CodeView/WinDbg";
4244 pThis->Dbgc.paEmulationCmds = &g_aCmdsCodeView[0];
4245 pThis->Dbgc.cEmulationCmds = g_cCmdsCodeView;
4246 pThis->Dbgc.paEmulationFuncs = &g_aFuncsCodeView[0];
4247 pThis->Dbgc.cEmulationFuncs = g_cFuncsCodeView;
4248 //pThis->Dbgc.fLog = false;
4249 pThis->Dbgc.fRegTerse = true;
4250 pThis->Dbgc.fStepTraceRegs = true;
4251 //pThis->Dbgc.cPagingHierarchyDumps = 0;
4252 //pThis->Dbgc.DisasmPos = {0};
4253 //pThis->Dbgc.SourcePos = {0};
4254 //pThis->Dbgc.DumpPos = {0};
4255 pThis->Dbgc.pLastPos = &pThis->Dbgc.DisasmPos;
4256 //pThis->Dbgc.cbDumpElement = 0;
4257 //pThis->Dbgc.cVars = 0;
4258 //pThis->Dbgc.paVars = NULL;
4259 //pThis->Dbgc.pPlugInHead = NULL;
4260 //pThis->Dbgc.pFirstBp = NULL;
4261 //pThis->Dbgc.abSearch = {0};
4262 //pThis->Dbgc.cbSearch = 0;
4263 pThis->Dbgc.cbSearchUnit = 1;
4264 pThis->Dbgc.cMaxSearchHits = 1;
4265 //pThis->Dbgc.SearchAddr = {0};
4266 //pThis->Dbgc.cbSearchRange = 0;
4267
4268 //pThis->Dbgc.uInputZero = 0;
4269 //pThis->Dbgc.iRead = 0;
4270 //pThis->Dbgc.iWrite = 0;
4271 //pThis->Dbgc.cInputLines = 0;
4272 //pThis->Dbgc.fInputOverflow = false;
4273 pThis->Dbgc.fReady = true;
4274 pThis->Dbgc.pszScratch = &pThis->Dbgc.achScratch[0];
4275 //pThis->Dbgc.iArg = 0;
4276 //pThis->Dbgc.rcOutput = 0;
4277 //pThis->Dbgc.rcCmd = 0;
4278
4279 //pThis->Dbgc.pszHistoryFile = NULL;
4280 //pThis->Dbgc.pszGlobalInitScript = NULL;
4281 //pThis->Dbgc.pszLocalInitScript = NULL;
4282
4283 dbgcEvalInit();
4284
4285 pThis->fBreakinRecv = false;
4286 pThis->fInVBoxDbg = false;
4287 pThis->idPktNext = KD_PACKET_HDR_ID_INITIAL;
4288 pThis->pIfWinNt = NULL;
4289 pThis->f32Bit = false;
4290 dbgcKdCtxPktRecvReset(pThis);
4291
4292 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aHwBp); i++)
4293 {
4294 PKDCTXHWBP pBp = &pThis->aHwBp[i];
4295 pBp->iDbgfBp = UINT32_MAX;
4296 }
4297
4298 dbgcKdCtxHwBpReset(pThis);
4299
4300 *ppKdCtx = pThis;
4301 return VINF_SUCCESS;
4302}
4303
4304
4305/**
4306 * Destroys the given KD context.
4307 *
4308 * @returns nothing.
4309 * @param pThis The KD context to destroy.
4310 */
4311static void dbgcKdCtxDestroy(PKDCTX pThis)
4312{
4313 AssertPtr(pThis);
4314
4315 pThis->pIfWinNt = NULL;
4316
4317 /* Detach from the VM. */
4318 if (pThis->Dbgc.pUVM)
4319 DBGFR3Detach(pThis->Dbgc.pUVM);
4320
4321 /* Free config strings. */
4322 RTStrFree(pThis->Dbgc.pszGlobalInitScript);
4323 pThis->Dbgc.pszGlobalInitScript = NULL;
4324 RTStrFree(pThis->Dbgc.pszLocalInitScript);
4325 pThis->Dbgc.pszLocalInitScript = NULL;
4326 RTStrFree(pThis->Dbgc.pszHistoryFile);
4327 pThis->Dbgc.pszHistoryFile = NULL;
4328
4329 /* Finally, free the instance memory. */
4330 RTMemFree(pThis);
4331}
4332
4333
4334DECL_HIDDEN_CALLBACK(int) dbgcKdStubRunloop(PUVM pUVM, PCDBGCIO pIo, unsigned fFlags)
4335{
4336 /*
4337 * Validate input.
4338 */
4339 AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE);
4340 PVM pVM = NULL;
4341 if (pUVM)
4342 {
4343 pVM = VMR3GetVM(pUVM);
4344 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
4345 }
4346
4347 /*
4348 * Allocate and initialize instance data
4349 */
4350 PKDCTX pThis;
4351 int rc = dbgcKdCtxCreate(&pThis, pIo, fFlags);
4352 if (RT_FAILURE(rc))
4353 return rc;
4354 if (!HMR3IsEnabled(pUVM) && !NEMR3IsEnabled(pUVM))
4355 pThis->Dbgc.hDbgAs = DBGF_AS_RC_AND_GC_GLOBAL;
4356
4357 /*
4358 * Attach to the specified VM.
4359 */
4360 if (RT_SUCCESS(rc) && pUVM)
4361 {
4362 rc = DBGFR3Attach(pUVM);
4363 if (RT_SUCCESS(rc))
4364 {
4365 pThis->Dbgc.pVM = pVM;
4366 pThis->Dbgc.pUVM = pUVM;
4367 pThis->Dbgc.idCpu = 0;
4368 }
4369 else
4370 rc = pThis->Dbgc.CmdHlp.pfnVBoxError(&pThis->Dbgc.CmdHlp, rc, "When trying to attach to VM %p\n", pThis->Dbgc.pVM);
4371 }
4372
4373 /*
4374 * Load plugins.
4375 */
4376 if (RT_SUCCESS(rc))
4377 {
4378 if (pVM)
4379 DBGFR3PlugInLoadAll(pThis->Dbgc.pUVM);
4380 dbgcEventInit(&pThis->Dbgc);
4381
4382 /*
4383 * Run the debugger main loop.
4384 */
4385 rc = dbgcKdRun(pThis);
4386 dbgcEventTerm(&pThis->Dbgc);
4387 }
4388
4389 /*
4390 * Cleanup console debugger session.
4391 */
4392 dbgcKdCtxDestroy(pThis);
4393 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
4394}
4395
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette