VirtualBox

Changeset 61369 in vbox


Ignore:
Timestamp:
Jun 1, 2016 12:50:48 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107677
Message:

Debugger/DBGPlugInLinux: Add support to get at the guest kernel log if the required symbols are not exposed in kallsyms by disassembling some public helpers to get at the log buffer address and size

File:
1 edited

Legend:

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

    r61040 r61369  
    2424#include "DBGPlugInCommonELF.h"
    2525#include <VBox/vmm/dbgf.h>
     26#include <VBox/dis.h>
    2627#include <iprt/string.h>
    2728#include <iprt/mem.h>
     
    163164
    164165/**
     166 * Disassembles a simple getter returning the value for it.
     167 *
     168 * @returns VBox status code.
     169 * @param   pThis               The Linux digger data.
     170 * @param   pUVM                The VM handle.
     171 * @param   hMod                The module to use.
     172 * @param   pszSymbol           The symbol of the getter.
     173 * @param   pvVal               Where to store the value on success.
     174 * @param   cbVal               Size of the value in bytes.
     175 */
     176static int dbgDiggerLinuxDisassembleSimpleGetter(PDBGDIGGERLINUX pThis, PUVM pUVM, RTDBGMOD hMod,
     177                                                 const char *pszSymbol, void *pvVal, uint32_t cbVal)
     178{
     179    int rc = VINF_SUCCESS;
     180
     181    RTDBGSYMBOL SymInfo;
     182    rc = RTDbgModSymbolByName(hMod, pszSymbol, &SymInfo);
     183    if (RT_SUCCESS(rc))
     184    {
     185        /*
     186         * Do the diassembling. Disassemble until a ret instruction is encountered
     187         * or a limit is reached (don't want to disassemble for too long as the getter
     188         * should be short).
     189         * push and pop instructions are skipped as well as any mov instructions not
     190         * touching the rax or eax register (depending on the size of the value).
     191         */
     192        unsigned cInstrDisassembled = 0;
     193        uint32_t offInstr = 0;
     194        bool fRet = false;
     195        DISSTATE DisState;
     196        RT_ZERO(DisState);
     197
     198        do
     199        {
     200            DBGFADDRESS Addr;
     201            RTGCPTR GCPtrCur = (RTGCPTR)SymInfo.Value + pThis->AddrKernelBase.FlatPtr + offInstr;
     202            DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrCur);
     203
     204            /* Prefetch the instruction. */
     205            uint8_t abInstr[32];
     206            rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &abInstr[0], sizeof(abInstr));
     207            if (RT_SUCCESS(rc))
     208            {
     209                uint32_t cbInstr = 0;
     210
     211                rc = DISInstr(&abInstr[0], pThis->f64Bit ? DISCPUMODE_64BIT : DISCPUMODE_32BIT, &DisState, &cbInstr);
     212                if (RT_SUCCESS(rc))
     213                {
     214                    switch (DisState.pCurInstr->uOpcode)
     215                    {
     216                        case OP_PUSH:
     217                        case OP_POP:
     218                        case OP_NOP:
     219                        case OP_LEA:
     220                            break;
     221                        case OP_RETN:
     222                            /* Getter returned, abort disassembling. */
     223                            fRet = true;
     224                            break;
     225                        case OP_MOV:
     226                            /*
     227                             * Check that the destination is either rax or eax depending on the
     228                             * value size.
     229                             *
     230                             * Param1 is the destination and Param2 the source.
     231                             */
     232                            if (   (   (   (DisState.Param1.fUse & (DISUSE_BASE | DISUSE_REG_GEN32))
     233                                        && cbVal == sizeof(uint32_t))
     234                                    || (    (DisState.Param1.fUse & (DISUSE_BASE | DISUSE_REG_GEN64))
     235                                         && cbVal == sizeof(uint64_t)))
     236                                && DisState.Param1.Base.idxGenReg == DISGREG_RAX)
     237                            {
     238                                /* Parse the source. */
     239                                if (DisState.Param2.fUse & (DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64))
     240                                    memcpy(pvVal, &DisState.Param2.uValue, cbVal);
     241                                else if (DisState.Param2.fUse & (DISUSE_RIPDISPLACEMENT32|DISUSE_DISPLACEMENT32|DISUSE_DISPLACEMENT64))
     242                                {
     243                                    RTGCPTR GCPtrVal = 0;
     244
     245                                    if (DisState.Param2.fUse & DISUSE_RIPDISPLACEMENT32)
     246                                        GCPtrVal = GCPtrCur + DisState.Param2.uDisp.i32 + cbInstr;
     247                                    else if (DisState.Param2.fUse & DISUSE_DISPLACEMENT32)
     248                                        GCPtrVal = (RTGCPTR)DisState.Param2.uDisp.u32;
     249                                    else if (DisState.Param2.fUse & DISUSE_DISPLACEMENT64)
     250                                        GCPtrVal = (RTGCPTR)DisState.Param2.uDisp.u64;
     251                                    else
     252                                        AssertMsgFailedBreakStmt(("Invalid displacement\n"), rc = VERR_INVALID_STATE);
     253
     254                                    DBGFADDRESS AddrVal;
     255                                    rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
     256                                                       DBGFR3AddrFromFlat(pUVM, &AddrVal, GCPtrVal),
     257                                                       pvVal, cbVal);
     258                                }
     259                            }
     260                            break;
     261                        default:
     262                            /* All other instructions will cause an error for now (playing safe here). */
     263                            rc = VERR_INVALID_PARAMETER;
     264                            break;
     265                    }
     266                    cInstrDisassembled++;
     267                    offInstr += cbInstr;
     268                }
     269            }
     270        } while (   RT_SUCCESS(rc)
     271                 && cInstrDisassembled < 20
     272                 && !fRet);
     273    }
     274
     275    return rc;
     276}
     277
     278/**
     279 * Try to get at the log buffer starting address and size by disassembling some exposed helpers.
     280 *
     281 * @returns VBox status code.
     282 * @param   pThis               The Linux digger data.
     283 * @param   pUVM                The VM handle.
     284 * @param   hMod                The module to use.
     285 * @param   pGCPtrLogBuf        Where to store the log buffer pointer on success.
     286 * @param   pcbLogBuf           Where to store the size of the log buffer on success.
     287 */
     288static int dbgDiggerLinuxQueryLogBufferPtrs(PDBGDIGGERLINUX pThis, PUVM pUVM, RTDBGMOD hMod,
     289                                            RTGCPTR *pGCPtrLogBuf, uint32_t *pcbLogBuf)
     290{
     291    int rc = VINF_SUCCESS;
     292
     293    struct { void *pvVar; size_t cbHost, cbGuest; const char *pszSymbol; } aSymbols[] =
     294    {
     295        { pGCPtrLogBuf, sizeof(RTGCPTR),  pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t), "log_buf_addr_get" },
     296        { pcbLogBuf,    sizeof(uint32_t), sizeof(uint32_t),                                    "log_buf_len_get" }
     297    };
     298    for (uint32_t i = 0; i < RT_ELEMENTS(aSymbols) && RT_SUCCESS(rc); i++)
     299    {
     300        RT_BZERO(aSymbols[i].pvVar, aSymbols[i].cbHost);
     301        Assert(aSymbols[i].cbHost >= aSymbols[i].cbGuest);
     302        rc = dbgDiggerLinuxDisassembleSimpleGetter(pThis, pUVM, hMod, aSymbols[i].pszSymbol,
     303                                                   aSymbols[i].pvVar,  aSymbols[i].cbGuest);
     304    }
     305
     306    return rc;
     307}
     308
     309/**
    165310 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
    166311 */
     
    213358        else
    214359            Log(("dbgDiggerLinuxIDmsg_QueryKernelLog: Error looking up '%s': %Rrc\n", aSymbols[i].pszSymbol, rc));
     360        rc = VERR_NOT_FOUND;
     361        break;
     362    }
     363
     364    /*
     365     * Some kernels don't expose the variables in kallsyms so we have to try disassemble
     366     * some public helpers to get at the addresses.
     367     *
     368     * @todo: Maybe cache those values so we don't have to do the heavy work every time?
     369     */
     370    if (rc == VERR_NOT_FOUND)
     371    {
     372        idxFirst = 0;
     373        idxNext = 0;
     374        rc = dbgDiggerLinuxQueryLogBufferPtrs(pData, pUVM, hMod, &GCPtrLogBuf, &cbLogBuf);
     375
     376        /* Release the module in any case. */
    215377        RTDbgModRelease(hMod);
    216         return VERR_NOT_FOUND;
     378
     379        if (RT_FAILURE(rc))
     380            return rc;
    217381    }
    218382
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