/** * 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); }
/** * Load symbols from an executable module into the specified address space. * * If an module exist at the specified address it will be replaced by this * call, otherwise a new module is created. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space. * @param pszFilename The filename of the executable module. * @param pszModName The module name. If NULL, then then the file name * base is used (no extension or nothing). * @param enmArch The desired architecture, use RTLDRARCH_WHATEVER if * it's not relevant or known. * @param pModAddress The load address of the module. * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load * the whole image. * @param fFlags Flags reserved for future extensions, must be 0. */ VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, RTLDRARCH enmArch, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags) { /* * Validate input */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); AssertReturn(*pszFilename, VERR_INVALID_PARAMETER); AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER); AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; RTDBGMOD hDbgMod; int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszModName, enmArch, pUVM->dbgf.s.hDbgCfg); if (RT_SUCCESS(rc)) { rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0); if (RT_FAILURE(rc)) RTDbgModRelease(hDbgMod); } RTDbgAsRelease(hRealAS); return rc; }
VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pLine, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pLine, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pLine, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ return RTDbgAsLineByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pLine, phMod); }
/** * Read a zero terminated string from guest memory. * * @returns VBox status code. * * @param pVM Pointer to the shared VM structure. * @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. */ static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf) { /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pszBuf)) return VERR_INVALID_POINTER; /* * Let dbgfR3MemRead do the job. */ int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf); /* * Make sure the result is terminated and that overflow is signaled. * This may look a bit reckless with the rc but, it should be fine. */ if (!RTStrEnd(pszBuf, cchBuf)) { pszBuf[cchBuf - 1] = '\0'; rc = VINF_BUFFER_OVERFLOW; } /* * Handle partial reads (not perfect). */ else if (RT_FAILURE(rc)) { if (pszBuf[0]) rc = VINF_SUCCESS; } return rc; }
/** * EMT worker for DBGFR3BpSetREM(). * * @returns VBox status code. * @param pVM The VM handle. * @param pAddress The address of the breakpoint. * @param piHitTrigger The hit count at which the breakpoint start triggering. * Use 0 (or 1) if it's gonna trigger at once. * @param piHitDisable The hit count which disables the breakpoint. * Use ~(uint64_t) if it's never gonna be disabled. * @param piBp Where to store the breakpoint id. (optional) * @thread EMT * @internal */ static DECLCALLBACK(int) dbgfR3BpSetREM(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint32_t *piBp) { /* * Validate input. */ if (!DBGFR3AddrIsValid(pVM, pAddress)) return VERR_INVALID_PARAMETER; if (*piHitTrigger > *piHitDisable) return VERR_INVALID_PARAMETER; AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER); if (piBp) *piBp = ~0; /* * Check if the breakpoint already exists. */ PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REM, pAddress->FlatPtr); if (pBp) { int rc = VINF_SUCCESS; if (!pBp->fEnabled) rc = REMR3BreakpointSet(pVM, pBp->GCPtr); if (RT_SUCCESS(rc)) { rc = VINF_DBGF_BP_ALREADY_EXIST; if (piBp) *piBp = pBp->iBp; } return rc; } /* * Allocate and initialize the bp. */ pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REM); if (!pBp) return VERR_DBGF_NO_MORE_BP_SLOTS; pBp->GCPtr = pAddress->FlatPtr; pBp->iHitTrigger = *piHitTrigger; pBp->iHitDisable = *piHitDisable; pBp->fEnabled = true; /* * Now ask REM to set the breakpoint. */ int rc = REMR3BreakpointSet(pVM, pAddress->FlatPtr); if (RT_SUCCESS(rc)) { if (piBp) *piBp = pBp->iBp; } else dbgfR3BpFree(pVM, pBp); return rc; }
/** * Scan guest memory for an exact byte string. * * @returns VBox status code. * @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 puAlign The alignment restriction imposed on the search result. * @param pcbRange The number of bytes to scan. Passed as a pointer because * it may be 64-bit. * @param pabNeedle 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. */ static DECLCALLBACK(int) dbgfR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange, RTGCUINTPTR *puAlign, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress) { PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); Assert(idCpu == VMMGetCpuId(pVM)); /* * Validate the input we use, PGM does the rest. */ RTGCUINTPTR cbRange = *pcbRange; if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pHitAddress)) return VERR_INVALID_POINTER; if (DBGFADDRESS_IS_HMA(pAddress)) return VERR_INVALID_POINTER; /* * Select DBGF worker by addressing mode. */ int rc; PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) { RTGCPHYS GCPhysAlign = *puAlign; if (GCPhysAlign != *puAlign) return VERR_OUT_OF_RANGE; RTGCPHYS PhysHit; rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, GCPhysAlign, pabNeedle, cbNeedle, &PhysHit); if (RT_SUCCESS(rc)) DBGFR3AddrFromPhys(pUVM, pHitAddress, PhysHit); } else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbRange > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_DBGF_MEM_NOT_FOUND; #endif RTGCUINTPTR GCPtrHit; rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, *puAlign, pabNeedle, cbNeedle, &GCPtrHit); if (RT_SUCCESS(rc)) DBGFR3AddrFromFlat(pUVM, pHitAddress, GCPtrHit); } return rc; }
/** * Read guest memory. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param idCpu The ID of the CPU context to read memory from. * @param pAddress Where to start reading. * @param pvBuf Where to store the data we've read. * @param cbRead The number of bytes to read. */ static DECLCALLBACK(int) dbgfR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead) { PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); Assert(idCpu == VMMGetCpuId(pVM)); /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pvBuf)) return VERR_INVALID_POINTER; /* * HMA is special */ int rc; if (DBGFADDRESS_IS_HMA(pAddress)) { if (DBGFADDRESS_IS_PHYS(pAddress)) rc = VERR_INVALID_POINTER; else rc = MMR3HyperReadGCVirt(pVM, pvBuf, pAddress->FlatPtr, cbRead); } else { /* * Select DBGF worker by addressing mode. */ PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead); else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbRead > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_PAGE_TABLE_NOT_PRESENT; #endif rc = PGMPhysSimpleReadGCPtr(pVCpu, pvBuf, pAddress->FlatPtr, cbRead); } } return rc; }
/** * Writes 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. */ static DECLCALLBACK(int) dbgfR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite) { /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pvBuf)) return VERR_INVALID_POINTER; PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); /* * HMA is always special. */ int rc; if (DBGFADDRESS_IS_HMA(pAddress)) { /** @todo write to HMA. */ rc = VERR_ACCESS_DENIED; } else { /* * Select PGM function by addressing mode. */ PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite); else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbWrite > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_PAGE_TABLE_NOT_PRESENT; #endif rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite); } } return rc; }
/** * Query a symbol by address. * * The returned symbol is the one we consider closes to the specified address. * * @returns VBox status code. See RTDbgAsSymbolByAddr. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. * @param pAddress The address to lookup. * @param fFlags One of the RTDBGSYMADDR_FLAGS_XXX flags. * @param poffDisp Where to return the distance between the returned * symbol and pAddress. Optional. * @param pSymbol Where to return the symbol information. The returned * symbol name will be prefixed by the module name as * far as space allows. * @param phMod Where to return the module handle. Optional. */ VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags, PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, fFlags, poffDisp, pSymbol, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, fFlags, poffDisp, pSymbol, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pSymbol, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ RTDBGMOD hMod; int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, fFlags, poffDisp, pSymbol, &hMod); if (RT_SUCCESS(rc)) { dbgfR3AsSymbolJoinNames(pSymbol, hMod); if (!phMod) RTDbgModRelease(hMod); } return rc; }
/** * Load symbols from a map file into a module at the specified address space. * * If an module exist at the specified address it will be replaced by this * call, otherwise a new module is created. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space. * @param pszFilename The map file. * @param pszModName The module name. If NULL, then then the file name * base is used (no extension or nothing). * @param pModAddress The load address of the module. * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load * the whole image. * @param uSubtrahend Value to to subtract from the symbols in the map * file. This is useful for the linux System.map and * /proc/kallsyms. * @param fFlags Flags reserved for future extensions, must be 0. */ VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags) { /* * Validate input */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); AssertReturn(*pszFilename, VERR_INVALID_PARAMETER); AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER); AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the work. */ DBGFR3ASLOADOPENDATA Data; Data.pszModName = pszModName; Data.uSubtrahend = uSubtrahend; Data.fFlags = 0; Data.hMod = NIL_RTDBGMOD; int rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "MapPath", dbgfR3AsLoadMapOpen, &Data); if (RT_FAILURE(rc)) rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_MAP_PATH", dbgfR3AsLoadMapOpen, &Data); if (RT_FAILURE(rc)) rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "Path", dbgfR3AsLoadMapOpen, &Data); if (RT_FAILURE(rc)) rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadMapOpen, &Data); if (RT_SUCCESS(rc)) { rc = DBGFR3AsLinkModule(pUVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0); if (RT_FAILURE(rc)) RTDbgModRelease(Data.hMod); } RTDbgAsRelease(hRealAS); return rc; }
/** * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param hDbgAs The address space handle. * @param hMod The module handle. * @param pModAddress The link address. * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image. * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*. */ VMMR3DECL(int) DBGFR3AsLinkModule(PVM pVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags) { /* * Input validation. */ VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER); RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the job. */ int rc; if (iModSeg == NIL_RTDBGSEGIDX) rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags); else rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags); RTDbgAsRelease(hRealAS); return rc; }
/** * Query a symbol by address. * * The returned symbol is the one we consider closes to the specified address. * * @returns VBox status code. See RTDbgAsSymbolByAddr. * * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. * @param pAddress The address to lookup. * @param poffDisp Where to return the distance between the returned * symbol and pAddress. Optional. * @param pSymbol Where to return the symbol information. The returned * symbol name will be prefixed by the module name as * far as space allows. * @param phMod Where to return the module handle. Optional. */ VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod) { /* * Implement the special address space aliases the lazy way. */ if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL) { int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pSymbol, phMod); if (RT_FAILURE(rc)) rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pSymbol, phMod); return rc; } /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER); AssertPtrReturn(pSymbol, VERR_INVALID_POINTER); AssertPtrNullReturn(phMod, VERR_INVALID_POINTER); if (poffDisp) *poffDisp = 0; if (phMod) *phMod = NIL_RTDBGMOD; RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs); if (hRealAS == NIL_RTDBGAS) return VERR_INVALID_HANDLE; /* * Do the lookup. */ RTDBGMOD hMod; int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, poffDisp, pSymbol, &hMod); if (RT_SUCCESS(rc)) { dbgfR3AsSymbolJoinNames(pSymbol, hMod); if (!phMod) RTDbgModRelease(hMod); } /* Temporary conversions. */ else if (hDbgAs == DBGF_AS_GLOBAL) { DBGFSYMBOL DbgfSym; rc = DBGFR3SymbolByAddr(pUVM->pVM, pAddress->FlatPtr, poffDisp, &DbgfSym); if (RT_SUCCESS(rc)) dbgfR3AsSymbolConvert(pSymbol, &DbgfSym); } else if (hDbgAs == DBGF_AS_R0) { RTR0PTR R0PtrMod; char szNearSym[260]; RTR0PTR R0PtrNearSym; RTR0PTR R0PtrNearSym2; VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE); rc = PDMR3LdrQueryR0ModFromPC(pUVM->pVM, pAddress->FlatPtr, pSymbol->szName, sizeof(pSymbol->szName) / 2, &R0PtrMod, &szNearSym[0], sizeof(szNearSym), &R0PtrNearSym, NULL, 0, &R0PtrNearSym2); if (RT_SUCCESS(rc)) { pSymbol->offSeg = pSymbol->Value = R0PtrNearSym; pSymbol->cb = R0PtrNearSym2 > R0PtrNearSym ? R0PtrNearSym2 - R0PtrNearSym : 0; pSymbol->iSeg = 0; pSymbol->fFlags = 0; pSymbol->iOrdinal = UINT32_MAX; size_t offName = strlen(pSymbol->szName); pSymbol->szName[offName++] = '!'; size_t cchNearSym = strlen(szNearSym); if (cchNearSym + offName >= sizeof(pSymbol->szName)) cchNearSym = sizeof(pSymbol->szName) - offName - 1; strncpy(&pSymbol->szName[offName], szNearSym, cchNearSym); pSymbol->szName[offName + cchNearSym] = '\0'; if (poffDisp) *poffDisp = pAddress->FlatPtr - pSymbol->Value; } } return rc; }
/** * Sets a register breakpoint. * * @returns VBox status code. * @param pVM The VM handle. * @param pAddress The address of the breakpoint. * @param piHitTrigger The hit count at which the breakpoint start triggering. * Use 0 (or 1) if it's gonna trigger at once. * @param piHitDisable The hit count which disables the breakpoint. * Use ~(uint64_t) if it's never gonna be disabled. * @param fType The access type (one of the X86_DR7_RW_* defines). * @param cb The access size - 1,2,4 or 8 (the latter is AMD64 long mode only. * Must be 1 if fType is X86_DR7_RW_EO. * @param piBp Where to store the breakpoint id. (optional) * @thread EMT * @internal */ static DECLCALLBACK(int) dbgfR3BpSetReg(PVM pVM, PCDBGFADDRESS pAddress, uint64_t *piHitTrigger, uint64_t *piHitDisable, uint8_t fType, uint8_t cb, uint32_t *piBp) { /* * Validate input. */ if (!DBGFR3AddrIsValid(pVM, pAddress)) return VERR_INVALID_PARAMETER; if (*piHitTrigger > *piHitDisable) return VERR_INVALID_PARAMETER; AssertMsgReturn(!piBp || VALID_PTR(piBp), ("piBp=%p\n", piBp), VERR_INVALID_POINTER); if (piBp) *piBp = ~0; switch (fType) { case X86_DR7_RW_EO: if (cb == 1) break; AssertMsgFailed(("fType=%#x cb=%d != 1\n", fType, cb)); return VERR_INVALID_PARAMETER; case X86_DR7_RW_IO: case X86_DR7_RW_RW: case X86_DR7_RW_WO: break; default: AssertMsgFailed(("fType=%#x\n", fType)); return VERR_INVALID_PARAMETER; } switch (cb) { case 1: case 2: case 4: break; default: AssertMsgFailed(("cb=%#x\n", cb)); return VERR_INVALID_PARAMETER; } /* * Check if the breakpoint already exists. */ PDBGFBP pBp = dbgfR3BpGetByAddr(pVM, DBGFBPTYPE_REG, pAddress->FlatPtr); if ( pBp && pBp->u.Reg.cb == cb && pBp->u.Reg.fType == fType) { int rc = VINF_SUCCESS; if (!pBp->fEnabled) rc = dbgfR3BpRegArm(pVM, pBp); if (RT_SUCCESS(rc)) { rc = VINF_DBGF_BP_ALREADY_EXIST; if (piBp) *piBp = pBp->iBp; } return rc; } /* * Allocate and initialize the bp. */ pBp = dbgfR3BpAlloc(pVM, DBGFBPTYPE_REG); if (!pBp) return VERR_DBGF_NO_MORE_BP_SLOTS; pBp->GCPtr = pAddress->FlatPtr; pBp->iHitTrigger = *piHitTrigger; pBp->iHitDisable = *piHitDisable; pBp->fEnabled = true; Assert(pBp->iBp == pBp->u.Reg.iReg); pBp->u.Reg.fType = fType; pBp->u.Reg.cb = cb; /* * Arm the breakpoint. */ int rc = dbgfR3BpRegArm(pVM, pBp); if (RT_SUCCESS(rc)) { if (piBp) *piBp = pBp->iBp; } else dbgfR3BpFree(pVM, pBp); return rc; }