VirtualBox

儲存庫 vbox 的更動 84627


忽略:
時間撮記:
2020-6-1 下午08:13:57 (5 年 以前)
作者:
vboxsync
svn:sync-xref-src-repo-rev:
138367
訊息:

Debugger: Initial port of my GDB stub library from https://github.com/AlexanderEichner/libgdbstub to VirtualBox, bugref:5217

Very basic port with quite a few rough edges, this is basically a backup of the current code.

Working:

  • Halt and Resume VM execution
  • Reading registers
  • Reading/Writing memory
  • Basic support for breakpoints (removing doesn't work yet)

Still todo:

  • Cleanup, cleanup, cleanup
  • Writing memory
  • SMP support (by abusing the thread support of GDB)
  • Access to the native debugger console through the Rcmd/monitor protocol
  • More register sets (MMX,SSE,AVX, etc.)

If you want to try it out enable the normal TCP debugger interface and set the following extradata key:

VBoxInternal/DBGC/GdbStub 1

No complaints about the code at this point please, hints and comments welcome though!

位置:
trunk/src/VBox/Debugger
檔案:
修改 4 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp

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

    r83088 r84627  
    588588
    589589
     590DECLHIDDEN(int) dbgcGdbStubCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags);
     591
     592
    590593/*******************************************************************************
    591594*   Global Variables                                                           *
  • trunk/src/VBox/Debugger/DBGCTcp.cpp

    r82968 r84627  
    3030
    3131#include <iprt/string.h>
     32
     33#include "DBGCInternal.h"
    3234
    3335
     
    168170}
    169171
     172/**
     173 * Write (output) - raw version not converting any newlines.
     174 *
     175 * @returns VBox status code.
     176 * @param   pBack       Pointer to the backend structure supplied by
     177 *                      the backend. The backend can use this to find
     178 *                      it's instance data.
     179 * @param   pvBuf       What to write.
     180 * @param   cbBuf       Number of bytes to write.
     181 * @param   pcbWritten  Where to store the number of bytes actually written.
     182 *                      If NULL the entire buffer must be successfully written.
     183 */
     184static DECLCALLBACK(int) dbgcTcpBackWriteRaw(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
     185{
     186    PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack);
     187    if (!pDbgcTcp->fAlive)
     188        return VERR_INVALID_HANDLE;
     189
     190    int rc = RTTcpWrite(pDbgcTcp->Sock, pvBuf, cbBuf);
     191    if (RT_FAILURE(rc))
     192        pDbgcTcp->fAlive = false;
     193
     194    if (pcbWritten)
     195        *pcbWritten = cbBuf;
     196
     197    return rc;
     198}
     199
    170200/** @copydoc FNDBGCBACKSETREADY */
    171201static DECLCALLBACK(void) dbgcTcpBackSetReady(PDBGCBACK pBack, bool fReady)
     
    191221    LogFlow(("dbgcTcpConnection: connection! Sock=%d pvUser=%p\n", Sock, pvUser));
    192222
     223    PUVM pUVM = (PUVM)pvUser;
     224    PCFGMNODE pKey = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "DBGC");
     225    bool fGdbStub = false;
     226    int rc = CFGMR3QueryBoolDef(pKey, "GdbStub", &fGdbStub, false);
     227    if (RT_FAILURE(rc))
     228        return VM_SET_ERROR_U(pUVM, rc, "Configuration error: Failed querying \"DBGC/GdbStub\"");
     229
    193230    /*
    194231     * Start the console.
    195232     */
    196233    DBGCTCP    DbgcTcp;
    197     DbgcTcp.Back.pfnInput    = dbgcTcpBackInput;
    198     DbgcTcp.Back.pfnRead     = dbgcTcpBackRead;
    199     DbgcTcp.Back.pfnWrite    = dbgcTcpBackWrite;
    200     DbgcTcp.Back.pfnSetReady = dbgcTcpBackSetReady;
     234    DbgcTcp.Back.pfnInput     = dbgcTcpBackInput;
     235    DbgcTcp.Back.pfnRead      = dbgcTcpBackRead;
     236    if (fGdbStub)
     237        DbgcTcp.Back.pfnWrite = dbgcTcpBackWriteRaw;
     238    else
     239        DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite;
     240    DbgcTcp.Back.pfnSetReady  = dbgcTcpBackSetReady;
    201241    DbgcTcp.fAlive = true;
    202242    DbgcTcp.Sock   = Sock;
    203     int rc = DBGCCreate((PUVM)pvUser, &DbgcTcp.Back, 0);
     243    if (fGdbStub)
     244        rc = dbgcGdbStubCreate(pUVM, &DbgcTcp.Back, 0);
     245    else
     246        rc = DBGCCreate(pUVM, &DbgcTcp.Back, 0);
    204247    LogFlow(("dbgcTcpConnection: disconnect rc=%Rrc\n", rc));
    205248    return rc;
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r83088 r84627  
    10341034                                  "HistoryFile|"
    10351035                                  "LocalInitScript|"
    1036                                   "GlobalInitScript",
     1036                                  "GlobalInitScript|"
     1037                                  "GdbStub",
    10371038                                  "", "DBGC", 0);
    10381039    AssertRCReturn(rc, rc);
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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