VirtualBox

Changeset 84980 in vbox


Ignore:
Timestamp:
Jun 29, 2020 8:44:28 AM (5 years ago)
Author:
vboxsync
Message:

Debugger/DBGPlugInLinux: New heuristic to find the kernel log buffer even if we couldn't get at the symbols, used as a last resort if everything fails.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGPlugInLinux.cpp

    r82968 r84980  
    182182/** The max kernel size. */
    183183#define LNX_MAX_KERNEL_SIZE                 UINT32_C(0x0f000000)
     184/** Maximum kernel log buffer size. */
     185#define LNX_MAX_KERNEL_LOG_SIZE             (16 * _1M)
    184186
    185187/** The maximum size we expect for kallsyms_names. */
     
    223225
    224226static const uint8_t g_abLinuxVersion[] = "Linux version ";
     227/** The needle for searching for the kernel log area (the value is observed in pretty much all 32bit and 64bit x86 kernels).
     228 * This needle should appear only once in the memory due to the address being filled in by a format string. */
     229static const uint8_t g_abKrnlLogNeedle[] = "BIOS-e820: [mem 0x0000000000000000";
     230
     231
     232/**
     233 * Tries to resolve the kernel log buffer start and end by searching for needle.
     234 *
     235 * @returns VBox status code.
     236 * @param   pThis               The Linux digger data.
     237 * @param   pUVM                The VM handle.
     238 * @param   pGCPtrLogBuf        Where to store the start of the kernel log buffer on success.
     239 * @param   pcbLogBuf           Where to store the size of the kernel log buffer on success.
     240 */
     241static int dbgDiggerLinuxKrnlLogBufFindByNeedle(PDBGDIGGERLINUX pThis, PUVM pUVM, RTGCPTR *pGCPtrLogBuf, uint32_t *pcbLogBuf)
     242{
     243    int rc = VINF_SUCCESS;
     244
     245    /* Try to find the needle, it should be very early in the kernel log buffer. */
     246    DBGFADDRESS AddrScan;
     247    DBGFADDRESS AddrHit;
     248    DBGFR3AddrFromFlat(pUVM, &AddrScan, pThis->f64Bit ? LNX64_KERNEL_ADDRESS_START : LNX32_KERNEL_ADDRESS_START);
     249
     250    rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &AddrScan, ~(RTGCUINTPTR)0, 1 /*uAlign*/,
     251                       g_abKrnlLogNeedle, sizeof(g_abKrnlLogNeedle) - 1, &AddrHit);
     252    if (RT_SUCCESS(rc))
     253    {
     254        size_t cbLogBuf = 0;
     255        uint64_t tsLastNs = 0;
     256        DBGFADDRESS AddrCur;
     257
     258        DBGFR3AddrSub(&AddrHit, sizeof(LNXPRINTKHDR));
     259        AddrCur = AddrHit;
     260
     261        /* Try to find the end of the kernel log buffer. */
     262        for (;;)
     263        {
     264            if (cbLogBuf >= LNX_MAX_KERNEL_LOG_SIZE)
     265                break;
     266
     267            LNXPRINTKHDR Hdr;
     268            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrCur, &Hdr, sizeof(Hdr));
     269            if (RT_SUCCESS(rc))
     270            {
     271                uint32_t const cbLogAlign = 4;
     272
     273                /*
     274                 * If the header does not look valid anymore we stop.
     275                 * Timestamps are monotonically increasing.
     276                 */
     277                if (   !Hdr.cbTotal /* Zero entry size means there is no record anymore, doesn't make sense to look futher. */
     278                    || Hdr.cbText + Hdr.cbDict + sizeof(Hdr) > Hdr.cbTotal
     279                    || (Hdr.cbTotal & (cbLogAlign - 1)) != 0
     280                    || tsLastNs > Hdr.nsTimestamp)
     281                    break;
     282
     283                /** @todo Maybe read text part and verify it is all ASCII. */
     284
     285                cbLogBuf += Hdr.cbTotal;
     286                DBGFR3AddrAdd(&AddrCur, Hdr.cbTotal);
     287            }
     288
     289            if (RT_FAILURE(rc))
     290                break;
     291        }
     292
     293        /** @todo Go back to find the start address of the kernel log (or we loose potential kernel log messages). */
     294
     295        if (RT_SUCCESS(rc))
     296        {
     297            /* Align log buffer size to a power of two. */
     298            if (cbLogBuf && !RT_IS_POWER_OF_TWO(cbLogBuf))
     299            {
     300                uint32_t i = 0;
     301
     302                while (cbLogBuf)
     303                {
     304                    cbLogBuf >>= 1;
     305                    i++;
     306                }
     307
     308                cbLogBuf = 1 << i;
     309            }
     310
     311            *pGCPtrLogBuf = AddrHit.FlatPtr;
     312            *pcbLogBuf    = RT_MIN(cbLogBuf, LNX_MAX_KERNEL_LOG_SIZE);
     313        }
     314    }
     315
     316    return rc;
     317}
     318
    225319
    226320/**
     
    758852}
    759853
     854
     855/**
     856 * Worker to process a given record based kernel log.
     857 *
     858 * @returns VBox status code.
     859 * @param   pThis       The Linux digger data.
     860 * @param   pUVM        The VM user mode handle.
     861 * @param   GCPtrLogBuf Flat guest address of the start of the log buffer.
     862 * @param   cbLogBuf    Power of two aligned size of the log buffer.
     863 * @param   idxFirst    Index in the log bfufer of the first message.
     864 * @param   idxNext     Index where to write hte next message in the log buffer.
     865 * @param   fFlags      Flags reserved for future use, MBZ.
     866 * @param   cMessages   The number of messages to retrieve, counting from the
     867 *                      end of the log (i.e. like tail), use UINT32_MAX for all.
     868 * @param   pszBuf      The output buffer.
     869 * @param   cbBuf       The buffer size.
     870 * @param   pcbActual   Where to store the number of bytes actually returned,
     871 *                      including zero terminator.  On VERR_BUFFER_OVERFLOW this
     872 *                      holds the necessary buffer size.  Optional.
     873 */
     874static int dbgDiggerLinuxKrnLogBufferProcess(PDBGDIGGERLINUX pThis, PUVM pUVM, RTGCPTR GCPtrLogBuf,
     875                                             uint32_t cbLogBuf, uint32_t idxFirst, uint32_t idxNext,
     876                                             uint32_t fFlags, uint32_t cMessages, char *pszBuf, size_t cbBuf,
     877                                             size_t *pcbActual)
     878{
     879    RT_NOREF(fFlags);
     880
     881    /*
     882     * Check if the values make sense.
     883     */
     884    if (pThis->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
     885    {
     886        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
     887        return VERR_NOT_FOUND;
     888    }
     889    if (   cbLogBuf < _4K
     890        || !RT_IS_POWER_OF_TWO(cbLogBuf)
     891        || cbLogBuf > LNX_MAX_KERNEL_LOG_SIZE)
     892    {
     893        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
     894        return VERR_NOT_FOUND;
     895    }
     896    uint32_t const cbLogAlign = 4;
     897    if (   idxFirst > cbLogBuf - sizeof(LNXPRINTKHDR)
     898        || (idxFirst & (cbLogAlign - 1)) != 0)
     899    {
     900        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_first_idx' value %#x is not valid.\n", idxFirst));
     901        return VERR_NOT_FOUND;
     902    }
     903    if (   idxNext > cbLogBuf - sizeof(LNXPRINTKHDR)
     904        || (idxNext & (cbLogAlign - 1)) != 0)
     905    {
     906        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_next_idx' value %#x is not valid.\n", idxNext));
     907        return VERR_NOT_FOUND;
     908    }
     909
     910    /*
     911     * Read the whole log buffer.
     912     */
     913    uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
     914    if (!pbLogBuf)
     915    {
     916        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
     917        return VERR_NO_MEMORY;
     918    }
     919    DBGFADDRESS Addr;
     920    int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
     921    if (RT_FAILURE(rc))
     922    {
     923        LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
     924                cbLogBuf, Addr.FlatPtr, rc));
     925        RTMemFree(pbLogBuf);
     926        return VERR_NOT_FOUND;
     927    }
     928
     929    /*
     930     * Count the messages in the buffer while doing some basic validation.
     931     */
     932    uint32_t const cbUsed = idxFirst == idxNext ? cbLogBuf /* could be empty... */
     933                          : idxFirst < idxNext  ? idxNext - idxFirst : cbLogBuf - idxFirst + idxNext;
     934    uint32_t cbLeft    = cbUsed;
     935    uint32_t offCur    = idxFirst;
     936    uint32_t cLogMsgs  = 0;
     937
     938    while (cbLeft > 0)
     939    {
     940        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     941        if (!pHdr->cbTotal)
     942        {
     943            /* Wrap around packet, most likely... */
     944            if (cbLogBuf - offCur >= cbLeft)
     945                break;
     946            offCur = 0;
     947            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     948        }
     949        if (RT_UNLIKELY(   pHdr->cbTotal > cbLogBuf - sizeof(*pHdr) - offCur
     950                        || pHdr->cbTotal > cbLeft
     951                        || (pHdr->cbTotal & (cbLogAlign - 1)) != 0
     952                        || pHdr->cbTotal < (uint32_t)pHdr->cbText + (uint32_t)pHdr->cbDict + sizeof(*pHdr) ))
     953        {
     954            LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Invalid printk_log record at %#x: cbTotal=%#x cbText=%#x cbDict=%#x cbLogBuf=%#x cbLeft=%#x\n",
     955                    offCur, pHdr->cbTotal, pHdr->cbText, pHdr->cbDict, cbLogBuf, cbLeft));
     956            break;
     957        }
     958
     959        if (pHdr->cbText > 0)
     960            cLogMsgs++;
     961
     962        /* next */
     963        offCur += pHdr->cbTotal;
     964        cbLeft -= pHdr->cbTotal;
     965    }
     966    if (!cLogMsgs)
     967    {
     968        RTMemFree(pbLogBuf);
     969        return VERR_NOT_FOUND;
     970    }
     971
     972    /*
     973     * Copy the messages into the output buffer.
     974     */
     975    offCur = idxFirst;
     976    cbLeft = cbUsed - cbLeft;
     977
     978    /* Skip messages that the caller doesn't want. */
     979    if (cMessages < cLogMsgs)
     980    {
     981        uint32_t cToSkip = cLogMsgs - cMessages;
     982        cLogMsgs - cToSkip;
     983
     984        while (cToSkip > 0)
     985        {
     986            PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     987            if (!pHdr->cbTotal)
     988            {
     989                offCur = 0;
     990                pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     991            }
     992            if (pHdr->cbText > 0)
     993                cToSkip--;
     994
     995            /* next */
     996            offCur += pHdr->cbTotal;
     997            cbLeft -= pHdr->cbTotal;
     998        }
     999    }
     1000
     1001    /* Now copy the messages. */
     1002    size_t offDst = 0;
     1003    while (cbLeft > 0)
     1004    {
     1005        PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     1006        if (   !pHdr->cbTotal
     1007            || !cLogMsgs)
     1008        {
     1009            if (cbLogBuf - offCur >= cbLeft)
     1010                break;
     1011            offCur = 0;
     1012            pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
     1013        }
     1014
     1015        if (pHdr->cbText > 0)
     1016        {
     1017            char  *pchText = (char *)(pHdr + 1);
     1018            size_t cchText = RTStrNLen(pchText, pHdr->cbText);
     1019            if (offDst + cchText < cbBuf)
     1020            {
     1021                memcpy(&pszBuf[offDst], pHdr + 1, cchText);
     1022                pszBuf[offDst + cchText] = '\n';
     1023            }
     1024            else if (offDst < cbBuf)
     1025                memcpy(&pszBuf[offDst], pHdr + 1, cbBuf - offDst);
     1026            offDst += cchText + 1;
     1027        }
     1028
     1029        /* next */
     1030        offCur += pHdr->cbTotal;
     1031        cbLeft -= pHdr->cbTotal;
     1032    }
     1033
     1034    /* Done with the buffer. */
     1035    RTMemFree(pbLogBuf);
     1036
     1037    /* Make sure we've reserved a char for the terminator. */
     1038    if (!offDst)
     1039        offDst = 1;
     1040
     1041    /* Set return size value. */
     1042    if (pcbActual)
     1043        *pcbActual = offDst;
     1044
     1045    if (offDst <= cbBuf)
     1046        return VINF_SUCCESS;
     1047    return VERR_BUFFER_OVERFLOW;
     1048}
     1049
     1050
    7601051/**
    7611052 * Worker to get at the kernel log for post 3.4 kernels where the log buffer contains records.
     
    7781069                                               char *pszBuf, size_t cbBuf, size_t *pcbActual)
    7791070{
    780     RT_NOREF1(fFlags);
    7811071    int rc = VINF_SUCCESS;
    7821072    RTGCPTR  GCPtrLogBuf;
     
    8261116        rc = dbgDiggerLinuxQueryLogBufferPtrs(pThis, pUVM, hMod, &GCPtrLogBuf, &cbLogBuf);
    8271117        if (RT_FAILURE(rc))
     1118        {
     1119            /*
     1120             * Last resort, scan for a known value which should appear only once in the kernel log buffer
     1121             * and try to deduce the boundaries from there.
     1122             */
     1123            rc = dbgDiggerLinuxKrnlLogBufFindByNeedle(pThis, pUVM, &GCPtrLogBuf, &cbLogBuf);
    8281124            return rc;
    829     }
    830 
    831     /*
    832      * Check if the values make sense.
    833      */
    834     if (pThis->f64Bit ? !LNX64_VALID_ADDRESS(GCPtrLogBuf) : !LNX32_VALID_ADDRESS(GCPtrLogBuf))
    835     {
    836         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf' value %RGv is not valid.\n", GCPtrLogBuf));
    837         return VERR_NOT_FOUND;
    838     }
    839     if (   cbLogBuf < 4096
    840         || !RT_IS_POWER_OF_TWO(cbLogBuf)
    841         || cbLogBuf > 16*_1M)
    842     {
    843         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_buf_len' value %#x is not valid.\n", cbLogBuf));
    844         return VERR_NOT_FOUND;
    845     }
    846     uint32_t const cbLogAlign = 4;
    847     if (   idxFirst > cbLogBuf - sizeof(LNXPRINTKHDR)
    848         || (idxFirst & (cbLogAlign - 1)) != 0)
    849     {
    850         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_first_idx' value %#x is not valid.\n", idxFirst));
    851         return VERR_NOT_FOUND;
    852     }
    853     if (   idxNext > cbLogBuf - sizeof(LNXPRINTKHDR)
    854         || (idxNext & (cbLogAlign - 1)) != 0)
    855     {
    856         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: 'log_next_idx' value %#x is not valid.\n", idxNext));
    857         return VERR_NOT_FOUND;
    858     }
    859 
    860     /*
    861      * Read the whole log buffer.
    862      */
    863     uint8_t *pbLogBuf = (uint8_t *)RTMemAlloc(cbLogBuf);
    864     if (!pbLogBuf)
    865     {
    866         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Failed to allocate %#x bytes for log buffer\n", cbLogBuf));
    867         return VERR_NO_MEMORY;
    868     }
    869     DBGFADDRESS Addr;
    870     rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrLogBuf), pbLogBuf, cbLogBuf);
    871     if (RT_FAILURE(rc))
    872     {
    873         LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error reading %#x bytes of log buffer at %RGv: %Rrc\n",
    874                 cbLogBuf, Addr.FlatPtr, rc));
    875         RTMemFree(pbLogBuf);
    876         return VERR_NOT_FOUND;
    877     }
    878 
    879     /*
    880      * Count the messages in the buffer while doing some basic validation.
    881      */
    882     uint32_t const cbUsed = idxFirst == idxNext ? cbLogBuf /* could be empty... */
    883                           : idxFirst < idxNext  ? idxNext - idxFirst : cbLogBuf - idxFirst + idxNext;
    884     uint32_t cbLeft    = cbUsed;
    885     uint32_t offCur    = idxFirst;
    886     uint32_t cLogMsgs  = 0;
    887 
    888     while (cbLeft > 0)
    889     {
    890         PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    891         if (!pHdr->cbTotal)
    892         {
    893             /* Wrap around packet, most likely... */
    894             if (cbLogBuf - offCur >= cbLeft)
    895                 break;
    896             offCur = 0;
    897             pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    898         }
    899         if (RT_UNLIKELY(   pHdr->cbTotal > cbLogBuf - sizeof(*pHdr) - offCur
    900                         || pHdr->cbTotal > cbLeft
    901                         || (pHdr->cbTotal & (cbLogAlign - 1)) != 0
    902                         || pHdr->cbTotal < (uint32_t)pHdr->cbText + (uint32_t)pHdr->cbDict + sizeof(*pHdr) ))
    903         {
    904             LogRel(("dbgDiggerLinuxIDmsg_QueryKernelLog: Invalid printk_log record at %#x: cbTotal=%#x cbText=%#x cbDict=%#x cbLogBuf=%#x cbLeft=%#x\n",
    905                     offCur, pHdr->cbTotal, pHdr->cbText, pHdr->cbDict, cbLogBuf, cbLeft));
    906             rc = VERR_INVALID_STATE;
    907             break;
    908         }
    909 
    910         if (pHdr->cbText > 0)
    911             cLogMsgs++;
    912 
    913         /* next */
    914         offCur += pHdr->cbTotal;
    915         cbLeft -= pHdr->cbTotal;
    916     }
    917     if (RT_FAILURE(rc))
    918     {
    919         RTMemFree(pbLogBuf);
    920         return rc;
    921     }
    922 
    923     /*
    924      * Copy the messages into the output buffer.
    925      */
    926     offCur = idxFirst;
    927     cbLeft = cbUsed;
    928 
    929     /* Skip messages that the caller doesn't want. */
    930     if (cMessages < cLogMsgs)
    931     {
    932         uint32_t cToSkip = cLogMsgs - cMessages;
    933         while (cToSkip > 0)
    934         {
    935             PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    936             if (!pHdr->cbTotal)
    937             {
    938                 offCur = 0;
    939                 pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    940             }
    941             if (pHdr->cbText > 0)
    942                 cToSkip--;
    943 
    944             /* next */
    945             offCur += pHdr->cbTotal;
    946             cbLeft -= pHdr->cbTotal;
    947         }
    948     }
    949 
    950     /* Now copy the messages. */
    951     size_t offDst = 0;
    952     while (cbLeft > 0)
    953     {
    954         PCLNXPRINTKHDR pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    955         if (!pHdr->cbTotal)
    956         {
    957             if (cbLogBuf - offCur >= cbLeft)
    958                 break;
    959             offCur = 0;
    960             pHdr = (PCLNXPRINTKHDR)&pbLogBuf[offCur];
    961         }
    962 
    963         if (pHdr->cbText > 0)
    964         {
    965             char  *pchText = (char *)(pHdr + 1);
    966             size_t cchText = RTStrNLen(pchText, pHdr->cbText);
    967             if (offDst + cchText < cbBuf)
    968             {
    969                 memcpy(&pszBuf[offDst], pHdr + 1, cchText);
    970                 pszBuf[offDst + cchText] = '\n';
    971             }
    972             else if (offDst < cbBuf)
    973                 memcpy(&pszBuf[offDst], pHdr + 1, cbBuf - offDst);
    974             offDst += cchText + 1;
    975         }
    976 
    977         /* next */
    978         offCur += pHdr->cbTotal;
    979         cbLeft -= pHdr->cbTotal;
    980     }
    981 
    982     /* Done with the buffer. */
    983     RTMemFree(pbLogBuf);
    984 
    985     /* Make sure we've reserved a char for the terminator. */
    986     if (!offDst)
    987         offDst = 1;
    988 
    989     /* Set return size value. */
    990     if (pcbActual)
    991         *pcbActual = offDst;
    992 
    993     if (offDst <= cbBuf)
    994         return VINF_SUCCESS;
    995     return VERR_BUFFER_OVERFLOW;
     1125        }
     1126    }
     1127
     1128    return dbgDiggerLinuxKrnLogBufferProcess(pThis, pUVM, GCPtrLogBuf, cbLogBuf, idxFirst, idxNext,
     1129                                             fFlags, cMessages, pszBuf, cbBuf, pcbActual);
    9961130}
    9971131
     
    10141148    int rc = RTDbgAsModuleByName(hAs, "vmlinux", 0, &hMod);
    10151149    RTDbgAsRelease(hAs);
    1016     if (RT_FAILURE(rc))
    1017         return VERR_NOT_FOUND;
    1018 
    1019     /*
    1020      * Check whether the kernel log buffer is a simple char buffer or the newer
    1021      * record based implementation.
    1022      * The record based implementation was presumably introduced with kernel 3.4,
    1023      * see: http://thread.gmane.org/gmane.linux.kernel/1284184
    1024      */
    1025     size_t cbActual;
    1026     if (dbgDiggerLinuxLogBufferIsAsciiBuffer(pData, pUVM))
    1027         rc = dbgDiggerLinuxLogBufferQueryAscii(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     1150
     1151    size_t cbActual = 0;
     1152    if (RT_SUCCESS(rc))
     1153    {
     1154        /*
     1155         * Check whether the kernel log buffer is a simple char buffer or the newer
     1156         * record based implementation.
     1157         * The record based implementation was presumably introduced with kernel 3.4,
     1158         * see: http://thread.gmane.org/gmane.linux.kernel/1284184
     1159         */
     1160        if (dbgDiggerLinuxLogBufferIsAsciiBuffer(pData, pUVM))
     1161            rc = dbgDiggerLinuxLogBufferQueryAscii(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     1162        else
     1163            rc = dbgDiggerLinuxLogBufferQueryRecords(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     1164
     1165        /* Release the module in any case. */
     1166        RTDbgModRelease(hMod);
     1167    }
    10281168    else
    1029         rc = dbgDiggerLinuxLogBufferQueryRecords(pData, pUVM, hMod, fFlags, cMessages, pszBuf, cbBuf, &cbActual);
    1030 
    1031     /* Release the module in any case. */
    1032     RTDbgModRelease(hMod);
     1169    {
     1170        /*
     1171         * For the record based kernel versions we have a last resort heuristic which doesn't
     1172         * require any symbols, try that here.
     1173         */
     1174        if (!dbgDiggerLinuxLogBufferIsAsciiBuffer(pData, pUVM))
     1175        {
     1176            RTGCPTR GCPtrLogBuf = 0;
     1177            uint32_t cbLogBuf = 0;
     1178
     1179            rc = dbgDiggerLinuxKrnlLogBufFindByNeedle(pData, pUVM, &GCPtrLogBuf, &cbLogBuf);
     1180            if (RT_SUCCESS(rc))
     1181                rc = dbgDiggerLinuxKrnLogBufferProcess(pData, pUVM, GCPtrLogBuf, cbLogBuf, 0 /*idxFirst*/, 0 /*idxNext*/,
     1182                                                       fFlags, cMessages, pszBuf, cbBuf, &cbActual);
     1183        }
     1184        else
     1185            rc = VERR_NOT_FOUND;
     1186    }
    10331187
    10341188    if (RT_FAILURE(rc) && rc != VERR_BUFFER_OVERFLOW)
Note: See TracChangeset for help on using the changeset viewer.

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