VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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