/** * Deregisters a guest OS digger previously registered by DBGFR3OSRegister. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param pReg The registration structure. * @thread Any. */ VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg) { /* * Validate input. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pReg, VERR_INVALID_POINTER); AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME); DBGF_OS_READ_LOCK(pUVM); PDBGFOS pOS; for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext) if (pOS->pReg == pReg) break; DBGF_OS_READ_UNLOCK(pUVM); if (!pOS) { Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName)); return VERR_NOT_FOUND; } /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pUVM, pReg); }
/** * Registers a guest OS digger. * * This will instantiate an instance of the digger and add it * to the list for us in the next call to DBGFR3OSDetect(). * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param pReg The registration structure. * @thread Any. */ VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg) { /* * Validate intput. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pReg, VERR_INVALID_POINTER); AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC); AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER); AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER); AssertReturn(pReg->szName[0], VERR_INVALID_NAME); AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME); AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER); AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER); AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER); /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pUVM, pReg); }
/** * Changes the logger group settings. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param pszGroupSettings The group settings string. (VBOX_LOG) * By prefixing the string with \"release:\" the * changes will be applied to the release log * instead of the debug log. The prefix \"debug:\" * is also recognized. */ VMMR3DECL(int) DBGFR3LogModifyGroups(PUVM pUVM, const char *pszGroupSettings) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pszGroupSettings, VERR_INVALID_POINTER); return VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3LogModifyGroups, 2, pUVM, pszGroupSettings); }
/** * Display a piece of info writing to the supplied handler. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param idCpu The CPU to exectue the request on. Pass NIL_VMCPUID * to not involve any EMT. * @param pszName The identifier of the info to display. * @param pszArgs Arguments to the info handler. * @param pHlp The output helper functions. If NULL the logger will be used. */ VMMR3DECL(int) DBGFR3InfoEx(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); if (idCpu == NIL_VMCPUID) return dbgfR3Info(pUVM, VMCPUID_ANY, pszName, pszArgs, pHlp); return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3Info, 5, pUVM, idCpu, pszName, pszArgs, pHlp); }
/** * Scan guest memory for an exact byte string. * * @returns VBox status codes: * @retval VINF_SUCCESS and *pGCPtrHit on success. * @retval VERR_DBGF_MEM_NOT_FOUND if not found. * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid. * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the CPU context to search in. * @param pAddress Where to store the mixed address. * @param cbRange The number of bytes to scan. * @param uAlign The alignment restriction imposed on the result. * Usually set to 1. * @param pvNeedle What to search for - exact search. * @param cbNeedle Size of the search byte string. * @param pHitAddress Where to put the address of the first hit. * * @thread Any thread. */ VMMR3DECL(int) DBGFR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign, const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemScan, 8, pUVM, idCpu, pAddress, &cbRange, &uAlign, pvNeedle, cbNeedle, pHitAddress); }
/** * Checks if the given CPU is executing 64-bit code or not. * * @returns true / false accordingly. * @param pUVM The user mode VM handle. * @param idCpu The target CPU ID. */ VMMR3DECL(bool) DBGFR3CpuIsIn64BitCode(PUVM pUVM, VMCPUID idCpu) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, false); VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, false); AssertReturn(idCpu < pUVM->pVM->cCpus, false); bool fIn64BitCode; int rc = VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3CpuIn64BitCode, 3, pUVM->pVM, idCpu, &fIn64BitCode); if (RT_FAILURE(rc)) return false; return fIn64BitCode; }
/** * Get the current CPU mode. * * @returns The CPU mode on success, CPUMMODE_INVALID on failure. * @param pUVM The user mode VM handle. * @param idCpu The target CPU ID. */ VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PUVM pUVM, VMCPUID idCpu) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, CPUMMODE_INVALID); VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, CPUMMODE_INVALID); AssertReturn(idCpu < pUVM->pVM->cCpus, CPUMMODE_INVALID); CPUMMODE enmMode; int rc = VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3CpuGetMode, 3, pUVM->pVM, idCpu, &enmMode); if (RT_FAILURE(rc)) return CPUMMODE_INVALID; return enmMode; }
/** * Detects the guest OS and try dig out symbols and useful stuff. * * When called the 2nd time, symbols will be updated that if the OS * is the same. * * @returns VBox status code. * @retval VINF_SUCCESS if successfully detected. * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out. * * @param pUVM The user mode VM handle. * @param pszName Where to store the OS name. Empty string if not detected. * @param cchName Size of the buffer. * @thread Any. */ VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName) { AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); if (pszName && cchName) *pszName = '\0'; UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pUVM, pszName, cchName); }
/** * Read guest memory. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the source CPU context (for the address). * @param pAddress Where to start reading. * @param pvBuf Where to store the data we've read. * @param cbRead The number of bytes to read. */ VMMR3DECL(int) DBGFR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); if ((pAddress->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0) { AssertCompile(sizeof(RTHCUINTPTR) <= sizeof(pAddress->FlatPtr)); VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE); return VMMR3ReadR0Stack(pUVM->pVM, idCpu, (RTHCUINTPTR)pAddress->FlatPtr, pvBuf, cbRead); } return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemRead, 5, pUVM, idCpu, pAddress, pvBuf, cbRead); }
/** * Common worker for DBGFR3StackWalkBeginGuestEx, DBGFR3StackWalkBeginHyperEx, * DBGFR3StackWalkBeginGuest and DBGFR3StackWalkBeginHyper. */ static int dbgfR3StackWalkBeginCommon(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, PCDBGFADDRESS pAddrStack, PCDBGFADDRESS pAddrPC, DBGFRETURNTYPE enmReturnType, PCDBGFSTACKFRAME *ppFirstFrame) { /* * Validate parameters. */ *ppFirstFrame = NULL; UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID); if (pAddrFrame) AssertReturn(DBGFR3AddrIsValid(pUVM, pAddrFrame), VERR_INVALID_PARAMETER); if (pAddrStack) AssertReturn(DBGFR3AddrIsValid(pUVM, pAddrStack), VERR_INVALID_PARAMETER); if (pAddrPC) AssertReturn(DBGFR3AddrIsValid(pUVM, pAddrPC), VERR_INVALID_PARAMETER); AssertReturn(enmReturnType >= DBGFRETURNTYPE_INVALID && enmReturnType < DBGFRETURNTYPE_END, VERR_INVALID_PARAMETER); /* * Get the CPUM context pointer and pass it on the specified EMT. */ RTDBGAS hAs; PCCPUMCTXCORE pCtxCore; switch (enmCodeType) { case DBGFCODETYPE_GUEST: pCtxCore = CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu)); hAs = DBGF_AS_GLOBAL; break; case DBGFCODETYPE_HYPER: pCtxCore = CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu)); hAs = DBGF_AS_RC_AND_GC_GLOBAL; break; case DBGFCODETYPE_RING0: pCtxCore = NULL; /* No valid context present. */ hAs = DBGF_AS_R0; break; default: AssertFailedReturn(VERR_INVALID_PARAMETER); } return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3StackWalkCtxFull, 10, pUVM, idCpu, pCtxCore, hAs, enmCodeType, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame); }
/** * Gets information about a selector. * * Intended for the debugger mostly and will prefer the guest * descriptor tables over the shadow ones. * * @returns VBox status code, the following are the common ones. * @retval VINF_SUCCESS on success. * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the * descriptor table. * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This * is not returned if the selector itself isn't present, you have to * check that for yourself (see DBGFSELINFO::fFlags). * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the * pagetable or page backing the selector table wasn't present. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the virtual CPU context. * @param Sel The selector to get info about. * @param fFlags Flags, see DBGFQSEL_FLAGS_*. * @param pSelInfo Where to store the information. This will always be * updated. * * @remarks This is a wrapper around SELMR3GetSelectorInfo and * SELMR3GetShadowSelectorInfo. */ VMMR3DECL(int) DBGFR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); AssertReturn(!(fFlags & ~(DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)), VERR_INVALID_PARAMETER); AssertReturn( (fFlags & (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)) != (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE), VERR_INVALID_PARAMETER); /* Clear the return data here on this thread. */ memset(pSelInfo, 0, sizeof(*pSelInfo)); /* * Dispatch the request to a worker running on the target CPU. */ return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3SelQueryInfo, 5, pUVM, idCpu, Sel, fFlags, pSelInfo); }
/** * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog, Generic EMT wrapper.} */ static DECLCALLBACK(int) dbgfR3OSEmtIDmesg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual) { PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.Dmesg); UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(!fFlags, VERR_INVALID_FLAGS); AssertReturn(cMessages > 0, VERR_INVALID_PARAMETER); if (cbBuf) AssertPtrReturn(pszBuf, VERR_INVALID_POINTER); AssertPtrNullReturn(pcbActual, VERR_INVALID_POINTER); return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/, (PFNRT)pWrapper->uDigger.pDmesg->pfnQueryKernelLog, 7, pWrapper->uDigger.pDmesg, pUVM, fFlags, cMessages, pszBuf, cbBuf, pcbActual); }
/** * Read a zero terminated string from guest memory. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the source CPU context (for the address). * @param pAddress Where to start reading. * @param pszBuf Where to store the string. * @param cchBuf The size of the buffer. */ VMMR3DECL(int) DBGFR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf) { /* * Validate and zero output. */ if (!VALID_PTR(pszBuf)) return VERR_INVALID_POINTER; if (cchBuf <= 0) return VERR_INVALID_PARAMETER; memset(pszBuf, 0, cchBuf); UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); /* * Pass it on to the EMT. */ return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemReadString, 5, pUVM, idCpu, pAddress, pszBuf, cchBuf); }
/** * Queries the name and/or version string for the guest OS. * * It goes without saying that this querying is done using the current * guest OS digger and not additions or user configuration. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param pszName Where to store the OS name. Optional. * @param cchName The size of the name buffer. * @param pszVersion Where to store the version string. Optional. * @param cchVersion The size of the version buffer. * @thread Any. */ VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrNullReturn(pszName, VERR_INVALID_POINTER); AssertPtrNullReturn(pszVersion, VERR_INVALID_POINTER); /* * Initialize the output up front. */ if (pszName && cchName) *pszName = '\0'; if (pszVersion && cchVersion) *pszVersion = '\0'; /* * Pass it on to EMT(0). */ return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSQueryNameAndVersion, 5, pUVM, pszName, cchName, pszVersion, cchVersion); }
/** * Dump paging structures. * * This API can be used to dump both guest and shadow structures. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param idCpu The current CPU ID. * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX. * @param cr3 The CR3 to use (unless we're getting the current * state, see @a fFlags). * @param u64FirstAddr The address to start dumping at. * @param u64LastAddr The address to end dumping after. * @param cMaxDepth The depth. * @param pHlp The output callbacks. Defaults to the debug log if * NULL. */ VMMDECL(int) DBGFR3PagingDumpEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, uint64_t cr3, uint64_t u64FirstAddr, uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp) { /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); AssertReturn(!(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER); AssertReturn(fFlags & (DBGFPGDMP_FLAGS_SHADOW | DBGFPGDMP_FLAGS_GUEST), VERR_INVALID_PARAMETER); AssertReturn((fFlags & DBGFPGDMP_FLAGS_CURRENT_MODE) || !(fFlags & DBGFPGDMP_FLAGS_MODE_MASK), VERR_INVALID_PARAMETER); AssertReturn( !(fFlags & DBGFPGDMP_FLAGS_EPT) || !(fFlags & (DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_NXE)) , VERR_INVALID_PARAMETER); AssertPtrReturn(pHlp, VERR_INVALID_POINTER); AssertReturn(cMaxDepth, VERR_INVALID_PARAMETER); /* * Forward the request to the target CPU. */ return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3PagingDumpEx, 8, pUVM, idCpu, fFlags, &cr3, &u64FirstAddr, &u64LastAddr, cMaxDepth, pHlp); }
/** * Read guest memory. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the target CPU context (for the address). * @param pAddress Where to start writing. * @param pvBuf The data to write. * @param cbWrite The number of bytes to write. */ VMMR3DECL(int) DBGFR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite) { UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID); return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3MemWrite, 5, pUVM, idCpu, pAddress, pvBuf, cbWrite); }