VirtualBox

vbox的更動 54218 路徑 trunk/src/VBox/Debugger


忽略:
時間撮記:
2015-2-16 下午03:17:05 (10 年 以前)
作者:
vboxsync
訊息:

DBGF,DBGC: Added dmesg command and implemented it for linux guests.

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

圖例:

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

    r51957 r54218  
    5252static FNDBGCCMD dbgcCmdStop;
    5353static FNDBGCCMD dbgcCmdDetect;
     54static FNDBGCCMD dbgcCmdDmesg;
    5455static FNDBGCCMD dbgcCmdCpu;
    5556static FNDBGCCMD dbgcCmdInfo;
     
    109110
    110111
     112/** 'dmesg' arguments. */
     113static const DBGCVARDESC    g_aArgDmesg[] =
     114{
     115    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
     116    {  0,           1,     DBGCVAR_CAT_NUMBER_NO_RANGE, 0,                              "messages",     "Limit the output to the last N messages. (optional)" },
     117};
     118
     119
    111120/** 'help' arguments. */
    112121static const DBGCVARDESC    g_aArgHelp[] =
     
    232241    { "format",     1,        1,        &g_aArgAny[0],       RT_ELEMENTS(g_aArgAny),       0, dbgcCmdFormat,    "",                     "Evaluates an expression and formats it." },
    233242    { "detect",     0,        0,        NULL,                0,                            0, dbgcCmdDetect,    "",                     "Detects or re-detects the guest os and starts the OS specific digger." },
     243    { "dmesg",      0,        1,        &g_aArgDmesg[0],     RT_ELEMENTS(g_aArgDmesg),     0, dbgcCmdDmesg,     "[N last messages]",    "Displays the guest os kernel messages, if available." },
    234244    { "harakiri",   0,        0,        NULL,                0,                            0, dbgcCmdHarakiri,  "",                     "Kills debugger process." },
    235245    { "help",       0,        ~0U,      &g_aArgHelp[0],      RT_ELEMENTS(g_aArgHelp),      0, dbgcCmdHelp,      "[cmd/op [..]]",        "Display help. For help about info items try 'info help'." },
     
    9981008        rc = DBGCCmdHlpPrintf(pCmdHlp, "Unable to figure out which guest OS it is, sorry.\n");
    9991009    NOREF(pCmd); NOREF(paArgs);
     1010    return rc;
     1011}
     1012
     1013
     1014/**
     1015 * @interface_method_impl{FNDBCCMD, The 'dmesg' command.}
     1016 */
     1017static DECLCALLBACK(int) dbgcCmdDmesg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
     1018{
     1019    /* check that the parser did what it's supposed to do. */
     1020    if (cArgs > 1)
     1021        return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
     1022    uint32_t cMessages = UINT32_MAX;
     1023    if (cArgs == 1)
     1024    {
     1025        if (paArgs[0].enmType != DBGCVAR_TYPE_NUMBER)
     1026            return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
     1027        cMessages = paArgs[0].u.u64Number <= UINT32_MAX ? (uint32_t)paArgs[0].u.u64Number : UINT32_MAX;
     1028    }
     1029
     1030    /*
     1031     * Query the interface.
     1032     */
     1033    int rc;
     1034    PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(pUVM, DBGFOSINTERFACE_DMESG);
     1035    if (pDmesg)
     1036    {
     1037        size_t  cbActual;
     1038        size_t  cbBuf  = _512K;
     1039        char   *pszBuf = (char *)RTMemAlloc(cbBuf);
     1040        if (pszBuf)
     1041        {
     1042            rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
     1043
     1044            uint32_t cTries = 10;
     1045            while (rc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
     1046            {
     1047                RTMemFree(pszBuf);
     1048                cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
     1049                pszBuf = (char *)RTMemAlloc(cbBuf);
     1050                if (RT_UNLIKELY(!pszBuf))
     1051                {
     1052                    rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
     1053                    break;
     1054                }
     1055                rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
     1056            }
     1057            if (RT_SUCCESS(rc))
     1058                rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\n", pszBuf);
     1059            else if (rc == VERR_BUFFER_OVERFLOW && pszBuf)
     1060                rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\nWarning: incomplete\n", pszBuf);
     1061            else
     1062                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
     1063        }
     1064        else
     1065            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
     1066    }
     1067    else
     1068        rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "The dmesg interface isn't implemented by guest OS.\n");
    10001069    return rc;
    10011070}
  • trunk/src/VBox/Debugger/DBGPlugInLinux.cpp

    r54213 r54218  
    8181    DBGFADDRESS AddrKernelTokenIndex;
    8282
     83    /** The kernel message log interface. */
     84    DBGFOSIDMESG    IDmesg;
    8385} DBGDIGGERLINUX;
    8486/** Pointer to the linux guest OS digger instance data. */
    8587typedef DBGDIGGERLINUX *PDBGDIGGERLINUX;
     88
     89
     90/**
     91 * The current printk_log structure.
     92 */
     93typedef struct LNXPRINTKHDR
     94{
     95    /** Monotonic timestamp. */
     96    uint64_t nsTimestamp;
     97    /** The total size of this message record. */
     98    uint16_t cbTotal;
     99    /** The size of the text part (immediately follows the header). */
     100    uint16_t cbText;
     101    /** The size of the optional dictionary part (follows the text). */
     102    uint16_t cbDict;
     103    /** The syslog facility number. */
     104    uint8_t  bFacility;
     105    /** First 5 bits are internal flags, next 3 bits are log level. */
     106    uint8_t  fFlagsAndLevel;
     107} LNXPRINTKHDR;
     108AssertCompileSize(LNXPRINTKHDR, 2*sizeof(uint64_t));
     109/** Pointer to linux printk_log header. */
     110typedef LNXPRINTKHDR *PLNXPRINTKHDR;
     111/** Pointer to linux const printk_log header. */
     112typedef LNXPRINTKHDR const *PCLNXPRINTKHDR;
    86113
    87114
     
    113140#define LNX_MAX_KALLSYMS_TOKEN_LEN          UINT16_C(32)
    114141
    115 
    116142/** Module tag for linux ('linuxmod' on little endian ASCII systems). */
    117143#define DIG_LNX_MOD_TAG                     UINT64_C(0x545f5d78758e898c)
     
    137163
    138164/**
     165 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
     166 */
     167static DECLCALLBACK(int) dbgDiggerLinuxIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
     168                                                            char *pszBuf, size_t cbBuf, size_t *pcbActual)
     169{
     170    PDBGDIGGERLINUX pData = RT_FROM_MEMBER(pThis, DBGDIGGERLINUX, IDmesg);
     171
     172    if (cMessages < 1)
     173        return VERR_INVALID_PARAMETER;
     174
     175    /*
     176     * Resolve the symbols we need and read their values.
     177     */
     178    RTDBGAS  hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
     179    RTDBGMOD hMod;
     180    int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
     181    if (RT_FAILURE(rc))
     182        return VERR_NOT_FOUND;
     183    RTDbgAsRelease(hAs);
     184
     185    RTGCPTR  GCPtrLogBuf;
     186    uint32_t cbLogBuf;
     187    uint32_t idxFirst;
     188    uint32_t idxNext;
     189
     190    struct { void *pvVar; uint32_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
     191    {
     192        { &GCPtrLogBuf, sizeof(GCPtrLogBuf),    pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t),   "log_buf" },
     193        { &cbLogBuf,    sizeof(cbLogBuf),       sizeof(cbLogBuf),                                      "log_buf_len" },
     194        { &idxFirst,    sizeof(idxFirst),       sizeof(idxFirst),                                      "log_first_idx" },
     195        { &idxNext,     sizeof(idxNext),        sizeof(idxNext),                                       "log_next_idx" },
     196    };
     197    for (uint32_t i = 0; i < RT_ELEMENTS(aSymbols); i++)
     198    {
     199        RTDBGSYMBOL SymInfo;
     200        rc = RTDbgModSymbolByName(hMod, aSymbols[i].pszSymbol, &SymInfo);
     201        if (RT_SUCCESS(rc))
     202        {
     203            RT_BZERO(aSymbols[i].pvVar, aSymbols[i].cbHost);
     204            Assert(aSymbols[i].cbHost >= aSymbols[i].cbGuest);
     205            DBGFADDRESS Addr;
     206            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
     207                               DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pData->AddrKernelBase.FlatPtr),
     208                               aSymbols[i].pvVar,  aSymbols[i].cbGuest);
     209            if (RT_SUCCESS(rc))
     210                continue;
     211            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Reading '%s' at %RGv: %Rrc\n", aSymbols[i].pszSymbol, Addr.FlatPtr, rc));
     212        }
     213        else
     214            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error looking up '%s': %Rrc\n", aSymbols[i].pszSymbol, rc));
     215        RTDbgModRelease(hMod);
     216        return VERR_NOT_FOUND;
     217    }
     218
     219    /*
     220     * Check if the values make sense.
     221     */
     222    if (pData->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
     223    {
     224        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
     225        return VERR_NOT_FOUND;
     226    }
     227    if (   cbLogBuf < 4096
     228        || !RT_IS_POWER_OF_TWO(cbLogBuf)
     229        || cbLogBuf > 16*_1M)
     230    {
     231        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
     232        return VERR_NOT_FOUND;
     233    }
     234    uint32_t const cbLogAlign = 4;
     235    if (   idxFirst > cbLogBuf - sizeof(LNXPRINTKHDR)
     236        || (idxFirst & (cbLogAlign - 1)) != 0)
     237    {
     238        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_first_idx' value %#x is not valid.\n", idxFirst));
     239        return VERR_NOT_FOUND;
     240    }
     241    if (   idxNext > cbLogBuf - sizeof(LNXPRINTKHDR)
     242        || (idxNext & (cbLogAlign - 1)) != 0)
     243    {
     244        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_next_idx' value %#x is not valid.\n", idxNext));
     245        return VERR_NOT_FOUND;
     246    }
     247
     248    /*
     249     * Read the whole log buffer.
     250     */
     251    uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
     252    if (!pbLogBuf)
     253    {
     254        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
     255        return VERR_NO_MEMORY;
     256    }
     257    DBGFADDRESS Addr;
     258    rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
     259    if (RT_FAILURE(rc))
     260    {
     261        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
     262             cbLogBuf, Addr.FlatPtr, rc));
     263        RTMemFree(pbLogBuf);
     264        return VERR_NOT_FOUND;
     265    }
     266
     267    /*
     268     * Count the messages in the buffer while doing some basic validation.
     269     */
     270    uint32_t const cbUsed = idxFirst == idxNext ? cbLogBuf /* could be empty... */
     271                          : idxFirst < idxNext  ? idxNext - idxFirst : cbLogBuf - idxFirst + idxNext;
     272    uint32_t cbLeft    = cbUsed;
     273    uint32_t offCur    = idxFirst;
     274    uint32_t cLogMsgs  = 0;
     275
     276    while (cbLeft > 0)
     277    {
     278        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     279        if (!pHdr->cbTotal)
     280        {
     281            /* Wrap around packet, most likely... */
     282            if (cbLogBuf - offCur >= cbLeft)
     283                break;
     284            offCur = 0;
     285            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     286        }
     287        if (RT_UNLIKELY(   pHdr->cbTotal > cbLogBuf - sizeof(*pHdr) - offCur
     288                        || pHdr->cbTotal > cbLeft
     289                        || (pHdr->cbTotal & (cbLogAlign - 1)) != 0
     290                        || pHdr->cbTotal < (uint32_t)pHdr->cbText + (uint32_t)pHdr->cbDict + sizeof(*pHdr) ))
     291        {
     292            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Invalid printk_log record at %#x: cbTotal=%#x cbText=%#x cbDict=%#x cbLogBuf=%#x cbLeft=%#x\n",
     293                 offCur, pHdr->cbTotal, pHdr->cbText, pHdr->cbDict, cbLogBuf, cbLeft));
     294            rc = VERR_INVALID_STATE;
     295            break;
     296        }
     297
     298        if (pHdr->cbText > 0)
     299            cLogMsgs++;
     300
     301        /* next */
     302        offCur += pHdr->cbTotal;
     303        cbLeft -= pHdr->cbTotal;
     304    }
     305    if (RT_FAILURE(rc))
     306    {
     307        RTMemFree(pbLogBuf);
     308        return rc;
     309    }
     310
     311    /*
     312     * Copy the messages into the output buffer.
     313     */
     314    offCur = idxFirst;
     315    cbLeft = cbUsed;
     316
     317    /* Skip messages that the caller doesn't want. */
     318    if (cMessages < cLogMsgs)
     319    {
     320        uint32_t cToSkip = cLogMsgs - cMessages;
     321        while (cToSkip > 0)
     322        {
     323            PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     324            if (!pHdr->cbTotal)
     325            {
     326                offCur = 0;
     327                pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     328            }
     329            if (pHdr->cbText > 0)
     330                cToSkip--;
     331
     332            /* next */
     333            offCur += pHdr->cbTotal;
     334            cbLeft -= pHdr->cbTotal;
     335        }
     336    }
     337
     338    /* Now copy the messages. */
     339    size_t offDst = 0;
     340    while (cbLeft > 0)
     341    {
     342        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     343        if (!pHdr->cbTotal)
     344        {
     345            if (cbLogBuf - offCur >= cbLeft)
     346                break;
     347            offCur = 0;
     348            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     349        }
     350
     351        if (pHdr->cbText > 0)
     352        {
     353            char  *pchText = (char *)(pHdr + 1);
     354            size_t cchText = RTStrNLen(pchText, pHdr->cbText);
     355            if (offDst + cchText < cbBuf)
     356            {
     357                memcpy(&pszBuf[offDst], pHdr + 1, cchText);
     358                pszBuf[offDst + cchText] = '\n';
     359            }
     360            else if (offDst < cbBuf)
     361                memcpy(&pszBuf[offDst], pHdr + 1, cbBuf - offDst);
     362            offDst += cchText + 1;
     363        }
     364
     365        /* next */
     366        offCur += pHdr->cbTotal;
     367        cbLeft -= pHdr->cbTotal;
     368    }
     369
     370    /* Done with the buffer. */
     371    RTMemFree(pbLogBuf);
     372
     373    /* Make sure we've reserved a char for the terminator. */
     374    if (!offDst)
     375        offDst = 1;
     376
     377    /* Set return size value. */
     378    if (pcbActual)
     379        *pcbActual = offDst;
     380
     381    /*
     382     * All VBox strings are UTF-8 and bad things may in theory happen if we
     383     * pass bad UTF-8 to code which assumes it's all valid.  So, we enforce
     384     * UTF-8 upon the guest kernel messages here even if they (probably) have
     385     * no defined code set in reality.
     386     */
     387    if (offDst <= cbBuf)
     388    {
     389        pszBuf[offDst - 1] = '\0';
     390        RTStrPurgeEncoding(pszBuf);
     391        return VINF_SUCCESS;
     392    }
     393
     394    if (cbBuf)
     395    {
     396        pszBuf[cbBuf - 1] = '\0';
     397        RTStrPurgeEncoding(pszBuf);
     398    }
     399    return VERR_BUFFER_OVERFLOW;
     400}
     401
     402
     403/**
    139404 * @copydoc DBGFOSREG::pfnQueryInterface
    140405 */
    141406static DECLCALLBACK(void *) dbgDiggerLinuxQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
    142407{
    143     return NULL;
     408    PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
     409    switch (enmIf)
     410    {
     411        case DBGFOSINTERFACE_DMESG:
     412            return &pThis->IDmesg;
     413
     414        default:
     415            return NULL;
     416    }
    144417}
    145418
     
    9481221static DECLCALLBACK(int)  dbgDiggerLinuxConstruct(PUVM pUVM, void *pvData)
    9491222{
     1223    PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
     1224    pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
     1225    pThis->IDmesg.pfnQueryKernelLog = dbgDiggerLinuxIDmsg_QueryKernelLog;
     1226    pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
     1227
    9501228    return VINF_SUCCESS;
    9511229}
  • trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp

    r48946 r54218  
    294294    return VERR_INTERNAL_ERROR;
    295295}
     296VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf)
     297{
     298    return NULL;
     299}
    296300
    297301VMMR3DECL(int) DBGFR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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