VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp@ 84708

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

Debugger/DBGCGdbRemoteStub: Started with SMP support, bugref:5217

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.1 KB
Line 
1/* $Id: DBGCGdbRemoteStub.cpp 84707 2020-06-05 18:12:41Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, GDB Remote Stub.
4 */
5
6/*
7 * Copyright (C) 2010-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <VBox/dbg.h>
23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/vmapi.h> /* VMR3GetVM() */
25#include <VBox/vmm/hm.h> /* HMR3IsEnabled */
26#include <VBox/vmm/nem.h> /* NEMR3IsEnabled */
27#include <iprt/cdefs.h>
28#include <iprt/err.h>
29#include <iprt/list.h>
30#include <iprt/mem.h>
31#include <iprt/string.h>
32
33#include <stdlib.h>
34
35#include "DBGCInternal.h"
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41
42/** Character indicating the start of a packet. */
43#define GDBSTUB_PKT_START '$'
44/** Character indicating the end of a packet (excluding the checksum). */
45#define GDBSTUB_PKT_END '#'
46/** The escape character. */
47#define GDBSTUB_PKT_ESCAPE '{'
48/** The out-of-band interrupt character. */
49#define GDBSTUB_OOB_INTERRUPT 0x03
50
51
52/** Indicate support for the 'qXfer:features:read' packet to support the target description. */
53#define GDBSTUBCTX_FEATURES_F_TGT_DESC RT_BIT(0)
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59
60/**
61 * Trace point type.
62 */
63typedef enum GDBSTUBTPTYPE
64{
65 /** Invalid type, do not use. */
66 GDBSTUBTPTYPE_INVALID = 0,
67 /** An instruction software trace point. */
68 GDBSTUBTPTYPE_EXEC_SW,
69 /** An instruction hardware trace point. */
70 GDBSTUBTPTYPE_EXEC_HW,
71 /** A memory read trace point. */
72 GDBSTUBTPTYPE_MEM_READ,
73 /** A memory write trace point. */
74 GDBSTUBTPTYPE_MEM_WRITE,
75 /** A memory access trace point. */
76 GDBSTUBTPTYPE_MEM_ACCESS,
77 /** 32bit hack. */
78 GDBSTUBTPTYPE_32BIT_HACK = 0x7fffffff
79} GDBSTUBTPTYPE;
80
81
82/**
83 * GDB stub receive state.
84 */
85typedef enum GDBSTUBRECVSTATE
86{
87 /** Invalid state. */
88 GDBSTUBRECVSTATE_INVALID = 0,
89 /** Waiting for the start character. */
90 GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START,
91 /** Reiceiving the packet body up until the END character. */
92 GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY,
93 /** Receiving the checksum. */
94 GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM,
95 /** Blow up the enum to 32bits for easier alignment of members in structs. */
96 GDBSTUBRECVSTATE_32BIT_HACK = 0x7fffffff
97} GDBSTUBRECVSTATE;
98
99
100/**
101 * A tracepoint descriptor.
102 */
103typedef struct GDBSTUBTP
104{
105 /** List node for the list of tracepoints. */
106 RTLISTNODE NdTps;
107 /** The breakpoint number from the DBGF API. */
108 uint32_t iBp;
109 /** The tracepoint type for identification. */
110 GDBSTUBTPTYPE enmTpType;
111 /** The tracepoint address for identification. */
112 uint64_t GdbTgtAddr;
113 /** The tracepoint kind for identification. */
114 uint64_t uKind;
115} GDBSTUBTP;
116/** Pointer to a tracepoint. */
117typedef GDBSTUBTP *PGDBSTUBTP;
118
119
120/**
121 * GDB stub context data.
122 */
123typedef struct GDBSTUBCTX
124{
125 /** Internal debugger console data. */
126 DBGC Dbgc;
127 /** The current state when receiving a new packet. */
128 GDBSTUBRECVSTATE enmState;
129 /** Maximum number of bytes the packet buffer can hold. */
130 size_t cbPktBufMax;
131 /** Current offset into the packet buffer. */
132 size_t offPktBuf;
133 /** The size of the packet (minus the start, end characters and the checksum). */
134 size_t cbPkt;
135 /** Pointer to the packet buffer data. */
136 uint8_t *pbPktBuf;
137 /** Number of bytes left for the checksum. */
138 size_t cbChksumRecvLeft;
139 /** Send packet checksum. */
140 uint8_t uChkSumSend;
141 /** Feature flags supported we negotiated with the remote end. */
142 uint32_t fFeatures;
143 /** Pointer to the XML target description. */
144 char *pachTgtXmlDesc;
145 /** Size of the XML target description. */
146 size_t cbTgtXmlDesc;
147 /** Flag whether the stub is in extended mode. */
148 bool fExtendedMode;
149 /** Flag whether was something was output using the 'O' packet since it was reset last. */
150 bool fOutput;
151 /** List of registered trace points.
152 * GDB removes breakpoints/watchpoints using the parameters they were
153 * registered with while we only use the BP number form DBGF internally.
154 * Means we have to track all registration so we can remove them later on. */
155 RTLISTANCHOR LstTps;
156 /** Flag whether a ThreadInfo query was started. */
157 bool fInThrdInfoQuery;
158 /** Next ID to return in the current ThreadInfo query. */
159 VMCPUID idCpuNextThrdInfoQuery;
160} GDBSTUBCTX;
161/** Pointer to the GDB stub context data. */
162typedef GDBSTUBCTX *PGDBSTUBCTX;
163/** Pointer to const GDB stub context data. */
164typedef const GDBSTUBCTX *PCGDBSTUBCTX;
165/** Pointer to a GDB stub context data pointer. */
166typedef PGDBSTUBCTX *PPGDBSTUBCTX;
167
168
169/**
170 * Specific query packet processor callback.
171 *
172 * @returns Status code.
173 * @param pThis The GDB stub context.
174 * @param pbVal Pointer to the remaining value.
175 * @param cbVal Size of the remaining value in bytes.
176 */
177typedef DECLCALLBACK(int) FNGDBSTUBQPKTPROC(PGDBSTUBCTX pThis, const uint8_t *pbVal, size_t cbVal);
178typedef FNGDBSTUBQPKTPROC *PFNGDBSTUBQPKTPROC;
179
180
181/**
182 * 'q' packet processor.
183 */
184typedef struct GDBSTUBQPKTPROC
185{
186 /** Name */
187 const char *pszName;
188 /** Length of name in characters (without \0 terminator). */
189 uint32_t cchName;
190 /** The callback to call for processing the particular query. */
191 PFNGDBSTUBQPKTPROC pfnProc;
192} GDBSTUBQPKTPROC;
193/** Pointer to a 'q' packet processor entry. */
194typedef GDBSTUBQPKTPROC *PGDBSTUBQPKTPROC;
195/** Pointer to a const 'q' packet processor entry. */
196typedef const GDBSTUBQPKTPROC *PCGDBSTUBQPKTPROC;
197
198
199/**
200 * 'v' packet processor.
201 */
202typedef struct GDBSTUBVPKTPROC
203{
204 /** Name */
205 const char *pszName;
206 /** Length of name in characters (without \0 terminator). */
207 uint32_t cchName;
208 /** Replay to a query packet (ends with ?). */
209 const char *pszReplyQ;
210 /** Length of the query reply (without \0 terminator). */
211 uint32_t cchReplyQ;
212 /** The callback to call for processing the particular query. */
213 PFNGDBSTUBQPKTPROC pfnProc;
214} GDBSTUBVPKTPROC;
215/** Pointer to a 'q' packet processor entry. */
216typedef GDBSTUBVPKTPROC *PGDBSTUBVPKTPROC;
217/** Pointer to a const 'q' packet processor entry. */
218typedef const GDBSTUBVPKTPROC *PCGDBSTUBVPKTPROC;
219
220
221/**
222 * Feature callback.
223 *
224 * @returns Status code.
225 * @param pThis The GDB stub context.
226 * @param pbVal Pointer to the value.
227 * @param cbVal Size of the value in bytes.
228 */
229typedef DECLCALLBACK(int) FNGDBSTUBFEATHND(PGDBSTUBCTX pThis, const uint8_t *pbVal, size_t cbVal);
230typedef FNGDBSTUBFEATHND *PFNGDBSTUBFEATHND;
231
232
233/**
234 * GDB feature descriptor.
235 */
236typedef struct GDBSTUBFEATDESC
237{
238 /** Feature name */
239 const char *pszName;
240 /** Length of the feature name in characters (without \0 terminator). */
241 uint32_t cchName;
242 /** The callback to call for processing the particular feature. */
243 PFNGDBSTUBFEATHND pfnHandler;
244 /** Flag whether the feature requires a value. */
245 bool fVal;
246} GDBSTUBFEATDESC;
247/** Pointer to a GDB feature descriptor. */
248typedef GDBSTUBFEATDESC *PGDBSTUBFEATDESC;
249/** Pointer to a const GDB feature descriptor. */
250typedef const GDBSTUBFEATDESC *PCGDBSTUBFEATDESC;
251
252
253/*********************************************************************************************************************************
254* Internal Functions *
255*********************************************************************************************************************************/
256
257
258/**
259 * Tries to find a trace point with the given parameters in the list of registered trace points.
260 *
261 * @returns Pointer to the trace point registration record if found or NULL if none was found.
262 * @param pThis The GDB stub context.
263 * @param enmTpType The trace point type.
264 * @param GdbTgtAddr Target address given by GDB.
265 * @param uKind Trace point kind.
266 */
267static PGDBSTUBTP dbgcGdbStubTpFind(PGDBSTUBCTX pThis, GDBSTUBTPTYPE enmTpType, uint64_t GdbTgtAddr, uint64_t uKind)
268{
269 PGDBSTUBTP pTpCur = NULL;
270 RTListForEach(&pThis->LstTps, pTpCur, GDBSTUBTP, NdTps)
271 {
272 if ( pTpCur->enmTpType == enmTpType
273 && pTpCur->GdbTgtAddr == GdbTgtAddr
274 && pTpCur->uKind == uKind)
275 return pTpCur;
276 }
277
278 return NULL;
279}
280
281
282/**
283 * Registers a new trace point.
284 *
285 * @returns VBox status code.
286 * @param pThis The GDB stub context.
287 * @param enmTpType The trace point type.
288 * @param GdbTgtAddr Target address given by GDB.
289 * @param uKind Trace point kind.
290 * @param iBp The internal DBGF breakpoint ID this trace point was registered with.
291 */
292static int dbgcGdbStubTpRegister(PGDBSTUBCTX pThis, GDBSTUBTPTYPE enmTpType, uint64_t GdbTgtAddr, uint64_t uKind, uint32_t iBp)
293{
294 int rc = VERR_ALREADY_EXISTS;
295
296 /* Can't register a tracepoint with the same parameters twice or we can't decide whom to remove later on. */
297 PGDBSTUBTP pTp = dbgcGdbStubTpFind(pThis, enmTpType, GdbTgtAddr, uKind);
298 if (!pTp)
299 {
300 pTp = (PGDBSTUBTP)RTMemAllocZ(sizeof(*pTp));
301 if (pTp)
302 {
303 pTp->enmTpType = enmTpType;
304 pTp->GdbTgtAddr = GdbTgtAddr;
305 pTp->uKind = uKind;
306 pTp->iBp = iBp;
307 RTListAppend(&pThis->LstTps, &pTp->NdTps);
308 rc = VINF_SUCCESS;
309 }
310 else
311 rc = VERR_NO_MEMORY;
312 }
313
314 return rc;
315}
316
317
318/**
319 * Deregisters the given trace point (needs to be unregistered from DBGF by the caller before).
320 *
321 * @returns nothing.
322 * @param pTp The trace point to deregister.
323 */
324static void dbgcGdbStubTpDeregister(PGDBSTUBTP pTp)
325{
326 RTListNodeRemove(&pTp->NdTps);
327 RTMemFree(pTp);
328}
329
330
331/**
332 * Converts a given to the hexadecimal value if valid.
333 *
334 * @returns The hexadecimal value the given character represents 0-9,a-f,A-F or 0xff on error.
335 * @param ch The character to convert.
336 */
337DECLINLINE(uint8_t) dbgcGdbStubCtxChrToHex(char ch)
338{
339 if (ch >= '0' && ch <= '9')
340 return ch - '0';
341 if (ch >= 'A' && ch <= 'F')
342 return ch - 'A' + 0xa;
343 if (ch >= 'a' && ch <= 'f')
344 return ch - 'a' + 0xa;
345
346 return 0xff;
347}
348
349
350/**
351 * Converts a 4bit hex number to the appropriate character.
352 *
353 * @returns Character representing the 4bit hex number.
354 * @param uHex The 4 bit hex number.
355 */
356DECLINLINE(char) dbgcGdbStubCtxHexToChr(uint8_t uHex)
357{
358 if (uHex < 0xa)
359 return '0' + uHex;
360 if (uHex <= 0xf)
361 return 'A' + uHex - 0xa;
362
363 return 'X';
364}
365
366
367/**
368 * Wrapper for the I/O interface write callback.
369 *
370 * @returns Status code.
371 * @param pThis The GDB stub context.
372 * @param pvPkt The packet data to send.
373 * @param cbPkt Size of the packet in bytes.
374 */
375DECLINLINE(int) dbgcGdbStubCtxWrite(PGDBSTUBCTX pThis, const void *pvPkt, size_t cbPkt)
376{
377 return pThis->Dbgc.pBack->pfnWrite(pThis->Dbgc.pBack, pvPkt, cbPkt, NULL /*pcbWritten*/);
378}
379
380
381/**
382 * Starts transmission of a new reply packet.
383 *
384 * @returns Status code.
385 * @param pThis The GDB stub context.
386 */
387static int dbgcGdbStubCtxReplySendBegin(PGDBSTUBCTX pThis)
388{
389 pThis->uChkSumSend = 0;
390
391 uint8_t chPktStart = GDBSTUB_PKT_START;
392 return dbgcGdbStubCtxWrite(pThis, &chPktStart, sizeof(chPktStart));
393}
394
395
396/**
397 * Sends the given data in the reply.
398 *
399 * @returns Status code.
400 * @param pThis The GDB stub context.
401 * @param pvReplyData The reply data to send.
402 * @param cbReplyData Size of the reply data in bytes.
403 */
404static int dbgcGdbStubCtxReplySendData(PGDBSTUBCTX pThis, const void *pvReplyData, size_t cbReplyData)
405{
406 /* Update checksum. */
407 const uint8_t *pbData = (const uint8_t *)pvReplyData;
408 for (uint32_t i = 0; i < cbReplyData; i++)
409 pThis->uChkSumSend += pbData[i];
410
411 return dbgcGdbStubCtxWrite(pThis, pvReplyData, cbReplyData);
412}
413
414
415/**
416 * Finishes transmission of the current reply by sending the packet end character and the checksum.
417 *
418 * @returns Status code.
419 * @param pThis The GDB stub context.
420 */
421static int dbgcGdbStubCtxReplySendEnd(PGDBSTUBCTX pThis)
422{
423 uint8_t achPktEnd[3];
424
425 achPktEnd[0] = GDBSTUB_PKT_END;
426 achPktEnd[1] = dbgcGdbStubCtxHexToChr(pThis->uChkSumSend >> 4);
427 achPktEnd[2] = dbgcGdbStubCtxHexToChr(pThis->uChkSumSend & 0xf);
428
429 return dbgcGdbStubCtxWrite(pThis, &achPktEnd[0], sizeof(achPktEnd));
430}
431
432
433/**
434 * Sends the given reply packet, doing the framing, checksumming, etc. in one call.
435 *
436 * @returns Status code.
437 * @param pThis The GDB stub context.
438 * @param pvReplyPkt The reply packet to send.
439 * @param cbReplyPkt Size of the reply packet in bytes.
440 */
441static int dbgcGdbStubCtxReplySend(PGDBSTUBCTX pThis, const void *pvReplyPkt, size_t cbReplyPkt)
442{
443 int rc = dbgcGdbStubCtxReplySendBegin(pThis);
444 if (RT_SUCCESS(rc))
445 {
446 rc = dbgcGdbStubCtxReplySendData(pThis, pvReplyPkt, cbReplyPkt);
447 if (RT_SUCCESS(rc))
448 rc = dbgcGdbStubCtxReplySendEnd(pThis);
449 }
450
451 return rc;
452}
453
454
455/**
456 * Encodes the given buffer as a hexstring string it into the given destination buffer.
457 *
458 * @returns Status code.
459 * @param pbDst Where store the resulting hex string on success.
460 * @param cbDst Size of the destination buffer in bytes.
461 * @param pvSrc The data to encode.
462 * @param cbSrc Number of bytes to encode.
463 */
464DECLINLINE(int) dbgcGdbStubCtxEncodeBinaryAsHex(uint8_t *pbDst, size_t cbDst, const void *pvSrc, size_t cbSrc)
465{
466 return RTStrPrintHexBytes((char *)pbDst, cbDst, pvSrc, cbSrc, RTSTRPRINTHEXBYTES_F_UPPER);
467}
468
469
470/**
471 * Decodes the given ASCII hexstring as binary data up until the given separator is found or the end of the string is reached.
472 *
473 * @returns Status code.
474 * @param pbBuf The buffer containing the hexstring to convert.
475 * @param cbBuf Size of the buffer in bytes.
476 * @param puVal Where to store the decoded integer.
477 * @param chSep The character to stop conversion at.
478 * @param ppbSep Where to store the pointer in the buffer where the separator was found, optional.
479 */
480static int dbgcGdbStubCtxParseHexStringAsInteger(const uint8_t *pbBuf, size_t cbBuf, uint64_t *puVal, uint8_t chSep, const uint8_t **ppbSep)
481{
482 uint64_t uVal = 0;
483
484 while ( cbBuf
485 && *pbBuf != chSep)
486 {
487 uVal = uVal * 16 + dbgcGdbStubCtxChrToHex(*pbBuf++);
488 cbBuf--;
489 }
490
491 *puVal = uVal;
492
493 if (ppbSep)
494 *ppbSep = pbBuf;
495
496 return VINF_SUCCESS;
497}
498
499
500/**
501 * Decodes the given ASCII hexstring as a byte buffer up until the given separator is found or the end of the string is reached.
502 *
503 * @returns Status code.
504 * @param pbBuf The buffer containing the hexstring to convert.
505 * @param cbBuf Size of the buffer in bytes.
506 * @param pvDst Where to store the decoded data.
507 * @param cbDst Maximum buffer size in bytes.
508 * @param pcbDecoded Where to store the number of consumed bytes from the input.
509 */
510DECLINLINE(int) dbgcGdbStubCtxParseHexStringAsByteBuf(const uint8_t *pbBuf, size_t cbBuf, void *pvDst, size_t cbDst, size_t *pcbDecoded)
511{
512 size_t cbDecode = RT_MIN(cbBuf, cbDst * 2);
513
514 if (pcbDecoded)
515 *pcbDecoded = cbDecode;
516
517 return RTStrConvertHexBytes((const char *)pbBuf, pvDst, cbDecode, 0 /* fFlags*/);
518}
519
520#if 0 /*unused for now*/
521/**
522 * Sends a 'OK' part of a reply packet only (packet start and end needs to be handled separately).
523 *
524 * @returns Status code.
525 * @param pThis The GDB stub context.
526 */
527static int dbgcGdbStubCtxReplySendOkData(PGDBSTUBCTX pThis)
528{
529 char achOk[2] = { 'O', 'K' };
530 return dbgcGdbStubCtxReplySendData(pThis, &achOk[0], sizeof(achOk));
531}
532#endif
533
534
535/**
536 * Sends a 'OK' reply packet.
537 *
538 * @returns Status code.
539 * @param pThis The GDB stub context.
540 */
541static int dbgcGdbStubCtxReplySendOk(PGDBSTUBCTX pThis)
542{
543 char achOk[2] = { 'O', 'K' };
544 return dbgcGdbStubCtxReplySend(pThis, &achOk[0], sizeof(achOk));
545}
546
547#if 0 /*unused for now*/
548/**
549 * Sends a 'E NN' part of a reply packet only (packet start and end needs to be handled separately).
550 *
551 * @returns Status code.
552 * @param pThis The GDB stub context.
553 * @param uErr The error code to send.
554 */
555static int dbgcGdbStubCtxReplySendErrData(PGDBSTUBCTX pThis, uint8_t uErr)
556{
557 char achErr[3] = { 'E', 0, 0 };
558 achErr[1] = dbgcGdbStubCtxHexToChr(uErr >> 4);
559 achErr[2] = dbgcGdbStubCtxHexToChr(uErr & 0xf);
560 return dbgcGdbStubCtxReplySendData(pThis, &achErr[0], sizeof(achErr));
561}
562#endif
563
564/**
565 * Sends a 'E NN' reply packet.
566 *
567 * @returns Status code.
568 * @param pThis The GDB stub context.
569 * @param uErr The error code to send.
570 */
571static int dbgcGdbStubCtxReplySendErr(PGDBSTUBCTX pThis, uint8_t uErr)
572{
573 char achErr[3] = { 'E', 0, 0 };
574 achErr[1] = dbgcGdbStubCtxHexToChr(uErr >> 4);
575 achErr[2] = dbgcGdbStubCtxHexToChr(uErr & 0xf);
576 return dbgcGdbStubCtxReplySend(pThis, &achErr[0], sizeof(achErr));
577}
578
579
580/**
581 * Sends a signal trap (S 05) packet to indicate that the target has stopped.
582 *
583 * @returns Status code.
584 * @param pThis The GDB stub context.
585 */
586static int dbgcGdbStubCtxReplySendSigTrap(PGDBSTUBCTX pThis)
587{
588 char achReply[32];
589 ssize_t cchStr = RTStrPrintf2(&achReply[0], sizeof(achReply), "T05thread:%02x;", pThis->Dbgc.idCpu + 1);
590 return dbgcGdbStubCtxReplySend(pThis, &achReply[0], cchStr);
591}
592
593
594/**
595 * Sends a GDB stub status code indicating an error using the error reply packet.
596 *
597 * @returns Status code.
598 * @param pThis The GDB stub context.
599 * @param rc The status code to send.
600 */
601static int dbgcGdbStubCtxReplySendErrSts(PGDBSTUBCTX pThis, int rc)
602{
603 /** @todo convert error codes maybe. */
604 return dbgcGdbStubCtxReplySendErr(pThis, (-rc) & 0xff);
605}
606
607
608/**
609 * Ensures that there is at least the given amount of bytes of free space left in the packet buffer.
610 *
611 * @returns Status code (error when increasing the buffer failed).
612 * @param pThis The GDB stub context.
613 * @param cbSpace Number of bytes required.
614 */
615static int dbgcGdbStubCtxEnsurePktBufSpace(PGDBSTUBCTX pThis, size_t cbSpace)
616{
617 if (pThis->cbPktBufMax - pThis->offPktBuf >= cbSpace)
618 return VINF_SUCCESS;
619
620 /* Slow path allocate new buffer and copy content over. */
621 int rc = VINF_SUCCESS;
622 size_t cbPktBufMaxNew = pThis->cbPktBufMax + cbSpace;
623 void *pvNew = RTMemRealloc(pThis->pbPktBuf, cbPktBufMaxNew);
624 if (pvNew)
625 {
626 pThis->pbPktBuf = (uint8_t *)pvNew;
627 pThis->cbPktBufMax = cbPktBufMaxNew;
628 }
629 else
630 rc = VERR_NO_MEMORY;
631
632 return rc;
633}
634
635
636/**
637 * Parses the arguments of a 'Z' and 'z' packet.
638 *
639 * @returns Status code.
640 * @param pbArgs Pointer to the start of the first argument.
641 * @param cbArgs Number of argument bytes.
642 * @param penmTpType Where to store the tracepoint type on success.
643 * @param pGdbTgtAddr Where to store the address on success.
644 * @param puKind Where to store the kind argument on success.
645 */
646static int dbgcGdbStubCtxParseTpPktArgs(const uint8_t *pbArgs, size_t cbArgs, GDBSTUBTPTYPE *penmTpType, uint64_t *pGdbTgtAddr, uint64_t *puKind)
647{
648 const uint8_t *pbPktSep = NULL;
649 uint64_t uType = 0;
650
651 int rc = dbgcGdbStubCtxParseHexStringAsInteger(pbArgs, cbArgs, &uType,
652 ',', &pbPktSep);
653 if (RT_SUCCESS(rc))
654 {
655 cbArgs -= (uintptr_t)(pbPktSep - pbArgs) - 1;
656 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, cbArgs, pGdbTgtAddr,
657 ',', &pbPktSep);
658 if (RT_SUCCESS(rc))
659 {
660 cbArgs -= (uintptr_t)(pbPktSep - pbArgs) - 1;
661 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, cbArgs, puKind,
662 GDBSTUB_PKT_END, NULL);
663 if (RT_SUCCESS(rc))
664 {
665 switch (uType)
666 {
667 case 0:
668 *penmTpType = GDBSTUBTPTYPE_EXEC_SW;
669 break;
670 case 1:
671 *penmTpType = GDBSTUBTPTYPE_EXEC_HW;
672 break;
673 case 2:
674 *penmTpType = GDBSTUBTPTYPE_MEM_WRITE;
675 break;
676 case 3:
677 *penmTpType = GDBSTUBTPTYPE_MEM_READ;
678 break;
679 case 4:
680 *penmTpType = GDBSTUBTPTYPE_MEM_ACCESS;
681 break;
682 default:
683 rc = VERR_INVALID_PARAMETER;
684 break;
685 }
686 }
687 }
688 }
689
690 return rc;
691}
692
693
694/**
695 * Processes the 'TStatus' query.
696 *
697 * @returns Status code.
698 * @param pThis The GDB stub context.
699 * @param pbArgs Pointer to the start of the arguments in the packet.
700 * @param cbArgs Size of arguments in bytes.
701 */
702static int dbgcGdbStubCtxPktProcessQueryTStatus(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
703{
704 RT_NOREF(pbArgs, cbArgs);
705
706 char achReply[2] = { 'T', '0' };
707 return dbgcGdbStubCtxReplySend(pThis, &achReply[0], sizeof(achReply));
708}
709
710
711/**
712 * @copydoc FNGDBSTUBQPKTPROC
713 */
714static int dbgcGdbStubCtxPktProcessFeatXmlRegs(PGDBSTUBCTX pThis, const uint8_t *pbVal, size_t cbVal)
715{
716 /*
717 * xmlRegisters contain a list of supported architectures delimited by ','.
718 * Check that the architecture is in the supported list.
719 */
720 while (cbVal)
721 {
722 /* Find the next delimiter. */
723 size_t cbThisVal = cbVal;
724 const uint8_t *pbDelim = (const uint8_t *)memchr(pbVal, ',', cbVal);
725 if (pbDelim)
726 cbThisVal = pbDelim - pbVal;
727
728 size_t cchArch = sizeof("i386:x86-64") - 1;
729 if (!memcmp(pbVal, "i386:x86-64", RT_MIN(cbVal, cchArch)))
730 {
731 /* Set the flag to support the qXfer:features:read packet. */
732 pThis->fFeatures |= GDBSTUBCTX_FEATURES_F_TGT_DESC;
733 break;
734 }
735
736 cbVal -= cbThisVal + (pbDelim ? 1 : 0);
737 pbVal = pbDelim + (pbDelim ? 1 : 0);
738 }
739
740 return VINF_SUCCESS;
741}
742
743
744/**
745 * Features which can be reported by the remote GDB which we might support.
746 *
747 * @note The sorting matters for features which start the same, the longest must come first.
748 */
749static const GDBSTUBFEATDESC g_aGdbFeatures[] =
750{
751#define GDBSTUBFEATDESC_INIT(a_Name, a_pfnHnd, a_fVal) { a_Name, sizeof(a_Name) - 1, a_pfnHnd, a_fVal }
752 GDBSTUBFEATDESC_INIT("xmlRegisters", dbgcGdbStubCtxPktProcessFeatXmlRegs, true),
753#undef GDBSTUBFEATDESC_INIT
754};
755
756
757/**
758 * Calculates the feature length of the next feature pointed to by the given arguments buffer.
759 *
760 * @returns Status code.
761 * @param pbArgs Pointer to the start of the arguments in the packet.
762 * @param cbArgs Size of arguments in bytes.
763 * @param pcbArg Where to store the size of the argument in bytes on success (excluding the delimiter).
764 * @param pfTerminator Whereto store the flag whether the packet terminator (#) was seen as a delimiter.
765 */
766static int dbgcGdbStubCtxQueryPktQueryFeatureLen(const uint8_t *pbArgs, size_t cbArgs, size_t *pcbArg, bool *pfTerminator)
767{
768 const uint8_t *pbArgCur = pbArgs;
769
770 while ( cbArgs
771 && *pbArgCur != ';'
772 && *pbArgCur != GDBSTUB_PKT_END)
773 {
774 cbArgs--;
775 pbArgCur++;
776 }
777
778 if ( !cbArgs
779 && *pbArgCur != ';'
780 && *pbArgCur != GDBSTUB_PKT_END)
781 return VERR_NET_PROTOCOL_ERROR;
782
783 *pcbArg = pbArgCur - pbArgs;
784 *pfTerminator = *pbArgCur == GDBSTUB_PKT_END ? true : false;
785
786 return VINF_SUCCESS;
787}
788
789
790/**
791 * Sends the reply to the 'qSupported' packet.
792 *
793 * @returns Status code.
794 * @param pThis The GDB stub context.
795 */
796static int dbgcGdbStubCtxPktProcessQuerySupportedReply(PGDBSTUBCTX pThis)
797{
798 /** @todo Enhance. */
799 if (pThis->fFeatures & GDBSTUBCTX_FEATURES_F_TGT_DESC)
800 return dbgcGdbStubCtxReplySend(pThis, "qXfer:features:read+;vContSupported+", sizeof("qXfer:features:read+;vContSupported+") - 1);
801
802 return dbgcGdbStubCtxReplySend(pThis, NULL, 0);
803}
804
805
806/**
807 * Processes the 'Supported' query.
808 *
809 * @returns Status code.
810 * @param pThis The GDB stub context.
811 * @param pbArgs Pointer to the start of the arguments in the packet.
812 * @param cbArgs Size of arguments in bytes.
813 */
814static int dbgcGdbStubCtxPktProcessQuerySupported(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
815{
816 /* Skip the : following the qSupported start. */
817 if ( cbArgs < 1
818 || pbArgs[0] != ':')
819 return VERR_NET_PROTOCOL_ERROR;
820
821 cbArgs--;
822 pbArgs++;
823
824 /*
825 * Each feature but the last one are separated by ; and the last one is delimited by the # packet end symbol.
826 * We first determine the boundaries of the reported feature and pass it to the appropriate handler.
827 */
828 int rc = VINF_SUCCESS;
829 while ( cbArgs
830 && RT_SUCCESS(rc))
831 {
832 bool fTerminator = false;
833 size_t cbArg = 0;
834 rc = dbgcGdbStubCtxQueryPktQueryFeatureLen(pbArgs, cbArgs, &cbArg, &fTerminator);
835 if (RT_SUCCESS(rc))
836 {
837 /* Search for the feature handler. */
838 for (uint32_t i = 0; i < RT_ELEMENTS(g_aGdbFeatures); i++)
839 {
840 PCGDBSTUBFEATDESC pFeatDesc = &g_aGdbFeatures[i];
841
842 if ( cbArg > pFeatDesc->cchName /* At least one character must come after the feature name ('+', '-' or '='). */
843 && !memcmp(pFeatDesc->pszName, pbArgs, pFeatDesc->cchName))
844 {
845 /* Found, execute handler after figuring out whether there is a value attached. */
846 const uint8_t *pbVal = pbArgs + pFeatDesc->cchName;
847 size_t cbVal = cbArg - pFeatDesc->cchName;
848
849 if (pFeatDesc->fVal)
850 {
851 if ( *pbVal == '='
852 && cbVal > 1)
853 {
854 pbVal++;
855 cbVal--;
856 }
857 else
858 rc = VERR_NET_PROTOCOL_ERROR;
859 }
860 else if ( cbVal != 1
861 || ( *pbVal != '+'
862 && *pbVal != '-')) /* '+' and '-' are allowed to indicate support for a particular feature. */
863 rc = VERR_NET_PROTOCOL_ERROR;
864
865 if (RT_SUCCESS(rc))
866 rc = pFeatDesc->pfnHandler(pThis, pbVal, cbVal);
867 break;
868 }
869 }
870
871 cbArgs -= cbArg;
872 pbArgs += cbArg;
873 if (!fTerminator)
874 {
875 cbArgs--;
876 pbArgs++;
877 }
878 else
879 break;
880 }
881 }
882
883 /* If everything went alright send the reply with our supported features. */
884 if (RT_SUCCESS(rc))
885 rc = dbgcGdbStubCtxPktProcessQuerySupportedReply(pThis);
886
887 return rc;
888}
889
890
891/**
892 * Sends the reply to a 'qXfer:object:read:...' request.
893 *
894 * @returns Status code.
895 * @param pThis The GDB stub context.
896 * @param offRead Where to start reading from within the object.
897 * @param cbRead How much to read.
898 * @param pbObj The start of the object.
899 * @param cbObj Size of the object.
900 */
901static int dbgcGdbStubCtxQueryXferReadReply(PGDBSTUBCTX pThis, uint32_t offRead, size_t cbRead, const uint8_t *pbObj, size_t cbObj)
902{
903 int rc = VINF_SUCCESS;
904 if (offRead < cbObj)
905 {
906 /** @todo Escaping */
907 size_t cbThisRead = offRead + cbRead < cbObj ? cbRead : cbObj - offRead;
908
909 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbThisRead + 1);
910 if (RT_SUCCESS(rc))
911 {
912 uint8_t *pbPktBuf = pThis->pbPktBuf;
913 *pbPktBuf++ = cbThisRead < cbRead ? 'l' : 'm';
914 memcpy(pbPktBuf, pbObj + offRead, cbThisRead);
915 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbThisRead + 1);
916 }
917 else
918 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NO_MEMORY);
919 }
920 else if (offRead == cbObj)
921 rc = dbgcGdbStubCtxReplySend(pThis, "l", sizeof("l") - 1);
922 else
923 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
924
925 return rc;
926}
927
928
929/**
930 * Parses the annex:offset,length part of a 'qXfer:object:read:...' request.
931 *
932 * @returns Status code.
933 * @param pbArgs Start of the arguments beginning with annex.
934 * @param cbArgs Number of bytes remaining for the arguments.
935 * @param ppchAnnex Where to store the pointer to the beginning of the annex on success.
936 * @param pcchAnnex Where to store the number of characters for the annex on success.
937 * @param poffRead Where to store the offset on success.
938 * @param pcbRead Where to store the length on success.
939 */
940static int dbgcGdbStubCtxPktProcessQueryXferParseAnnexOffLen(const uint8_t *pbArgs, size_t cbArgs, const char **ppchAnnex, size_t *pcchAnnex,
941 uint32_t *poffRead, size_t *pcbRead)
942{
943 int rc = VINF_SUCCESS;
944 const uint8_t *pbSep = (const uint8_t *)memchr(pbArgs, ':', cbArgs);
945 if (pbSep)
946 {
947 *ppchAnnex = (const char *)pbArgs;
948 *pcchAnnex = pbSep - pbArgs;
949
950 pbSep++;
951 cbArgs -= *pcchAnnex + 1;
952
953 uint64_t u64Tmp = 0;
954 const uint8_t *pbLenStart = NULL;
955 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbSep, cbArgs, &u64Tmp, ',', &pbLenStart);
956 if ( RT_SUCCESS(rc)
957 && (uint32_t)u64Tmp == u64Tmp)
958 {
959 *poffRead = (uint32_t)u64Tmp;
960 cbArgs -= pbLenStart - pbSep;
961
962 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbLenStart + 1, cbArgs, &u64Tmp, '#', &pbLenStart);
963 if ( RT_SUCCESS(rc)
964 && (size_t)u64Tmp == u64Tmp)
965 *pcbRead = (size_t)u64Tmp;
966 else
967 rc = VERR_NET_PROTOCOL_ERROR;
968 }
969 else
970 rc = VERR_NET_PROTOCOL_ERROR;
971 }
972 else
973 rc = VERR_NET_PROTOCOL_ERROR;
974
975 return rc;
976}
977
978
979/**
980 * GDB registers.
981 */
982static const struct GDBREGDESC
983{
984 /** Register name. */
985 const char *pszName;
986 /** DBGF register index. */
987 DBGFREG enmReg;
988 /** Bitsize */
989 uint32_t cBits;
990 /** Type. */
991 const char *pszType;
992 /** Group. */
993 const char *pszGroup;
994} g_aGdbRegs[] =
995{
996#define DBGREG_DESC_INIT_INT64(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "int64", NULL }
997#define DBGREG_DESC_INIT_INT32(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 32, "int32", NULL }
998#define DBGREG_DESC_INIT_DATA_PTR(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "data_ptr", NULL }
999#define DBGREG_DESC_INIT_CODE_PTR(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "code_ptr", NULL }
1000#define DBGREG_DESC_INIT_X87(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 80, "i387_ext", NULL }
1001#define DBGREG_DESC_INIT_X87_CTRL(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 32, "int", "float" }
1002 DBGREG_DESC_INIT_INT64( "rax", DBGFREG_RAX),
1003 DBGREG_DESC_INIT_INT64( "rbx", DBGFREG_RBX),
1004 DBGREG_DESC_INIT_INT64( "rcx", DBGFREG_RCX),
1005 DBGREG_DESC_INIT_INT64( "rdx", DBGFREG_RDX),
1006 DBGREG_DESC_INIT_INT64( "rsi", DBGFREG_RSI),
1007 DBGREG_DESC_INIT_INT64( "rdi", DBGFREG_RDI),
1008 DBGREG_DESC_INIT_DATA_PTR("rbp", DBGFREG_RBP),
1009 DBGREG_DESC_INIT_DATA_PTR("rsp", DBGFREG_RSP),
1010 DBGREG_DESC_INIT_INT64( "r8", DBGFREG_R8),
1011 DBGREG_DESC_INIT_INT64( "r9", DBGFREG_R9),
1012 DBGREG_DESC_INIT_INT64( "r10", DBGFREG_R10),
1013 DBGREG_DESC_INIT_INT64( "r11", DBGFREG_R11),
1014 DBGREG_DESC_INIT_INT64( "r12", DBGFREG_R12),
1015 DBGREG_DESC_INIT_INT64( "r13", DBGFREG_R13),
1016 DBGREG_DESC_INIT_INT64( "r14", DBGFREG_R14),
1017 DBGREG_DESC_INIT_INT64( "r15", DBGFREG_R15),
1018 DBGREG_DESC_INIT_CODE_PTR("rip", DBGFREG_RIP),
1019 DBGREG_DESC_INIT_INT32( "eflags", DBGFREG_FLAGS),
1020 DBGREG_DESC_INIT_INT32( "cs", DBGFREG_CS),
1021 DBGREG_DESC_INIT_INT32( "ss", DBGFREG_SS),
1022 DBGREG_DESC_INIT_INT32( "ds", DBGFREG_DS),
1023 DBGREG_DESC_INIT_INT32( "es", DBGFREG_ES),
1024 DBGREG_DESC_INIT_INT32( "fs", DBGFREG_FS),
1025 DBGREG_DESC_INIT_INT32( "gs", DBGFREG_GS),
1026
1027 DBGREG_DESC_INIT_X87( "st0", DBGFREG_ST0),
1028 DBGREG_DESC_INIT_X87( "st1", DBGFREG_ST1),
1029 DBGREG_DESC_INIT_X87( "st2", DBGFREG_ST2),
1030 DBGREG_DESC_INIT_X87( "st3", DBGFREG_ST3),
1031 DBGREG_DESC_INIT_X87( "st4", DBGFREG_ST4),
1032 DBGREG_DESC_INIT_X87( "st5", DBGFREG_ST5),
1033 DBGREG_DESC_INIT_X87( "st6", DBGFREG_ST6),
1034 DBGREG_DESC_INIT_X87( "st7", DBGFREG_ST7),
1035
1036 DBGREG_DESC_INIT_X87_CTRL("fctrl", DBGFREG_FCW),
1037 DBGREG_DESC_INIT_X87_CTRL("fstat", DBGFREG_FSW),
1038 DBGREG_DESC_INIT_X87_CTRL("ftag", DBGFREG_FTW),
1039 DBGREG_DESC_INIT_X87_CTRL("fop", DBGFREG_FOP),
1040 DBGREG_DESC_INIT_X87_CTRL("fioff", DBGFREG_FPUIP),
1041 DBGREG_DESC_INIT_X87_CTRL("fiseg", DBGFREG_FPUCS),
1042 DBGREG_DESC_INIT_X87_CTRL("fooff", DBGFREG_FPUDP),
1043 DBGREG_DESC_INIT_X87_CTRL("foseg", DBGFREG_FPUDS)
1044
1045#undef DBGREG_DESC_INIT_CODE_PTR
1046#undef DBGREG_DESC_INIT_DATA_PTR
1047#undef DBGREG_DESC_INIT_INT32
1048#undef DBGREG_DESC_INIT_INT64
1049};
1050
1051
1052/**
1053 * Creates the target XML description.
1054 *
1055 * @returns Status code.
1056 * @param pThis The GDB stub context.
1057 */
1058static int dbgcGdbStubCtxTgtXmlDescCreate(PGDBSTUBCTX pThis)
1059{
1060 static const char s_szXmlTgtHdr[] =
1061 "<?xml version=\"1.0\"?>\n"
1062 "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
1063 "<target version=\"1.0\">\n"
1064 " <architecture>i386:x86-64</architecture>\n"
1065 " <feature name=\"org.gnu.gdb.i386.core\">\n";
1066 static const char s_szXmlTgtFooter[] =
1067 " </feature>\n"
1068 "</target>\n";
1069
1070 int rc = VINF_SUCCESS;
1071
1072 pThis->pachTgtXmlDesc = (char *)RTStrAlloc(_32K);
1073 if (pThis->pachTgtXmlDesc)
1074 {
1075 size_t cbLeft = _32K;
1076 char *pachXmlCur = pThis->pachTgtXmlDesc;
1077 pThis->cbTgtXmlDesc = cbLeft;
1078
1079 rc = RTStrCatP(&pachXmlCur, &cbLeft, &s_szXmlTgtHdr[0]);
1080 if (RT_SUCCESS(rc))
1081 {
1082 /* Register */
1083 for (uint32_t i = 0; i < RT_ELEMENTS(g_aGdbRegs) && RT_SUCCESS(rc); i++)
1084 {
1085 const struct GDBREGDESC *pReg = &g_aGdbRegs[i];
1086
1087 ssize_t cchStr = 0;
1088 if (pReg->pszGroup)
1089 cchStr = RTStrPrintf2(pachXmlCur, cbLeft,
1090 "<reg name=\"%s\" bitsize=\"%u\" regnum=\"%u\" type=\"%s\" group=\"%s\"/>\n",
1091 pReg->pszName, pReg->cBits, i, pReg->pszType, pReg->pszGroup);
1092 else
1093 cchStr = RTStrPrintf2(pachXmlCur, cbLeft,
1094 "<reg name=\"%s\" bitsize=\"%u\" regnum=\"%u\" type=\"%s\"/>\n",
1095 pReg->pszName, pReg->cBits, i, pReg->pszType);
1096
1097 if (cchStr > 0)
1098 {
1099 pachXmlCur += cchStr;
1100 cbLeft -= cchStr;
1101 }
1102 else
1103 rc = VERR_BUFFER_OVERFLOW;
1104 }
1105 }
1106
1107 if (RT_SUCCESS(rc))
1108 rc = RTStrCatP(&pachXmlCur, &cbLeft, &s_szXmlTgtFooter[0]);
1109
1110 pThis->cbTgtXmlDesc -= cbLeft;
1111 }
1112 else
1113 rc = VERR_NO_MEMORY;
1114
1115 return rc;
1116}
1117
1118
1119/**
1120 * Returns the GDB register descriptor describing the given DBGF register enum.
1121 *
1122 * @returns Pointer to the GDB register descriptor or NULL if not found.
1123 * @param idxReg The register to look for.
1124 */
1125static const GDBREGDESC *dbgcGdbStubRegGet(uint32_t idxReg)
1126{
1127 if (RT_LIKELY(idxReg < RT_ELEMENTS(g_aGdbRegs)))
1128 return &g_aGdbRegs[idxReg];
1129
1130 return NULL;
1131}
1132
1133
1134/**
1135 * Processes the 'C' query (query current thread ID).
1136 *
1137 * @returns Status code.
1138 * @param pThis The GDB stub context.
1139 * @param pbArgs Pointer to the start of the arguments in the packet.
1140 * @param cbArgs Size of arguments in bytes.
1141 */
1142static int dbgcGdbStubCtxPktProcessQueryThreadId(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1143{
1144 RT_NOREF(pbArgs, cbArgs);
1145
1146 int rc = VERR_BUFFER_OVERFLOW;
1147 char achReply[32];
1148 ssize_t cchStr = RTStrPrintf(&achReply[0], sizeof(achReply), "QC %02x", pThis->Dbgc.idCpu + 1);
1149 if (cchStr > 0)
1150 rc = dbgcGdbStubCtxReplySend(pThis, &achReply[0], cchStr);
1151
1152 return rc;
1153}
1154
1155
1156/**
1157 * Processes the 'Attached' query.
1158 *
1159 * @returns Status code.
1160 * @param pThis The GDB stub context.
1161 * @param pbArgs Pointer to the start of the arguments in the packet.
1162 * @param cbArgs Size of arguments in bytes.
1163 */
1164static int dbgcGdbStubCtxPktProcessQueryAttached(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1165{
1166 RT_NOREF(pbArgs, cbArgs);
1167
1168 /* We always report attached so that the VM doesn't get killed when GDB quits. */
1169 uint8_t bAttached = '1';
1170 return dbgcGdbStubCtxReplySend(pThis, &bAttached, sizeof(bAttached));
1171}
1172
1173
1174/**
1175 * Processes the 'Xfer:features:read' query.
1176 *
1177 * @returns Status code.
1178 * @param pThis The GDB stub context.
1179 * @param pbArgs Pointer to the start of the arguments in the packet.
1180 * @param cbArgs Size of arguments in bytes.
1181 */
1182static int dbgcGdbStubCtxPktProcessQueryXferFeatRead(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1183{
1184 /* Skip the : following the Xfer:features:read start. */
1185 if ( cbArgs < 1
1186 || pbArgs[0] != ':')
1187 return VERR_NET_PROTOCOL_ERROR;
1188
1189 cbArgs--;
1190 pbArgs++;
1191
1192 int rc = VINF_SUCCESS;
1193 if (pThis->fFeatures & GDBSTUBCTX_FEATURES_F_TGT_DESC)
1194 {
1195 /* Create the target XML description if not existing. */
1196 if (!pThis->pachTgtXmlDesc)
1197 rc = dbgcGdbStubCtxTgtXmlDescCreate(pThis);
1198
1199 if (RT_SUCCESS(rc))
1200 {
1201 /* Parse annex, offset and length and return the data. */
1202 const char *pchAnnex = NULL;
1203 size_t cchAnnex = 0;
1204 uint32_t offRead = 0;
1205 size_t cbRead = 0;
1206
1207 rc = dbgcGdbStubCtxPktProcessQueryXferParseAnnexOffLen(pbArgs, cbArgs,
1208 &pchAnnex, &cchAnnex,
1209 &offRead, &cbRead);
1210 if (RT_SUCCESS(rc))
1211 {
1212 /* Check whether the annex is supported. */
1213 if ( cchAnnex == sizeof("target.xml") - 1
1214 && !memcmp(pchAnnex, "target.xml", cchAnnex))
1215 rc = dbgcGdbStubCtxQueryXferReadReply(pThis, offRead, cbRead, (const uint8_t *)pThis->pachTgtXmlDesc,
1216 pThis->cbTgtXmlDesc);
1217 else
1218 rc = dbgcGdbStubCtxReplySendErr(pThis, 0);
1219 }
1220 else
1221 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1222 }
1223 else
1224 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1225 }
1226 else
1227 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0); /* Not supported. */
1228
1229 return rc;
1230}
1231
1232
1233/**
1234 * Processes the 'Rcmd' query.
1235 *
1236 * @returns Status code.
1237 * @param pThis The GDB stub context.
1238 * @param pbArgs Pointer to the start of the arguments in the packet.
1239 * @param cbArgs Size of arguments in bytes.
1240 */
1241static int dbgcGdbStubCtxPktProcessQueryRcmd(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1242{
1243 /* Skip the , following the qRcmd start. */
1244 if ( cbArgs < 1
1245 || pbArgs[0] != ',')
1246 return VERR_NET_PROTOCOL_ERROR;
1247
1248 cbArgs--;
1249 pbArgs++;
1250
1251 /* Decode the command. */
1252 /** @todo Make this dynamic. */
1253 char szCmd[_4K];
1254 RT_ZERO(szCmd);
1255
1256 if (cbArgs / 2 >= sizeof(szCmd))
1257 return VERR_NET_PROTOCOL_ERROR;
1258
1259 size_t cbDecoded = 0;
1260 int rc = RTStrConvertHexBytesEx((const char *)pbArgs, &szCmd[0], sizeof(szCmd), 0 /*fFlags*/,
1261 NULL /* ppszNext */, &cbDecoded);
1262 if (rc == VWRN_TRAILING_CHARS)
1263 rc = VINF_SUCCESS;
1264 if (RT_SUCCESS(rc))
1265 {
1266 szCmd[cbDecoded] = '\0'; /* Ensure zero termination. */
1267
1268 pThis->fOutput = false;
1269 rc = dbgcEvalCommand(&pThis->Dbgc, &szCmd[0], cbDecoded, false /*fNoExecute*/);
1270 dbgcGdbStubCtxReplySendOk(pThis);
1271 if ( rc != VERR_DBGC_QUIT
1272 && rc != VWRN_DBGC_CMD_PENDING)
1273 rc = VINF_SUCCESS; /* ignore other statuses */
1274 }
1275
1276 return rc;
1277}
1278
1279
1280/**
1281 * Worker for both 'qfThreadInfo' and 'qsThreadInfo'.
1282 *
1283 * @returns VBox status code.
1284 * @param pThis The GDB stub context.
1285 */
1286static int dbgcGdbStubCtxPktProcessQueryThreadInfoWorker(PGDBSTUBCTX pThis)
1287{
1288 int rc = dbgcGdbStubCtxReplySendBegin(pThis);
1289 if (RT_SUCCESS(rc))
1290 {
1291 uint8_t bReplyStart = { 'm' };
1292 rc = dbgcGdbStubCtxReplySendData(pThis, &bReplyStart, sizeof(bReplyStart));
1293 if (RT_SUCCESS(rc))
1294 {
1295 char achReply[32];
1296 ssize_t cchStr = RTStrPrintf(&achReply[0], sizeof(achReply), "%02x", pThis->idCpuNextThrdInfoQuery + 1);
1297 if (cchStr <= 0)
1298 rc = VERR_BUFFER_OVERFLOW;
1299
1300 if (RT_SUCCESS(rc))
1301 rc = dbgcGdbStubCtxReplySendData(pThis, &achReply[0], cchStr);
1302 pThis->idCpuNextThrdInfoQuery++;
1303 }
1304
1305 rc = dbgcGdbStubCtxReplySendEnd(pThis);
1306 }
1307
1308 return rc;
1309}
1310
1311
1312/**
1313 * Processes the 'fThreadInfo' query.
1314 *
1315 * @returns Status code.
1316 * @param pThis The GDB stub context.
1317 * @param pbArgs Pointer to the start of the arguments in the packet.
1318 * @param cbArgs Size of arguments in bytes.
1319 */
1320static int dbgcGdbStubCtxPktProcessQueryThreadInfoStart(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1321{
1322 RT_NOREF(pbArgs, cbArgs);
1323
1324 pThis->idCpuNextThrdInfoQuery = 0;
1325 pThis->fInThrdInfoQuery = true;
1326 return dbgcGdbStubCtxPktProcessQueryThreadInfoWorker(pThis);
1327}
1328
1329
1330/**
1331 * Processes the 'fThreadInfo' query.
1332 *
1333 * @returns Status code.
1334 * @param pThis The GDB stub context.
1335 * @param pbArgs Pointer to the start of the arguments in the packet.
1336 * @param cbArgs Size of arguments in bytes.
1337 */
1338static int dbgcGdbStubCtxPktProcessQueryThreadInfoCont(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1339{
1340 RT_NOREF(pbArgs, cbArgs);
1341
1342 /* If we are in a thread info query we just send the end of list specifier (all thread IDs where sent previously already). */
1343 if (!pThis->fInThrdInfoQuery)
1344 return dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1345
1346 VMCPUID cCpus = DBGFR3CpuGetCount(pThis->Dbgc.pUVM);
1347 if (pThis->idCpuNextThrdInfoQuery == cCpus)
1348 {
1349 pThis->fInThrdInfoQuery = false;
1350 uint8_t bEoL = 'l';
1351 return dbgcGdbStubCtxReplySend(pThis, &bEoL, sizeof(bEoL));
1352 }
1353
1354 return dbgcGdbStubCtxPktProcessQueryThreadInfoWorker(pThis);
1355}
1356
1357
1358/**
1359 * Processes the 'ThreadExtraInfo' query.
1360 *
1361 * @returns Status code.
1362 * @param pThis The GDB stub context.
1363 * @param pbArgs Pointer to the start of the arguments in the packet.
1364 * @param cbArgs Size of arguments in bytes.
1365 */
1366static int dbgcGdbStubCtxPktProcessQueryThreadExtraInfo(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1367{
1368 /* Skip the , following the qThreadExtraInfo start. */
1369 if ( cbArgs < 1
1370 || pbArgs[0] != ',')
1371 return VERR_NET_PROTOCOL_ERROR;
1372
1373 cbArgs--;
1374 pbArgs++;
1375
1376 /* We know there is an # character denoting the end so the following must return with VWRN_TRAILING_CHARS. */
1377 VMCPUID idCpu;
1378 int rc = RTStrToUInt32Ex((const char *)pbArgs, NULL /*ppszNext*/, 16, &idCpu);
1379 if ( rc == VWRN_TRAILING_CHARS
1380 && idCpu > 0)
1381 {
1382 idCpu--;
1383
1384 VMCPUID cCpus = DBGFR3CpuGetCount(pThis->Dbgc.pUVM);
1385 if (idCpu < cCpus)
1386 {
1387 const char *pszCpuState = DBGFR3CpuGetState(pThis->Dbgc.pUVM, idCpu);
1388 size_t cchCpuState = strlen(pszCpuState);
1389
1390 if (!pszCpuState)
1391 pszCpuState = "DBGFR3CpuGetState() -> NULL";
1392
1393 rc = dbgcGdbStubCtxReplySendBegin(pThis);
1394 if (RT_SUCCESS(rc))
1395 {
1396 /* Convert the characters to hex. */
1397 const char *pachCur = pszCpuState;
1398
1399 while ( cchCpuState
1400 && RT_SUCCESS(rc))
1401 {
1402 uint8_t achHex[512 + 1];
1403 size_t cbThisSend = RT_MIN((sizeof(achHex) - 1) / 2, cchCpuState); /* Each character needs two bytes. */
1404
1405 rc = dbgcGdbStubCtxEncodeBinaryAsHex(&achHex[0], cbThisSend * 2 + 1, pachCur, cbThisSend);
1406 if (RT_SUCCESS(rc))
1407 rc = dbgcGdbStubCtxReplySendData(pThis, &achHex[0], cbThisSend * 2);
1408
1409 pachCur += cbThisSend;
1410 cchCpuState -= cbThisSend;
1411 }
1412
1413 dbgcGdbStubCtxReplySendEnd(pThis);
1414 }
1415 }
1416 else
1417 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1418 }
1419 else if ( RT_SUCCESS(rc)
1420 || !idCpu)
1421 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1422
1423 return rc;
1424}
1425
1426
1427/**
1428 * List of supported query packets.
1429 */
1430static const GDBSTUBQPKTPROC g_aQPktProcs[] =
1431{
1432#define GDBSTUBQPKTPROC_INIT(a_Name, a_pfnProc) { a_Name, sizeof(a_Name) - 1, a_pfnProc }
1433 GDBSTUBQPKTPROC_INIT("C", dbgcGdbStubCtxPktProcessQueryThreadId),
1434 GDBSTUBQPKTPROC_INIT("Attached", dbgcGdbStubCtxPktProcessQueryAttached),
1435 GDBSTUBQPKTPROC_INIT("TStatus", dbgcGdbStubCtxPktProcessQueryTStatus),
1436 GDBSTUBQPKTPROC_INIT("Supported", dbgcGdbStubCtxPktProcessQuerySupported),
1437 GDBSTUBQPKTPROC_INIT("Xfer:features:read", dbgcGdbStubCtxPktProcessQueryXferFeatRead),
1438 GDBSTUBQPKTPROC_INIT("Rcmd", dbgcGdbStubCtxPktProcessQueryRcmd),
1439 GDBSTUBQPKTPROC_INIT("fThreadInfo", dbgcGdbStubCtxPktProcessQueryThreadInfoStart),
1440 GDBSTUBQPKTPROC_INIT("sThreadInfo", dbgcGdbStubCtxPktProcessQueryThreadInfoCont),
1441 GDBSTUBQPKTPROC_INIT("ThreadExtraInfo", dbgcGdbStubCtxPktProcessQueryThreadExtraInfo),
1442#undef GDBSTUBQPKTPROC_INIT
1443};
1444
1445
1446/**
1447 * Processes a 'q' packet, sending the appropriate reply.
1448 *
1449 * @returns Status code.
1450 * @param pThis The GDB stub context.
1451 * @param pbQuery The query packet data (without the 'q').
1452 * @param cbQuery Size of the remaining query packet in bytes.
1453 */
1454static int dbgcGdbStubCtxPktProcessQuery(PGDBSTUBCTX pThis, const uint8_t *pbQuery, size_t cbQuery)
1455{
1456 /* Search the query and execute the processor or return an empty reply if not supported. */
1457 for (uint32_t i = 0; i < RT_ELEMENTS(g_aQPktProcs); i++)
1458 {
1459 size_t cbCmp = g_aQPktProcs[i].cchName < cbQuery ? g_aQPktProcs[i].cchName : cbQuery;
1460
1461 if (!memcmp(pbQuery, g_aQPktProcs[i].pszName, cbCmp))
1462 return g_aQPktProcs[i].pfnProc(pThis, pbQuery + cbCmp, cbQuery - cbCmp);
1463 }
1464
1465 return dbgcGdbStubCtxReplySend(pThis, NULL, 0);
1466}
1467
1468
1469/**
1470 * Processes a 'vCont[;action[:thread-id]]' packet.
1471 *
1472 * @returns Status code.
1473 * @param pThis The GDB stub context.
1474 * @param pbArgs Pointer to the start of the arguments in the packet.
1475 * @param cbArgs Size of arguments in bytes.
1476 */
1477static int dbgcGdbStubCtxPktProcessVCont(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs)
1478{
1479 int rc = VINF_SUCCESS;
1480
1481 /* Skip the ; following the identifier. */
1482 if ( cbArgs < 2
1483 || pbArgs[0] != ';')
1484 return dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1485
1486 pbArgs++;
1487 cbArgs--;
1488
1489 /** @todo For now we don't care about multiple threads and ignore thread IDs and multiple actions. */
1490 switch (pbArgs[0])
1491 {
1492 case 'c':
1493 {
1494 if (DBGFR3IsHalted(pThis->Dbgc.pUVM))
1495 DBGFR3Resume(pThis->Dbgc.pUVM);
1496 break;
1497 }
1498 case 's':
1499 {
1500 PDBGFADDRESS pStackPop = NULL;
1501 RTGCPTR cbStackPop = 0;
1502 rc = DBGFR3StepEx(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGF_STEP_F_INTO, NULL,
1503 pStackPop, cbStackPop, 1 /*cMaxSteps*/);
1504 if (RT_FAILURE(rc))
1505 dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1506 break;
1507 }
1508 case 't':
1509 {
1510 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
1511 rc = DBGFR3Halt(pThis->Dbgc.pUVM);
1512 /* The reply will be send in the event loop. */
1513 break;
1514 }
1515 default:
1516 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1517 }
1518
1519 return rc;
1520}
1521
1522
1523/**
1524 * List of supported 'v<identifier>' packets.
1525 */
1526static const GDBSTUBVPKTPROC g_aVPktProcs[] =
1527{
1528#define GDBSTUBVPKTPROC_INIT(a_Name, a_pszReply, a_pfnProc) { a_Name, sizeof(a_Name) - 1, a_pszReply, sizeof(a_pszReply) - 1, a_pfnProc }
1529 GDBSTUBVPKTPROC_INIT("Cont", "vCont;s;c;t", dbgcGdbStubCtxPktProcessVCont)
1530#undef GDBSTUBVPKTPROC_INIT
1531};
1532
1533
1534/**
1535 * Processes a 'v<identifier>' packet, sending the appropriate reply.
1536 *
1537 * @returns Status code.
1538 * @param pThis The GDB stub context.
1539 * @param pbPktRem The remaining packet data (without the 'v').
1540 * @param cbPktRem Size of the remaining packet in bytes.
1541 */
1542static int dbgcGdbStubCtxPktProcessV(PGDBSTUBCTX pThis, const uint8_t *pbPktRem, size_t cbPktRem)
1543{
1544 /* Determine the end of the identifier, delimiters are '?', ';' or end of packet. */
1545 bool fQuery = false;
1546 const uint8_t *pbDelim = (const uint8_t *)memchr(pbPktRem, '?', cbPktRem);
1547 if (!pbDelim)
1548 pbDelim = (const uint8_t *)memchr(pbPktRem, ';', cbPktRem);
1549 else
1550 fQuery = true;
1551
1552 size_t cchId = 0;
1553 if (pbDelim) /* Delimiter found, calculate length. */
1554 cchId = pbDelim - pbPktRem;
1555 else /* Not found, size goes till end of packet. */
1556 cchId = cbPktRem;
1557
1558 /* Search the query and execute the processor or return an empty reply if not supported. */
1559 for (uint32_t i = 0; i < RT_ELEMENTS(g_aVPktProcs); i++)
1560 {
1561 PCGDBSTUBVPKTPROC pVProc = &g_aVPktProcs[i];
1562
1563 if ( pVProc->cchName == cchId
1564 && !memcmp(pbPktRem, pVProc->pszName, cchId))
1565 {
1566 /* Just send the static reply for a query and execute the processor for everything else. */
1567 if (fQuery)
1568 return dbgcGdbStubCtxReplySend(pThis, pVProc->pszReplyQ, pVProc->cchReplyQ);
1569
1570 /* Execute the handler. */
1571 return pVProc->pfnProc(pThis, pbPktRem + cchId, cbPktRem - cchId);
1572 }
1573 }
1574
1575 return dbgcGdbStubCtxReplySend(pThis, NULL, 0);
1576}
1577
1578
1579/**
1580 * Processes a 'H<op><thread-id>' packet, sending the appropriate reply.
1581 *
1582 * @returns Status code.
1583 * @param pThis The GDB stub context.
1584 * @param pbPktRem The remaining packet data (without the 'H').
1585 * @param cbPktRem Size of the remaining packet in bytes.
1586 */
1587static int dbgcGdbStubCtxPktProcessH(PGDBSTUBCTX pThis, const uint8_t *pbPktRem, size_t cbPktRem)
1588{
1589 int rc = VINF_SUCCESS;
1590
1591 if (*pbPktRem == 'g')
1592 {
1593 cbPktRem--;
1594 pbPktRem++;
1595
1596 /* We know there is an # character denoting the end so the following must return with VWRN_TRAILING_CHARS. */
1597 VMCPUID idCpu;
1598 rc = RTStrToUInt32Ex((const char *)pbPktRem, NULL /*ppszNext*/, 16, &idCpu);
1599 if ( rc == VWRN_TRAILING_CHARS
1600 && idCpu > 0)
1601 {
1602 idCpu--;
1603
1604 VMCPUID cCpus = DBGFR3CpuGetCount(pThis->Dbgc.pUVM);
1605 if (idCpu < cCpus)
1606 {
1607 pThis->Dbgc.idCpu = idCpu;
1608 rc = dbgcGdbStubCtxReplySendOk(pThis);
1609 }
1610 else
1611 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1612 }
1613 else
1614 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1615 }
1616 else /* Do not support the 'c' operation for now (will be handled through vCont later on anyway). */
1617 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0);
1618
1619 return rc;
1620}
1621
1622
1623/**
1624 * Processes a completely received packet.
1625 *
1626 * @returns Status code.
1627 * @param pThis The GDB stub context.
1628 */
1629static int dbgcGdbStubCtxPktProcess(PGDBSTUBCTX pThis)
1630{
1631 int rc = VINF_SUCCESS;
1632
1633 if (pThis->cbPkt >= 1)
1634 {
1635 switch (pThis->pbPktBuf[1])
1636 {
1637 case '!': /* Enabled extended mode. */
1638 {
1639 pThis->fExtendedMode = true;
1640 rc = dbgcGdbStubCtxReplySendOk(pThis);
1641 break;
1642 }
1643 case '?':
1644 {
1645 /* Return signal state. */
1646 rc = dbgcGdbStubCtxReplySendSigTrap(pThis);
1647 break;
1648 }
1649 case 's': /* Single step, response will be sent in the event loop. */
1650 {
1651 PDBGFADDRESS pStackPop = NULL;
1652 RTGCPTR cbStackPop = 0;
1653 rc = DBGFR3StepEx(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGF_STEP_F_INTO, NULL,
1654 pStackPop, cbStackPop, 1 /*cMaxSteps*/);
1655 if (RT_FAILURE(rc))
1656 dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1657 break;
1658 }
1659 case 'c': /* Continue, no response */
1660 {
1661 if (DBGFR3IsHalted(pThis->Dbgc.pUVM))
1662 DBGFR3Resume(pThis->Dbgc.pUVM);
1663 break;
1664 }
1665 case 'H':
1666 {
1667 rc = dbgcGdbStubCtxPktProcessH(pThis, &pThis->pbPktBuf[2], pThis->cbPkt - 1);
1668 break;
1669 }
1670 case 'T':
1671 {
1672 rc = dbgcGdbStubCtxReplySendOk(pThis);
1673 break;
1674 }
1675 case 'g': /* Read general registers. */
1676 {
1677 uint32_t idxRegMax = 0;
1678 size_t cbRegs = 0;
1679 for (;;)
1680 {
1681 const GDBREGDESC *pReg = &g_aGdbRegs[idxRegMax++];
1682 cbRegs += pReg->cBits / 8;
1683 if (pReg->enmReg == DBGFREG_SS) /* Up to this seems to belong to the general register set. */
1684 break;
1685 }
1686
1687 size_t cbReplyPkt = cbRegs * 2 + 1; /* One byte needs two characters. */
1688 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt);
1689 if (RT_SUCCESS(rc))
1690 {
1691 size_t cbLeft = cbReplyPkt;
1692 uint8_t *pbReply = pThis->pbPktBuf;
1693
1694 for (uint32_t i = 0; i < idxRegMax && RT_SUCCESS(rc); i++)
1695 {
1696 const GDBREGDESC *pReg = &g_aGdbRegs[i];
1697 size_t cbReg = pReg->cBits / 8;
1698 union
1699 {
1700 uint32_t u32;
1701 uint64_t u64;
1702 uint8_t au8[8];
1703 } RegVal;
1704
1705 if (pReg->cBits == 32)
1706 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->enmReg, &RegVal.u32);
1707 else
1708 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->enmReg, &RegVal.u64);
1709
1710 if (RT_SUCCESS(rc))
1711 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pbReply, cbLeft, &RegVal.au8[0], cbReg);
1712
1713 pbReply += cbReg * 2;
1714 cbLeft -= cbReg * 2;
1715 }
1716
1717 if (RT_SUCCESS(rc))
1718 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt);
1719 else
1720 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1721 }
1722
1723 break;
1724 }
1725 case 'm': /* Read memory. */
1726 {
1727 uint64_t GdbTgtAddr = 0;
1728 const uint8_t *pbPktSep = NULL;
1729
1730 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &GdbTgtAddr,
1731 ',', &pbPktSep);
1732 if (RT_SUCCESS(rc))
1733 {
1734 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2];
1735 uint64_t cbRead = 0;
1736 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &cbRead, GDBSTUB_PKT_END, NULL);
1737 if (RT_SUCCESS(rc))
1738 {
1739 size_t cbReplyPkt = cbRead * 2 + 1; /* One byte needs two characters. */
1740
1741 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt);
1742 if (RT_SUCCESS(rc))
1743 {
1744 uint8_t *pbPktBuf = pThis->pbPktBuf;
1745 size_t cbPktBufLeft = cbReplyPkt;
1746 DBGFADDRESS AddrRead;
1747
1748 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrRead, GdbTgtAddr);
1749
1750 while ( cbRead
1751 && RT_SUCCESS(rc))
1752 {
1753 uint8_t abTmp[_4K];
1754 size_t cbThisRead = RT_MIN(cbRead, sizeof(abTmp));
1755
1756 rc = DBGFR3MemRead(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrRead, &abTmp[0], cbThisRead);
1757 if (RT_FAILURE(rc))
1758 break;
1759
1760 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pbPktBuf, cbPktBufLeft, &abTmp[0], cbThisRead);
1761 if (RT_FAILURE(rc))
1762 break;
1763
1764 DBGFR3AddrAdd(&AddrRead, cbThisRead);
1765 cbRead -= cbThisRead;
1766 pbPktBuf += cbThisRead;
1767 cbPktBufLeft -= cbThisRead;
1768 }
1769
1770 if (RT_SUCCESS(rc))
1771 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt);
1772 else
1773 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1774 }
1775 else
1776 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1777 }
1778 else
1779 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1780 }
1781 else
1782 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1783 break;
1784 }
1785 case 'M': /* Write memory. */
1786 {
1787 uint64_t GdbTgtAddr = 0;
1788 const uint8_t *pbPktSep = NULL;
1789
1790 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &GdbTgtAddr,
1791 ',', &pbPktSep);
1792 if (RT_SUCCESS(rc))
1793 {
1794 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2];
1795 uint64_t cbWrite = 0;
1796 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &cbWrite, ':', &pbPktSep);
1797 if (RT_SUCCESS(rc))
1798 {
1799 cbProcessed = pbPktSep - &pThis->pbPktBuf[2];
1800 const uint8_t *pbDataCur = pbPktSep + 1;
1801 size_t cbDataLeft = pThis->cbPkt - 1 - cbProcessed - 1 - 1;
1802 DBGFADDRESS AddrWrite;
1803
1804 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrWrite, GdbTgtAddr);
1805
1806 while ( cbWrite
1807 && RT_SUCCESS(rc))
1808 {
1809 uint8_t abTmp[_4K];
1810 size_t cbThisWrite = RT_MIN(cbWrite, sizeof(abTmp));
1811 size_t cbDecoded = 0;
1812
1813 rc = dbgcGdbStubCtxParseHexStringAsByteBuf(pbDataCur, cbDataLeft, &abTmp[0], cbThisWrite, &cbDecoded);
1814 if (!rc)
1815 rc = DBGFR3MemWrite(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrWrite, &abTmp[0], cbThisWrite);
1816
1817 DBGFR3AddrAdd(&AddrWrite, cbThisWrite);
1818 cbWrite -= cbThisWrite;
1819 pbDataCur += cbDecoded;
1820 cbDataLeft -= cbDecoded;
1821 }
1822
1823 if (RT_SUCCESS(rc))
1824 rc = dbgcGdbStubCtxReplySendOk(pThis);
1825 else
1826 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1827 }
1828 else
1829 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1830 }
1831 else
1832 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1833 break;
1834 }
1835 case 'p': /* Read a single register */
1836 {
1837 uint64_t uReg = 0;
1838 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &uReg,
1839 GDBSTUB_PKT_END, NULL);
1840 if (RT_SUCCESS(rc))
1841 {
1842 DBGFREGVAL RegVal;
1843 DBGFREGVALTYPE enmType;
1844 const GDBREGDESC *pReg = dbgcGdbStubRegGet(uReg);
1845 if (RT_LIKELY(pReg))
1846 {
1847 rc = DBGFR3RegNmQuery(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->pszName, &RegVal, &enmType);
1848 if (RT_SUCCESS(rc))
1849 {
1850 size_t cbReg = pReg->cBits / 8;
1851 size_t cbReplyPkt = cbReg * 2 + 1; /* One byte needs two characters. */
1852
1853 /* Encode data and send. */
1854 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt);
1855 if (RT_SUCCESS(rc))
1856 {
1857 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pThis->pbPktBuf, pThis->cbPktBufMax, &RegVal.au8[0], cbReg);
1858 if (RT_SUCCESS(rc))
1859 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt);
1860 else
1861 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1862 }
1863 else
1864 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1865 }
1866 else
1867 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1868 }
1869 else
1870 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1871 }
1872 else
1873 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1874 break;
1875 }
1876 case 'P': /* Write a single register */
1877 {
1878 uint64_t uReg = 0;
1879 const uint8_t *pbPktSep = NULL;
1880 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &uReg,
1881 '=', &pbPktSep);
1882 if (RT_SUCCESS(rc))
1883 {
1884 const GDBREGDESC *pReg = dbgcGdbStubRegGet(uReg);
1885
1886 if (pReg)
1887 {
1888 DBGFREGVAL RegVal;
1889 DBGFREGVALTYPE enmValType = pReg->cBits == 64 ? DBGFREGVALTYPE_U64 : DBGFREGVALTYPE_U32;
1890 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2];
1891 rc = dbgcGdbStubCtxParseHexStringAsByteBuf(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &RegVal.au8[0], pReg->cBits / 8, NULL);
1892 if (RT_SUCCESS(rc))
1893 {
1894 rc = DBGFR3RegNmSet(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->pszName, &RegVal, enmValType);
1895 if (RT_SUCCESS(rc))
1896 rc = dbgcGdbStubCtxReplySendOk(pThis);
1897 else
1898 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1899 }
1900 }
1901 else
1902 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR);
1903 }
1904 else
1905 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1906 break;
1907 }
1908 case 'Z': /* Insert a breakpoint/watchpoint. */
1909 {
1910 GDBSTUBTPTYPE enmTpType = GDBSTUBTPTYPE_INVALID;
1911 uint64_t GdbTgtTpAddr = 0;
1912 uint64_t uKind = 0;
1913
1914 rc = dbgcGdbStubCtxParseTpPktArgs(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &enmTpType, &GdbTgtTpAddr, &uKind);
1915 if (RT_SUCCESS(rc))
1916 {
1917 uint32_t iBp = 0;
1918 DBGFADDRESS BpAddr;
1919 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &BpAddr, GdbTgtTpAddr);
1920
1921 switch (enmTpType)
1922 {
1923 case GDBSTUBTPTYPE_EXEC_SW:
1924 {
1925 rc = DBGFR3BpSetInt3(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &BpAddr,
1926 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, &iBp);
1927 break;
1928 }
1929 case GDBSTUBTPTYPE_EXEC_HW:
1930 {
1931 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr,
1932 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/,
1933 X86_DR7_RW_EO, 1 /*cb*/, &iBp);
1934 break;
1935 }
1936 case GDBSTUBTPTYPE_MEM_ACCESS:
1937 case GDBSTUBTPTYPE_MEM_READ:
1938 {
1939 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr,
1940 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/,
1941 X86_DR7_RW_RW, uKind /*cb*/, &iBp);
1942 break;
1943 }
1944 case GDBSTUBTPTYPE_MEM_WRITE:
1945 {
1946 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr,
1947 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/,
1948 X86_DR7_RW_WO, uKind /*cb*/, &iBp);
1949 break;
1950 }
1951 default:
1952 AssertMsgFailed(("Invalid trace point type %d\n", enmTpType));
1953 }
1954
1955 if (RT_SUCCESS(rc))
1956 {
1957 rc = dbgcBpAdd(&pThis->Dbgc, iBp, NULL /*pszCmd*/);
1958 if (RT_SUCCESS(rc))
1959 {
1960 rc = dbgcGdbStubTpRegister(pThis, enmTpType, GdbTgtTpAddr, uKind, iBp);
1961 if (RT_SUCCESS(rc))
1962 rc = dbgcGdbStubCtxReplySendOk(pThis);
1963 else
1964 dbgcBpDelete(&pThis->Dbgc, iBp);
1965 }
1966
1967 if (RT_FAILURE(rc))
1968 {
1969 DBGFR3BpClear(pThis->Dbgc.pUVM, iBp);
1970 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1971 }
1972 }
1973 else
1974 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1975 }
1976 else
1977 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
1978 break;
1979 }
1980 case 'z': /* Remove a breakpoint/watchpoint. */
1981 {
1982 GDBSTUBTPTYPE enmTpType = GDBSTUBTPTYPE_INVALID;
1983 uint64_t GdbTgtTpAddr = 0;
1984 uint64_t uKind = 0;
1985
1986 rc = dbgcGdbStubCtxParseTpPktArgs(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &enmTpType, &GdbTgtTpAddr, &uKind);
1987 if (RT_SUCCESS(rc))
1988 {
1989 PGDBSTUBTP pTp = dbgcGdbStubTpFind(pThis, enmTpType, GdbTgtTpAddr, uKind);
1990 if (pTp)
1991 {
1992 int rc2 = DBGFR3BpClear(pThis->Dbgc.pUVM, pTp->iBp);
1993 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
1994 dbgcBpDelete(&pThis->Dbgc, pTp->iBp);
1995
1996 if (RT_SUCCESS(rc2))
1997 {
1998 dbgcGdbStubTpDeregister(pTp);
1999 rc = dbgcGdbStubCtxReplySendOk(pThis);
2000 }
2001 else
2002 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
2003 }
2004 else
2005 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NOT_FOUND);
2006 }
2007 else
2008 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc);
2009 break;
2010 }
2011 case 'q': /* Query packet */
2012 {
2013 rc = dbgcGdbStubCtxPktProcessQuery(pThis, &pThis->pbPktBuf[2], pThis->cbPkt - 1);
2014 break;
2015 }
2016 case 'v': /* Multiletter identifier (verbose?) */
2017 {
2018 rc = dbgcGdbStubCtxPktProcessV(pThis, &pThis->pbPktBuf[2], pThis->cbPkt - 1);
2019 break;
2020 }
2021 case 'R': /* Restart target. */
2022 {
2023 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0);
2024 break;
2025 }
2026 case 'k': /* Kill target. */
2027 {
2028 /* This is what the 'harakiri' command is doing. */
2029 for (;;)
2030 exit(126);
2031 break;
2032 }
2033 case 'D': /* Detach */
2034 {
2035 rc = dbgcGdbStubCtxReplySendOk(pThis);
2036 if (RT_SUCCESS(rc))
2037 rc = VERR_DBGC_QUIT;
2038 break;
2039 }
2040 default:
2041 /* Not supported, send empty reply. */
2042 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0);
2043 }
2044 }
2045
2046 return rc;
2047}
2048
2049
2050/**
2051 * Resets the packet buffer.
2052 *
2053 * @returns nothing.
2054 * @param pThis The GDB stub context.
2055 */
2056static void dbgcGdbStubCtxPktBufReset(PGDBSTUBCTX pThis)
2057{
2058 pThis->offPktBuf = 0;
2059 pThis->cbPkt = 0;
2060 pThis->cbChksumRecvLeft = 2;
2061}
2062
2063
2064/**
2065 * Resets the given GDB stub context to the initial state.
2066 *
2067 * @returns nothing.
2068 * @param pThis The GDB stub context.
2069 */
2070static void dbgcGdbStubCtxReset(PGDBSTUBCTX pThis)
2071{
2072 pThis->enmState = GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START;
2073 dbgcGdbStubCtxPktBufReset(pThis);
2074}
2075
2076
2077/**
2078 * Searches for the start character in the current data buffer.
2079 *
2080 * @returns Status code.
2081 * @param pThis The GDB stub context.
2082 * @param cbData Number of new bytes in the packet buffer.
2083 * @param pcbProcessed Where to store the amount of bytes processed.
2084 */
2085static int dbgcGdbStubCtxPktBufSearchStart(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed)
2086{
2087 int rc = VINF_SUCCESS;
2088 const uint8_t *pbStart = (const uint8_t *)memchr(pThis->pbPktBuf, GDBSTUB_PKT_START, cbData);
2089 if (pbStart)
2090 {
2091 /* Found the start character, align the start to the beginning of the packet buffer and advance the state machine. */
2092 memmove(pThis->pbPktBuf, pbStart, cbData - (pbStart - pThis->pbPktBuf));
2093 pThis->enmState = GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY;
2094 *pcbProcessed = (uintptr_t)(pbStart - pThis->pbPktBuf);
2095 pThis->offPktBuf = 0;
2096 }
2097 else
2098 {
2099 /* Check for out of band characters. */
2100 if (memchr(pThis->pbPktBuf, GDBSTUB_OOB_INTERRUPT, cbData) != NULL)
2101 {
2102 /* Stop target and send packet to indicate the target has stopped. */
2103 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
2104 rc = DBGFR3Halt(pThis->Dbgc.pUVM);
2105 /* The reply will be send in the event loop. */
2106 }
2107
2108 /* Not found, ignore the received data and reset the packet buffer. */
2109 dbgcGdbStubCtxPktBufReset(pThis);
2110 *pcbProcessed = cbData;
2111 }
2112
2113 return rc;
2114}
2115
2116
2117/**
2118 * Searches for the end character in the current data buffer.
2119 *
2120 * @returns Status code.
2121 * @param pThis The GDB stub context.
2122 * @param cbData Number of new bytes in the packet buffer.
2123 * @param pcbProcessed Where to store the amount of bytes processed.
2124 */
2125static int dbgcGdbStubCtxPktBufSearchEnd(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed)
2126{
2127 const uint8_t *pbEnd = (const uint8_t *)memchr(&pThis->pbPktBuf[pThis->offPktBuf], GDBSTUB_PKT_END, cbData);
2128 if (pbEnd)
2129 {
2130 /* Found the end character, next comes the checksum. */
2131 pThis->enmState = GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM;
2132
2133 *pcbProcessed = (uintptr_t)(pbEnd - &pThis->pbPktBuf[pThis->offPktBuf]) + 1;
2134 pThis->offPktBuf += *pcbProcessed;
2135 pThis->cbPkt = pThis->offPktBuf - 1; /* Don't account for the start and end character. */
2136 }
2137 else
2138 {
2139 /* Not found, still in the middle of a packet. */
2140 /** @todo Look for out of band characters. */
2141 *pcbProcessed = cbData;
2142 pThis->offPktBuf += cbData;
2143 }
2144
2145 return VINF_SUCCESS;
2146}
2147
2148
2149/**
2150 * Processes the checksum.
2151 *
2152 * @returns Status code.
2153 * @param pThis The GDB stub context.
2154 * @param cbData Number of new bytes in the packet buffer.
2155 * @param pcbProcessed Where to store the amount of bytes processed.
2156 */
2157static int dbgcGdbStubCtxPktBufProcessChksum(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed)
2158{
2159 int rc = VINF_SUCCESS;
2160 size_t cbChksumProcessed = (cbData < pThis->cbChksumRecvLeft) ? cbData : pThis->cbChksumRecvLeft;
2161
2162 pThis->cbChksumRecvLeft -= cbChksumProcessed;
2163 if (!pThis->cbChksumRecvLeft)
2164 {
2165 /* Verify checksum of the whole packet. */
2166 uint8_t uChkSum = dbgcGdbStubCtxChrToHex(pThis->pbPktBuf[pThis->offPktBuf]) << 4
2167 | dbgcGdbStubCtxChrToHex(pThis->pbPktBuf[pThis->offPktBuf + 1]);
2168
2169 uint8_t uSum = 0;
2170 for (size_t i = 1; i < pThis->cbPkt; i++)
2171 uSum += pThis->pbPktBuf[i];
2172
2173 if (uSum == uChkSum)
2174 {
2175 /* Checksum matches, send acknowledge and continue processing the complete payload. */
2176 char chAck = '+';
2177 rc = dbgcGdbStubCtxWrite(pThis, &chAck, sizeof(chAck));
2178 if (RT_SUCCESS(rc))
2179 rc = dbgcGdbStubCtxPktProcess(pThis);
2180 }
2181 else
2182 {
2183 /* Send NACK and reset for the next packet. */
2184 char chAck = '-';
2185 rc = dbgcGdbStubCtxWrite(pThis, &chAck, sizeof(chAck));
2186 }
2187
2188 dbgcGdbStubCtxReset(pThis);
2189 }
2190
2191 *pcbProcessed += cbChksumProcessed;
2192 return rc;
2193}
2194
2195
2196/**
2197 * Process read data in the packet buffer based on the current state.
2198 *
2199 * @returns Status code.
2200 * @param pThis The GDB stub context.
2201 * @param cbData Number of new bytes in the packet buffer.
2202 */
2203static int dbgcGdbStubCtxPktBufProcess(PGDBSTUBCTX pThis, size_t cbData)
2204{
2205 int rc = VINF_SUCCESS;
2206
2207 while ( cbData
2208 && RT_SUCCESS(rc))
2209 {
2210 size_t cbProcessed = 0;
2211
2212 switch (pThis->enmState)
2213 {
2214 case GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START:
2215 {
2216 rc = dbgcGdbStubCtxPktBufSearchStart(pThis, cbData, &cbProcessed);
2217 break;
2218 }
2219 case GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY:
2220 {
2221 rc = dbgcGdbStubCtxPktBufSearchEnd(pThis, cbData, &cbProcessed);
2222 break;
2223 }
2224 case GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM:
2225 {
2226 rc = dbgcGdbStubCtxPktBufProcessChksum(pThis, cbData, &cbProcessed);
2227 break;
2228 }
2229 default:
2230 /* Should never happen. */
2231 rc = VERR_INTERNAL_ERROR;
2232 }
2233
2234 cbData -= cbProcessed;
2235 }
2236
2237 return rc;
2238}
2239
2240
2241/**
2242 * Receive data and processes complete packets.
2243 *
2244 * @returns Status code.
2245 * @param pThis The GDB stub context.
2246 */
2247static int dbgcGdbStubCtxRecv(PGDBSTUBCTX pThis)
2248{
2249 /*
2250 * Read in 32 bytes chunks for now (need some peek API to get the amount of bytes actually available
2251 * to make it a bit more optimized).
2252 */
2253 int rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, 32);
2254 if (RT_SUCCESS(rc))
2255 {
2256 size_t cbThisRead = 32;
2257 rc = pThis->Dbgc.pBack->pfnRead(pThis->Dbgc.pBack, &pThis->pbPktBuf[pThis->offPktBuf], cbThisRead, &cbThisRead);
2258 if (RT_SUCCESS(rc))
2259 rc = dbgcGdbStubCtxPktBufProcess(pThis, cbThisRead);
2260 }
2261
2262 return rc;
2263}
2264
2265
2266/**
2267 * Processes debugger events.
2268 *
2269 * @returns VBox status code.
2270 * @param pThis The GDB stub context data.
2271 * @param pEvent Pointer to event data.
2272 */
2273static int dbgcGdbStubCtxProcessEvent(PGDBSTUBCTX pThis, PCDBGFEVENT pEvent)
2274{
2275 /*
2276 * Process the event.
2277 */
2278 PDBGC pDbgc = &pThis->Dbgc;
2279 pThis->Dbgc.pszScratch = &pThis->Dbgc.achInput[0];
2280 pThis->Dbgc.iArg = 0;
2281 int rc = VINF_SUCCESS;
2282 switch (pEvent->enmType)
2283 {
2284 /*
2285 * The first part is events we have initiated with commands.
2286 */
2287 case DBGFEVENT_HALT_DONE:
2288 {
2289 rc = dbgcGdbStubCtxReplySendSigTrap(pThis);
2290 break;
2291 }
2292
2293
2294 /*
2295 * The second part is events which can occur at any time.
2296 */
2297 case DBGFEVENT_FATAL_ERROR:
2298 {
2299 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
2300 dbgcGetEventCtx(pEvent->enmCtx));
2301 if (RT_SUCCESS(rc))
2302 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2303 break;
2304 }
2305
2306 case DBGFEVENT_BREAKPOINT:
2307 case DBGFEVENT_BREAKPOINT_IO:
2308 case DBGFEVENT_BREAKPOINT_MMIO:
2309 case DBGFEVENT_BREAKPOINT_HYPER:
2310 {
2311 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
2312 switch (rc)
2313 {
2314 case VERR_DBGC_BP_NOT_FOUND:
2315 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
2316 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2317 break;
2318
2319 case VINF_DBGC_BP_NO_COMMAND:
2320 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
2321 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2322 break;
2323
2324 case VINF_BUFFER_OVERFLOW:
2325 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
2326 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
2327 break;
2328
2329 default:
2330 break;
2331 }
2332 if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pUVM))
2333 {
2334 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2335
2336 /* Set the resume flag to ignore the breakpoint when resuming execution. */
2337 if ( RT_SUCCESS(rc)
2338 && pEvent->enmType == DBGFEVENT_BREAKPOINT)
2339 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r eflags.rf = 1");
2340 }
2341
2342 rc = dbgcGdbStubCtxReplySendSigTrap(pThis);
2343 break;
2344 }
2345
2346 case DBGFEVENT_STEPPED:
2347 case DBGFEVENT_STEPPED_HYPER:
2348 {
2349 rc = dbgcGdbStubCtxReplySendSigTrap(pThis);
2350 break;
2351 }
2352
2353 case DBGFEVENT_ASSERTION_HYPER:
2354 {
2355 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2356 "\ndbgf event: Hypervisor Assertion! (%s)\n"
2357 "%s"
2358 "%s"
2359 "\n",
2360 dbgcGetEventCtx(pEvent->enmCtx),
2361 pEvent->u.Assert.pszMsg1,
2362 pEvent->u.Assert.pszMsg2);
2363 if (RT_SUCCESS(rc))
2364 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2365 break;
2366 }
2367
2368 case DBGFEVENT_DEV_STOP:
2369 {
2370 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2371 "\n"
2372 "dbgf event: DBGFSTOP (%s)\n"
2373 "File: %s\n"
2374 "Line: %d\n"
2375 "Function: %s\n",
2376 dbgcGetEventCtx(pEvent->enmCtx),
2377 pEvent->u.Src.pszFile,
2378 pEvent->u.Src.uLine,
2379 pEvent->u.Src.pszFunction);
2380 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
2381 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
2382 "Message: %s\n",
2383 pEvent->u.Src.pszMessage);
2384 if (RT_SUCCESS(rc))
2385 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
2386 break;
2387 }
2388
2389
2390 case DBGFEVENT_INVALID_COMMAND:
2391 {
2392 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
2393 break;
2394 }
2395
2396 case DBGFEVENT_POWERING_OFF:
2397 {
2398 pThis->Dbgc.fReady = false;
2399 pThis->Dbgc.pBack->pfnSetReady(pThis->Dbgc.pBack, false);
2400 rc = VERR_GENERAL_FAILURE;
2401 break;
2402 }
2403
2404 default:
2405 {
2406 /*
2407 * Probably a generic event. Look it up to find its name.
2408 */
2409 PCDBGCSXEVT pEvtDesc = dbgcEventLookup(pEvent->enmType);
2410 if (pEvtDesc)
2411 {
2412 if (pEvtDesc->enmKind == kDbgcSxEventKind_Interrupt)
2413 {
2414 Assert(pEvtDesc->pszDesc);
2415 Assert(pEvent->u.Generic.cArgs == 1);
2416 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s no %#llx! (%s)\n",
2417 pEvtDesc->pszDesc, pEvent->u.Generic.auArgs[0], pEvtDesc->pszName);
2418 }
2419 else if (pEvtDesc->fFlags & DBGCSXEVT_F_BUGCHECK)
2420 {
2421 Assert(pEvent->u.Generic.cArgs >= 5);
2422 char szDetails[512];
2423 DBGFR3FormatBugCheck(pDbgc->pUVM, szDetails, sizeof(szDetails), pEvent->u.Generic.auArgs[0],
2424 pEvent->u.Generic.auArgs[1], pEvent->u.Generic.auArgs[2],
2425 pEvent->u.Generic.auArgs[3], pEvent->u.Generic.auArgs[4]);
2426 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s %s%s!\n%s", pEvtDesc->pszName,
2427 pEvtDesc->pszDesc ? "- " : "", pEvtDesc->pszDesc ? pEvtDesc->pszDesc : "",
2428 szDetails);
2429 }
2430 else if ( (pEvtDesc->fFlags & DBGCSXEVT_F_TAKE_ARG)
2431 || pEvent->u.Generic.cArgs > 1
2432 || ( pEvent->u.Generic.cArgs == 1
2433 && pEvent->u.Generic.auArgs[0] != 0))
2434 {
2435 if (pEvtDesc->pszDesc)
2436 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!",
2437 pEvtDesc->pszName, pEvtDesc->pszDesc);
2438 else
2439 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!", pEvtDesc->pszName);
2440 if (pEvent->u.Generic.cArgs <= 1)
2441 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " arg=%#llx\n", pEvent->u.Generic.auArgs[0]);
2442 else
2443 {
2444 for (uint32_t i = 0; i < pEvent->u.Generic.cArgs; i++)
2445 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " args[%u]=%#llx", i, pEvent->u.Generic.auArgs[i]);
2446 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");
2447 }
2448 }
2449 else
2450 {
2451 if (pEvtDesc->pszDesc)
2452 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!\n",
2453 pEvtDesc->pszName, pEvtDesc->pszDesc);
2454 else
2455 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!\n", pEvtDesc->pszName);
2456 }
2457 }
2458 else
2459 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
2460 break;
2461 }
2462 }
2463
2464 return rc;
2465}
2466
2467
2468/**
2469 * Run the debugger console.
2470 *
2471 * @returns VBox status code.
2472 * @param pThis Pointer to the GDB stub context.
2473 */
2474int dbgcGdbStubRun(PGDBSTUBCTX pThis)
2475{
2476 /*
2477 * We're ready for commands now.
2478 */
2479 pThis->Dbgc.fReady = true;
2480 pThis->Dbgc.pBack->pfnSetReady(pThis->Dbgc.pBack, true);
2481
2482 /*
2483 * Main Debugger Loop.
2484 *
2485 * This loop will either block on waiting for input or on waiting on
2486 * debug events. If we're forwarding the log we cannot wait for long
2487 * before we must flush the log.
2488 */
2489 int rc;
2490 for (;;)
2491 {
2492 rc = VERR_SEM_OUT_OF_TURN;
2493 if (pThis->Dbgc.pUVM)
2494 rc = DBGFR3QueryWaitable(pThis->Dbgc.pUVM);
2495
2496 if (RT_SUCCESS(rc))
2497 {
2498 /*
2499 * Wait for a debug event.
2500 */
2501 PCDBGFEVENT pEvent;
2502 rc = DBGFR3EventWait(pThis->Dbgc.pUVM, 32, &pEvent);
2503 if (RT_SUCCESS(rc))
2504 {
2505 rc = dbgcGdbStubCtxProcessEvent(pThis, pEvent);
2506 if (RT_FAILURE(rc))
2507 break;
2508 }
2509 else if (rc != VERR_TIMEOUT)
2510 break;
2511
2512 /*
2513 * Check for input.
2514 */
2515 if (pThis->Dbgc.pBack->pfnInput(pThis->Dbgc.pBack, 0))
2516 {
2517 rc = dbgcGdbStubCtxRecv(pThis);
2518 if (RT_FAILURE(rc))
2519 break;
2520 }
2521 }
2522 else if (rc == VERR_SEM_OUT_OF_TURN)
2523 {
2524 /*
2525 * Wait for input.
2526 */
2527 if (pThis->Dbgc.pBack->pfnInput(pThis->Dbgc.pBack, 1000))
2528 {
2529 rc = dbgcGdbStubCtxRecv(pThis);
2530 if (RT_FAILURE(rc))
2531 break;
2532 }
2533 }
2534 else
2535 break;
2536 }
2537
2538 return rc;
2539}
2540
2541
2542/**
2543 * @copydoc DBGC::pfnOutput
2544 */
2545static DECLCALLBACK(int) dbgcOutputGdb(void *pvUser, const char *pachChars, size_t cbChars)
2546{
2547 PGDBSTUBCTX pThis = (PGDBSTUBCTX)pvUser;
2548
2549 pThis->fOutput = true;
2550 int rc = dbgcGdbStubCtxReplySendBegin(pThis);
2551 if (RT_SUCCESS(rc))
2552 {
2553 uint8_t chConOut = 'O';
2554 rc = dbgcGdbStubCtxReplySendData(pThis, &chConOut, sizeof(chConOut));
2555 if (RT_SUCCESS(rc))
2556 {
2557 /* Convert the characters to hex. */
2558 const char *pachCur = pachChars;
2559
2560 while ( cbChars
2561 && RT_SUCCESS(rc))
2562 {
2563 uint8_t achHex[512 + 1];
2564 size_t cbThisSend = RT_MIN((sizeof(achHex) - 1) / 2, cbChars); /* Each character needs two bytes. */
2565
2566 rc = dbgcGdbStubCtxEncodeBinaryAsHex(&achHex[0], cbThisSend * 2 + 1, pachCur, cbThisSend);
2567 if (RT_SUCCESS(rc))
2568 rc = dbgcGdbStubCtxReplySendData(pThis, &achHex[0], cbThisSend * 2);
2569
2570 pachCur += cbThisSend;
2571 cbChars -= cbThisSend;
2572 }
2573 }
2574
2575 dbgcGdbStubCtxReplySendEnd(pThis);
2576 }
2577
2578 return rc;
2579}
2580
2581
2582/**
2583 * Creates a GDB stub context instance with the given backend.
2584 *
2585 * @returns VBox status code.
2586 * @param ppGdbStubCtx Where to store the pointer to the GDB stub context instance on success.
2587 * @param pBack The backend to use for I/O.
2588 * @param fFlags Flags controlling the behavior.
2589 */
2590static int dbgcGdbStubCtxCreate(PPGDBSTUBCTX ppGdbStubCtx, PDBGCBACK pBack, unsigned fFlags)
2591{
2592 /*
2593 * Validate input.
2594 */
2595 AssertPtrReturn(pBack, VERR_INVALID_POINTER);
2596 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
2597
2598 /*
2599 * Allocate and initialize.
2600 */
2601 PGDBSTUBCTX pThis = (PGDBSTUBCTX)RTMemAllocZ(sizeof(*pThis));
2602 if (!pThis)
2603 return VERR_NO_MEMORY;
2604
2605 dbgcInitCmdHlp(&pThis->Dbgc);
2606 /*
2607 * This is compied from the native debug console (will be used for monitor commands)
2608 * in DBGCConsole.cpp. Try to keep both functions in sync.
2609 */
2610 pThis->Dbgc.pBack = pBack;
2611 pThis->Dbgc.pfnOutput = dbgcOutputGdb;
2612 pThis->Dbgc.pvOutputUser = pThis;
2613 pThis->Dbgc.pVM = NULL;
2614 pThis->Dbgc.pUVM = NULL;
2615 pThis->Dbgc.idCpu = 0;
2616 pThis->Dbgc.hDbgAs = DBGF_AS_GLOBAL;
2617 pThis->Dbgc.pszEmulation = "CodeView/WinDbg";
2618 pThis->Dbgc.paEmulationCmds = &g_aCmdsCodeView[0];
2619 pThis->Dbgc.cEmulationCmds = g_cCmdsCodeView;
2620 pThis->Dbgc.paEmulationFuncs = &g_aFuncsCodeView[0];
2621 pThis->Dbgc.cEmulationFuncs = g_cFuncsCodeView;
2622 //pThis->Dbgc.fLog = false;
2623 pThis->Dbgc.fRegTerse = true;
2624 pThis->Dbgc.fStepTraceRegs = true;
2625 //pThis->Dbgc.cPagingHierarchyDumps = 0;
2626 //pThis->Dbgc.DisasmPos = {0};
2627 //pThis->Dbgc.SourcePos = {0};
2628 //pThis->Dbgc.DumpPos = {0};
2629 pThis->Dbgc.pLastPos = &pThis->Dbgc.DisasmPos;
2630 //pThis->Dbgc.cbDumpElement = 0;
2631 //pThis->Dbgc.cVars = 0;
2632 //pThis->Dbgc.paVars = NULL;
2633 //pThis->Dbgc.pPlugInHead = NULL;
2634 //pThis->Dbgc.pFirstBp = NULL;
2635 //pThis->Dbgc.abSearch = {0};
2636 //pThis->Dbgc.cbSearch = 0;
2637 pThis->Dbgc.cbSearchUnit = 1;
2638 pThis->Dbgc.cMaxSearchHits = 1;
2639 //pThis->Dbgc.SearchAddr = {0};
2640 //pThis->Dbgc.cbSearchRange = 0;
2641
2642 //pThis->Dbgc.uInputZero = 0;
2643 //pThis->Dbgc.iRead = 0;
2644 //pThis->Dbgc.iWrite = 0;
2645 //pThis->Dbgc.cInputLines = 0;
2646 //pThis->Dbgc.fInputOverflow = false;
2647 pThis->Dbgc.fReady = true;
2648 pThis->Dbgc.pszScratch = &pThis->Dbgc.achScratch[0];
2649 //pThis->Dbgc.iArg = 0;
2650 //pThis->Dbgc.rcOutput = 0;
2651 //pThis->Dbgc.rcCmd = 0;
2652
2653 //pThis->Dbgc.pszHistoryFile = NULL;
2654 //pThis->Dbgc.pszGlobalInitScript = NULL;
2655 //pThis->Dbgc.pszLocalInitScript = NULL;
2656
2657 dbgcEvalInit();
2658
2659 /* Init the GDB stub specific parts. */
2660 pThis->cbPktBufMax = 0;
2661 pThis->pbPktBuf = NULL;
2662 pThis->fFeatures = GDBSTUBCTX_FEATURES_F_TGT_DESC;
2663 pThis->pachTgtXmlDesc = NULL;
2664 pThis->cbTgtXmlDesc = 0;
2665 pThis->fExtendedMode = false;
2666 pThis->fOutput = false;
2667 pThis->fInThrdInfoQuery = false;
2668 RTListInit(&pThis->LstTps);
2669 dbgcGdbStubCtxReset(pThis);
2670
2671 *ppGdbStubCtx = pThis;
2672 return VINF_SUCCESS;
2673}
2674
2675
2676/**
2677 * Destroys the given GDB stub context.
2678 *
2679 * @returns nothing.
2680 * @param pThis The GDB stub context to destroy.
2681 */
2682static void dbgcGdbStubDestroy(PGDBSTUBCTX pThis)
2683{
2684 AssertPtr(pThis);
2685
2686 /* Detach from the VM. */
2687 if (pThis->Dbgc.pUVM)
2688 DBGFR3Detach(pThis->Dbgc.pUVM);
2689
2690 /* Free config strings. */
2691 RTStrFree(pThis->Dbgc.pszGlobalInitScript);
2692 pThis->Dbgc.pszGlobalInitScript = NULL;
2693 RTStrFree(pThis->Dbgc.pszLocalInitScript);
2694 pThis->Dbgc.pszLocalInitScript = NULL;
2695 RTStrFree(pThis->Dbgc.pszHistoryFile);
2696 pThis->Dbgc.pszHistoryFile = NULL;
2697
2698 /* Finally, free the instance memory. */
2699 RTMemFree(pThis);
2700}
2701
2702
2703DECLHIDDEN(int) dbgcGdbStubCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags)
2704{
2705 /*
2706 * Validate input.
2707 */
2708 AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE);
2709 PVM pVM = NULL;
2710 if (pUVM)
2711 {
2712 pVM = VMR3GetVM(pUVM);
2713 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
2714 }
2715
2716 /*
2717 * Allocate and initialize instance data
2718 */
2719 PGDBSTUBCTX pThis;
2720 int rc = dbgcGdbStubCtxCreate(&pThis, pBack, fFlags);
2721 if (RT_FAILURE(rc))
2722 return rc;
2723 if (!HMR3IsEnabled(pUVM) && !NEMR3IsEnabled(pUVM))
2724 pThis->Dbgc.hDbgAs = DBGF_AS_RC_AND_GC_GLOBAL;
2725
2726 /*
2727 * Attach to the specified VM.
2728 */
2729 if (RT_SUCCESS(rc) && pUVM)
2730 {
2731 rc = DBGFR3Attach(pUVM);
2732 if (RT_SUCCESS(rc))
2733 {
2734 pThis->Dbgc.pVM = pVM;
2735 pThis->Dbgc.pUVM = pUVM;
2736 pThis->Dbgc.idCpu = 0;
2737 }
2738 else
2739 rc = pThis->Dbgc.CmdHlp.pfnVBoxError(&pThis->Dbgc.CmdHlp, rc, "When trying to attach to VM %p\n", pThis->Dbgc.pVM);
2740 }
2741
2742 /*
2743 * Load plugins.
2744 */
2745 if (RT_SUCCESS(rc))
2746 {
2747 if (pVM)
2748 DBGFR3PlugInLoadAll(pThis->Dbgc.pUVM);
2749 dbgcEventInit(&pThis->Dbgc);
2750 //dbgcRunInitScripts(pDbgc); Not yet
2751
2752 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM))
2753 rc = DBGFR3Halt(pThis->Dbgc.pUVM);
2754
2755 /*
2756 * Run the debugger main loop.
2757 */
2758 rc = dbgcGdbStubRun(pThis);
2759 dbgcEventTerm(&pThis->Dbgc);
2760 }
2761
2762 /*
2763 * Cleanup console debugger session.
2764 */
2765 dbgcGdbStubDestroy(pThis);
2766 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
2767}
2768
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