VirtualBox

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


忽略:
時間撮記:
2016-6-8 上午08:13:51 (8 年 以前)
作者:
vboxsync
訊息:

Debugger/Digger/Linux: Implement getting the kernel log for older kernels where the log buffer is a simple ASCII buffer

檔案:
修改 1 筆資料

圖例:

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

    r61369 r61558  
    162162};
    163163
     164static const uint8_t g_abLinuxVersion[] = "Linux version ";
    164165
    165166/**
     
    308309
    309310/**
    310  * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
    311  */
    312 static DECLCALLBACK(int) dbgDiggerLinuxIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
    313                                                             char *pszBuf, size_t cbBuf, size_t *pcbActual)
    314 {
    315     PDBGDIGGERLINUX pData = RT_FROM_MEMBER(pThis, DBGDIGGERLINUX, IDmesg);
    316 
    317     if (cMessages < 1)
    318         return VERR_INVALID_PARAMETER;
    319 
    320     /*
    321      * Resolve the symbols we need and read their values.
    322      */
    323     RTDBGAS  hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
    324     RTDBGMOD hMod;
    325     int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
     311 * Returns whether the log buffer is a simple ascii buffer or a record based implementation
     312 * based on the kernel version found.
     313 *
     314 * @returns Flag whether the log buffer is the simple ascii buffer.
     315 * @param   pThis               The Linux digger data.
     316 * @param   pUVM                The user mode VM handle.
     317 */
     318static bool dbgDiggerLinuxLogBufferIsAsciiBuffer(PDBGDIGGERLINUX pThis, PUVM pUVM)
     319{
     320    char szTmp[128];
     321    char const *pszVer = &szTmp[sizeof(g_abLinuxVersion) - 1];
     322
     323    RT_ZERO(szTmp);
     324    int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrLinuxBanner, szTmp, sizeof(szTmp) - 1);
     325    if (    RT_SUCCESS(rc)
     326        &&  RTStrVersionCompare(pszVer, "3.4") == -1)
     327        return true;
     328
     329    return false;
     330}
     331
     332/**
     333 * Worker to get at the kernel log for pre 3.4 kernels where the log buffer was just a char buffer.
     334 *
     335 * @returns VBox status code.
     336 * @param   pThis       The Linux digger data.
     337 * @param   pUVM        The VM user mdoe handle.
     338 * @param   hMod        The debug module handle.
     339 * @param   fFlags      Flags reserved for future use, MBZ.
     340 * @param   cMessages   The number of messages to retrieve, counting from the
     341 *                      end of the log (i.e. like tail), use UINT32_MAX for all.
     342 * @param   pszBuf      The output buffer.
     343 * @param   cbBuf       The buffer size.
     344 * @param   pcbActual   Where to store the number of bytes actually returned,
     345 *                      including zero terminator.  On VERR_BUFFER_OVERFLOW this
     346 *                      holds the necessary buffer size.  Optional.
     347 */
     348static int dbgDiggerLinuxLogBufferQueryAscii(PDBGDIGGERLINUX pThis, PUVM pUVM, RTDBGMOD hMod,
     349                                             uint32_t fFlags, uint32_t cMessages,
     350                                             char *pszBuf, size_t cbBuf, size_t *pcbActual)
     351{
     352    int rc = VINF_SUCCESS;
     353    RTGCPTR  GCPtrLogBuf;
     354    uint32_t cbLogBuf;
     355
     356    struct { void *pvVar; size_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
     357    {
     358        { &GCPtrLogBuf, sizeof(GCPtrLogBuf),    pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t),   "log_buf" },
     359        { &cbLogBuf,    sizeof(cbLogBuf),       sizeof(cbLogBuf),                                      "log_buf_len" },
     360    };
     361    for (uint32_t i = 0; i < RT_ELEMENTS(aSymbols); i++)
     362    {
     363        RTDBGSYMBOL SymInfo;
     364        rc = RTDbgModSymbolByName(hMod, aSymbols[i].pszSymbol, &SymInfo);
     365        if (RT_SUCCESS(rc))
     366        {
     367            RT_BZERO(aSymbols[i].pvVar, aSymbols[i].cbHost);
     368            Assert(aSymbols[i].cbHost >= aSymbols[i].cbGuest);
     369            DBGFADDRESS Addr;
     370            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
     371                               DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pThis->AddrKernelBase.FlatPtr),
     372                               aSymbols[i].pvVar,  aSymbols[i].cbGuest);
     373            if (RT_SUCCESS(rc))
     374                continue;
     375            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Reading '%s' at %RGv: %Rrc\n", aSymbols[i].pszSymbol, Addr.FlatPtr, rc));
     376        }
     377        else
     378            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error looking up '%s': %Rrc\n", aSymbols[i].pszSymbol, rc));
     379        rc = VERR_NOT_FOUND;
     380        break;
     381    }
     382
    326383    if (RT_FAILURE(rc))
     384        return rc;
     385
     386    /*
     387     * Check if the values make sense.
     388     */
     389    if (pThis->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
     390    {
     391        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
    327392        return VERR_NOT_FOUND;
    328     RTDbgAsRelease(hAs);
    329 
     393    }
     394    if (   cbLogBuf < 4096
     395        || !RT_IS_POWER_OF_TWO(cbLogBuf)
     396        || cbLogBuf > 16*_1M)
     397    {
     398        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
     399        return VERR_NOT_FOUND;
     400    }
     401
     402    /*
     403     * Read the whole log buffer.
     404     */
     405    uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
     406    if (!pbLogBuf)
     407    {
     408        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
     409        return VERR_NO_MEMORY;
     410    }
     411    DBGFADDRESS Addr;
     412    rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
     413    if (RT_FAILURE(rc))
     414    {
     415        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
     416             cbLogBuf, Addr.FlatPtr, rc));
     417        RTMemFree(pbLogBuf);
     418        return VERR_NOT_FOUND;
     419    }
     420
     421    /** @todo: Try to parse where the single messages start to make use of cMessages. */
     422    memcpy(&pszBuf[0], pbLogBuf, RT_MIN(cbBuf, cbLogBuf));
     423
     424    /* Done with the buffer. */
     425    RTMemFree(pbLogBuf);
     426
     427    /* Set return size value. */
     428    if (pcbActual)
     429        *pcbActual = RT_MIN(cbBuf, cbLogBuf);
     430
     431    return cbBuf <= cbLogBuf ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
     432}
     433
     434/**
     435 * Worker to get at the kernel log for post 3.4 kernels where the log buffer contains records.
     436 *
     437 * @returns VBox status code.
     438 * @param   pThis       The Linux digger data.
     439 * @param   pUVM        The VM user mdoe handle.
     440 * @param   hMod        The debug module handle.
     441 * @param   fFlags      Flags reserved for future use, MBZ.
     442 * @param   cMessages   The number of messages to retrieve, counting from the
     443 *                      end of the log (i.e. like tail), use UINT32_MAX for all.
     444 * @param   pszBuf      The output buffer.
     445 * @param   cbBuf       The buffer size.
     446 * @param   pcbActual   Where to store the number of bytes actually returned,
     447 *                      including zero terminator.  On VERR_BUFFER_OVERFLOW this
     448 *                      holds the necessary buffer size.  Optional.
     449 */
     450static int dbgDiggerLinuxLogBufferQueryRecords(PDBGDIGGERLINUX pThis, PUVM pUVM, RTDBGMOD hMod,
     451                                               uint32_t fFlags, uint32_t cMessages,
     452                                               char *pszBuf, size_t cbBuf, size_t *pcbActual)
     453{
     454    int rc = VINF_SUCCESS;
    330455    RTGCPTR  GCPtrLogBuf;
    331456    uint32_t cbLogBuf;
     
    335460    struct { void *pvVar; size_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
    336461    {
    337         { &GCPtrLogBuf, sizeof(GCPtrLogBuf),    pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t),   "log_buf" },
     462        { &GCPtrLogBuf, sizeof(GCPtrLogBuf),    pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t),   "log_buf" },
    338463        { &cbLogBuf,    sizeof(cbLogBuf),       sizeof(cbLogBuf),                                      "log_buf_len" },
    339464        { &idxFirst,    sizeof(idxFirst),       sizeof(idxFirst),                                      "log_first_idx" },
     
    350475            DBGFADDRESS Addr;
    351476            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
    352                                DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pData->AddrKernelBase.FlatPtr),
     477                               DBGFR3AddrFromFlat(pUVM, &Addr, (RTGCPTR)SymInfo.Value + pThis->AddrKernelBase.FlatPtr),
    353478                               aSymbols[i].pvVar,  aSymbols[i].cbGuest);
    354479            if (RT_SUCCESS(rc))
     
    372497        idxFirst = 0;
    373498        idxNext = 0;
    374         rc = dbgDiggerLinuxQueryLogBufferPtrs(pData, pUVM, hMod, &GCPtrLogBuf, &cbLogBuf);
    375 
    376         /* Release the module in any case. */
    377         RTDbgModRelease(hMod);
    378 
     499        rc = dbgDiggerLinuxQueryLogBufferPtrs(pThis, pUVM, hMod, &GCPtrLogBuf, &cbLogBuf);
    379500        if (RT_FAILURE(rc))
    380501            return rc;
     
    384505     * Check if the values make sense.
    385506     */
    386     if (pData->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
     507    if (pThis->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
    387508    {
    388509        Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
     
    543664        *pcbActual = offDst;
    544665
     666    if (offDst <= cbBuf)
     667        return VINF_SUCCESS;
     668    else
     669        return VERR_BUFFER_OVERFLOW;
     670}
     671
     672/**
     673 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
     674 */
     675static DECLCALLBACK(int) dbgDiggerLinuxIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
     676                                                            char *pszBuf, size_t cbBuf, size_t *pcbActual)
     677{
     678    PDBGDIGGERLINUX pData = RT_FROM_MEMBER(pThis, DBGDIGGERLINUX, IDmesg);
     679
     680    if (cMessages < 1)
     681        return VERR_INVALID_PARAMETER;
     682
     683    /*
     684     * Resolve the symbols we need and read their values.
     685     */
     686    RTDBGAS  hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
     687    RTDBGMOD hMod;
     688    int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
     689    if (RT_FAILURE(rc))
     690        return VERR_NOT_FOUND;
     691    RTDbgAsRelease(hAs);
     692
     693    size_t cbActual;
     694    /*
     695     * Check whether the kernel log buffer is a simple char buffer or the newer
     696     * record based implementation.
     697     * The record based implementation was presumably introduced with kernel 3.4,
     698     * see: http://thread.gmane.org/gmane.linux.kernel/1284184
     699     */
     700    if (dbgDiggerLinuxLogBufferIsAsciiBuffer(pData, pUVM))
     701        rc = dbgDiggerLinuxLogBufferQueryAscii(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     702    else
     703        rc = dbgDiggerLinuxLogBufferQueryRecords(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     704
     705    /* Release the module in any case. */
     706    RTDbgModRelease(hMod);
     707
     708    if (RT_FAILURE(rc) && rc != VERR_BUFFER_OVERFLOW)
     709        return rc;
     710
     711    if (pcbActual)
     712        *pcbActual = cbActual;
     713
    545714    /*
    546715     * All VBox strings are UTF-8 and bad things may in theory happen if we
     
    549718     * no defined code set in reality.
    550719     */
    551     if (offDst <= cbBuf)
    552     {
    553         pszBuf[offDst - 1] = '\0';
     720    if (   RT_SUCCESS(rc)
     721        && cbActual <= cbBuf)
     722    {
     723        pszBuf[cbActual - 1] = '\0';
    554724        RTStrPurgeEncoding(pszBuf);
    555725        return VINF_SUCCESS;
     
    13301500        DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64LnxKernelAddresses[i]);
    13311501        DBGFADDRESS HitAddr;
    1332         static const uint8_t s_abLinuxVersion[] = "Linux version ";
    13331502        int rc = DBGFR3MemScan(pUVM, 0, &KernelAddr, LNX_MAX_KERNEL_SIZE, 1,
    1334                                s_abLinuxVersion, sizeof(s_abLinuxVersion) - 1, &HitAddr);
     1503                               g_abLinuxVersion, sizeof(g_abLinuxVersion) - 1, &HitAddr);
    13351504        if (RT_SUCCESS(rc))
    13361505        {
    13371506            char szTmp[128];
    1338             char const *pszX = &szTmp[sizeof(s_abLinuxVersion) - 1];
     1507            char const *pszX = &szTmp[sizeof(g_abLinuxVersion) - 1];
    13391508            rc = DBGFR3MemReadString(pUVM, 0, &HitAddr, szTmp, sizeof(szTmp));
    13401509            if (    RT_SUCCESS(rc)
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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