/** * @interface_method_impl{DBGCCMDHLP,pfnVarConvert} */ static DECLCALLBACK(int) dbgcHlpVarConvert(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pInVar, DBGCVARTYPE enmToType, bool fConvSyms, PDBGCVAR pResult) { PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); DBGCVAR const InVar = *pInVar; /* if pInVar == pResult */ PCDBGCVAR pArg = &InVar; /* lazy bird, clean up later */ DBGFADDRESS Address; int rc; Assert(pDbgc->pUVM); *pResult = InVar; switch (InVar.enmType) { case DBGCVAR_TYPE_GC_FLAT: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: return VINF_SUCCESS; case DBGCVAR_TYPE_GC_FAR: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_PHYS: pResult->enmType = DBGCVAR_TYPE_GC_PHYS; rc = DBGFR3AddrToPhys(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromFlat(pDbgc->pUVM, &Address, pArg->u.GCFlat), &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_FLAT: pResult->enmType = DBGCVAR_TYPE_HC_FLAT; rc = DBGFR3AddrToVolatileR3Ptr(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromFlat(pDbgc->pUVM, &Address, pArg->u.GCFlat), false /*fReadOnly */, &pResult->u.pvHCFlat); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_PHYS: pResult->enmType = DBGCVAR_TYPE_HC_PHYS; rc = DBGFR3AddrToHostPhys(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromFlat(pDbgc->pUVM, &Address, pArg->u.GCFlat), &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_NUMBER: pResult->enmType = enmToType; pResult->u.u64Number = InVar.u.GCFlat; return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_GC_FAR: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off); if (RT_SUCCESS(rc)) { pResult->enmType = DBGCVAR_TYPE_GC_FLAT; pResult->u.GCFlat = Address.FlatPtr; return VINF_SUCCESS; } return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_GC_FAR: return VINF_SUCCESS; case DBGCVAR_TYPE_GC_PHYS: rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off); if (RT_SUCCESS(rc)) { pResult->enmType = DBGCVAR_TYPE_GC_PHYS; rc = DBGFR3AddrToPhys(pDbgc->pUVM, pDbgc->idCpu, &Address, &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; } return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_FLAT: rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off); if (RT_SUCCESS(rc)) { pResult->enmType = DBGCVAR_TYPE_HC_FLAT; rc = DBGFR3AddrToVolatileR3Ptr(pDbgc->pUVM, pDbgc->idCpu, &Address, false /*fReadOnly*/, &pResult->u.pvHCFlat); if (RT_SUCCESS(rc)) return VINF_SUCCESS; } return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_PHYS: rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off); if (RT_SUCCESS(rc)) { pResult->enmType = DBGCVAR_TYPE_HC_PHYS; rc = DBGFR3AddrToHostPhys(pDbgc->pUVM, pDbgc->idCpu, &Address, &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; } return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_NUMBER: pResult->enmType = enmToType; pResult->u.u64Number = InVar.u.GCFar.off; return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_GC_PHYS: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure. return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_FAR: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_PHYS: return VINF_SUCCESS; case DBGCVAR_TYPE_HC_FLAT: pResult->enmType = DBGCVAR_TYPE_HC_FLAT; rc = DBGFR3AddrToVolatileR3Ptr(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromPhys(pDbgc->pUVM, &Address, pArg->u.GCPhys), false /*fReadOnly */, &pResult->u.pvHCFlat); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_PHYS: pResult->enmType = DBGCVAR_TYPE_HC_PHYS; rc = DBGFR3AddrToHostPhys(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromPhys(pDbgc->pUVM, &Address, pArg->u.GCPhys), &pResult->u.HCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_NUMBER: pResult->enmType = enmToType; pResult->u.u64Number = InVar.u.GCPhys; return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_HC_FLAT: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_FAR: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_PHYS: pResult->enmType = DBGCVAR_TYPE_GC_PHYS; rc = PGMR3DbgR3Ptr2GCPhys(pDbgc->pUVM, pArg->u.pvHCFlat, &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; /** @todo more memory types! */ return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_FLAT: return VINF_SUCCESS; case DBGCVAR_TYPE_HC_PHYS: pResult->enmType = DBGCVAR_TYPE_HC_PHYS; rc = PGMR3DbgR3Ptr2HCPhys(pDbgc->pUVM, pArg->u.pvHCFlat, &pResult->u.HCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; /** @todo more memory types! */ return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_NUMBER: pResult->enmType = enmToType; pResult->u.u64Number = (uintptr_t)InVar.u.pvHCFlat; return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_HC_PHYS: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_FAR: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_PHYS: pResult->enmType = DBGCVAR_TYPE_GC_PHYS; rc = PGMR3DbgHCPhys2GCPhys(pDbgc->pUVM, pArg->u.HCPhys, &pResult->u.GCPhys); if (RT_SUCCESS(rc)) return VINF_SUCCESS; return VERR_DBGC_PARSE_CONVERSION_FAILED; case DBGCVAR_TYPE_HC_FLAT: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_HC_PHYS: return VINF_SUCCESS; case DBGCVAR_TYPE_NUMBER: pResult->enmType = enmToType; pResult->u.u64Number = InVar.u.HCPhys; return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_NUMBER: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: pResult->enmType = DBGCVAR_TYPE_GC_FLAT; pResult->u.GCFlat = (RTGCPTR)InVar.u.u64Number; return VINF_SUCCESS; case DBGCVAR_TYPE_GC_FAR: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_GC_PHYS: pResult->enmType = DBGCVAR_TYPE_GC_PHYS; pResult->u.GCPhys = (RTGCPHYS)InVar.u.u64Number; return VINF_SUCCESS; case DBGCVAR_TYPE_HC_FLAT: pResult->enmType = DBGCVAR_TYPE_HC_FLAT; pResult->u.pvHCFlat = (void *)(uintptr_t)InVar.u.u64Number; return VINF_SUCCESS; case DBGCVAR_TYPE_HC_PHYS: pResult->enmType = DBGCVAR_TYPE_HC_PHYS; pResult->u.HCPhys = (RTHCPHYS)InVar.u.u64Number; return VINF_SUCCESS; case DBGCVAR_TYPE_NUMBER: return VINF_SUCCESS; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_SYMBOL: case DBGCVAR_TYPE_STRING: switch (enmToType) { case DBGCVAR_TYPE_GC_FLAT: case DBGCVAR_TYPE_GC_FAR: case DBGCVAR_TYPE_GC_PHYS: case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: case DBGCVAR_TYPE_NUMBER: if (fConvSyms) { rc = dbgcSymbolGet(pDbgc, InVar.u.pszString, enmToType, pResult); if (RT_SUCCESS(rc)) return VINF_SUCCESS; } return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; case DBGCVAR_TYPE_STRING: case DBGCVAR_TYPE_SYMBOL: pResult->enmType = enmToType; return VINF_SUCCESS; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } break; case DBGCVAR_TYPE_UNKNOWN: case DBGCVAR_TYPE_ANY: break; } AssertMsgFailed(("f=%d t=%d\n", InVar.enmType, enmToType)); return VERR_INVALID_PARAMETER; }
/** * @interface_method_impl{DBGCCMDHLP,pfnMemWrite} */ static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten) { PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); DBGFADDRESS Address; int rc; /* * Dummy check. */ if (cbWrite == 0) { if (*pcbWritten) *pcbWritten = 0; return VINF_SUCCESS; } /* * Convert Far addresses getting size and the correct base address. * Getting and checking the size is what makes this messy and slow. */ DBGCVAR Var = *pVarPointer; switch (pVarPointer->enmType) { case DBGCVAR_TYPE_GC_FAR: { /* Use DBGFR3AddrFromSelOff for the conversion. */ Assert(pDbgc->pUVM); rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, Var.u.GCFar.sel, Var.u.GCFar.off); if (RT_FAILURE(rc)) return rc; /* don't bother with flat selectors (for now). */ if (!DBGFADDRESS_IS_FLAT(&Address)) { DBGFSELINFO SelInfo; rc = DBGFR3SelQueryInfo(pDbgc->pUVM, pDbgc->idCpu, Address.Sel, DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE, &SelInfo); if (RT_SUCCESS(rc)) { RTGCUINTPTR cb; /* -1 byte */ if (DBGFSelInfoIsExpandDown(&SelInfo)) { if ( !SelInfo.u.Raw.Gen.u1Granularity && Address.off > UINT16_C(0xffff)) return VERR_OUT_OF_SELECTOR_BOUNDS; if (Address.off <= SelInfo.cbLimit) return VERR_OUT_OF_SELECTOR_BOUNDS; cb = (SelInfo.u.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off; } else { if (Address.off > SelInfo.cbLimit) return VERR_OUT_OF_SELECTOR_BOUNDS; cb = SelInfo.cbLimit - Address.off; } if (cbWrite - 1 > cb) { if (!pcbWritten) return VERR_OUT_OF_SELECTOR_BOUNDS; cbWrite = cb + 1; } } } Var.enmType = DBGCVAR_TYPE_GC_FLAT; Var.u.GCFlat = Address.FlatPtr; } /* fall thru */ case DBGCVAR_TYPE_GC_FLAT: rc = DBGFR3MemWrite(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromFlat(pDbgc->pUVM, &Address, Var.u.GCFlat), pvBuffer, cbWrite); if (pcbWritten && RT_SUCCESS(rc)) *pcbWritten = cbWrite; return rc; case DBGCVAR_TYPE_GC_PHYS: rc = DBGFR3MemWrite(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromPhys(pDbgc->pUVM, &Address, Var.u.GCPhys), pvBuffer, cbWrite); if (pcbWritten && RT_SUCCESS(rc)) *pcbWritten = cbWrite; return rc; case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: { /* * Copy HC memory page by page. */ if (pcbWritten) *pcbWritten = 0; while (cbWrite > 0) { /* convert to flat address */ DBGCVAR Var2; rc = dbgcOpAddrFlat(pDbgc, &Var, DBGCVAR_CAT_ANY, &Var2); if (RT_FAILURE(rc)) { if (pcbWritten && *pcbWritten) return -VERR_INVALID_POINTER; return VERR_INVALID_POINTER; } /* calc size. */ size_t cbChunk = PAGE_SIZE; cbChunk -= (uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK; if (cbChunk > cbWrite) cbChunk = cbWrite; /** @todo protect this!!! */ memcpy(Var2.u.pvHCFlat, pvBuffer, cbChunk); /* advance */ if (Var.enmType == DBGCVAR_TYPE_HC_FLAT) Var.u.pvHCFlat = (uint8_t *)Var.u.pvHCFlat + cbChunk; else Var.u.HCPhys += cbChunk; pvBuffer = (uint8_t const *)pvBuffer + cbChunk; if (pcbWritten) *pcbWritten += cbChunk; cbWrite -= cbChunk; } return VINF_SUCCESS; } default: return VERR_NOT_IMPLEMENTED; } }
/** * Internal worker routine. * * On x86 the typical stack frame layout is like this: * .. .. * 16 parameter 2 * 12 parameter 1 * 8 parameter 0 * 4 return address * 0 old ebp; current ebp points here * * @todo Add AMD64 support (needs teaming up with the module management for * unwind tables). */ static int dbgfR3StackWalk(PUVM pUVM, VMCPUID idCpu, RTDBGAS hAs, PDBGFSTACKFRAME pFrame) { /* * Stop if we got a read error in the previous run. */ if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST) return VERR_NO_MORE_FILES; /* * Read the raw frame data. */ const DBGFADDRESS AddrOldPC = pFrame->AddrPC; const unsigned cbRetAddr = DBGFReturnTypeSize(pFrame->enmReturnType); unsigned cbStackItem; switch (AddrOldPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) { case DBGFADDRESS_FLAGS_FAR16: cbStackItem = 2; break; case DBGFADDRESS_FLAGS_FAR32: cbStackItem = 4; break; case DBGFADDRESS_FLAGS_FAR64: cbStackItem = 8; break; case DBGFADDRESS_FLAGS_RING0: cbStackItem = sizeof(RTHCUINTPTR); break; default: switch (pFrame->enmReturnType) { case DBGFRETURNTYPE_FAR16: case DBGFRETURNTYPE_IRET16: case DBGFRETURNTYPE_IRET32_V86: case DBGFRETURNTYPE_NEAR16: cbStackItem = 2; break; case DBGFRETURNTYPE_FAR32: case DBGFRETURNTYPE_IRET32: case DBGFRETURNTYPE_IRET32_PRIV: case DBGFRETURNTYPE_NEAR32: cbStackItem = 4; break; case DBGFRETURNTYPE_FAR64: case DBGFRETURNTYPE_IRET64: case DBGFRETURNTYPE_NEAR64: cbStackItem = 8; break; default: AssertMsgFailed(("%d\n", pFrame->enmReturnType)); cbStackItem = 4; break; } } union { uint64_t *pu64; uint32_t *pu32; uint16_t *pu16; uint8_t *pb; void *pv; } u, uRet, uArgs, uBp; size_t cbRead = cbRetAddr + cbStackItem + sizeof(pFrame->Args); u.pv = alloca(cbRead); uBp = u; uRet.pb = u.pb + cbStackItem; uArgs.pb = u.pb + cbStackItem + cbRetAddr; Assert(DBGFADDRESS_IS_VALID(&pFrame->AddrFrame)); int rc = dbgfR3Read(pUVM, idCpu, u.pv, pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID ? &pFrame->AddrReturnFrame : &pFrame->AddrFrame, cbRead, &cbRead); if ( RT_FAILURE(rc) || cbRead < cbRetAddr + cbStackItem) pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_LAST; /* * The first step is taken in a different way than the others. */ if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID)) { pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_ALL_VALID; pFrame->iFrame = 0; /* Current PC - set by caller, just find symbol & line. */ if (DBGFADDRESS_IS_VALID(&pFrame->AddrPC)) { pFrame->pSymPC = DBGFR3AsSymbolByAddrA(pUVM, hAs, &pFrame->AddrPC, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, NULL /*poffDisp*/, NULL /*phMod*/); pFrame->pLinePC = DBGFR3AsLineByAddrA(pUVM, hAs, &pFrame->AddrPC, NULL /*poffDisp*/, NULL /*phMod*/); } } else /* 2nd and subsequent steps */ { /* frame, pc and stack is taken from the existing frames return members. */ pFrame->AddrFrame = pFrame->AddrReturnFrame; pFrame->AddrPC = pFrame->AddrReturnPC; pFrame->pSymPC = pFrame->pSymReturnPC; pFrame->pLinePC = pFrame->pLineReturnPC; /* increment the frame number. */ pFrame->iFrame++; } /* * Return Frame address. */ pFrame->AddrReturnFrame = pFrame->AddrFrame; switch (cbStackItem) { case 2: pFrame->AddrReturnFrame.off = *uBp.pu16; break; case 4: pFrame->AddrReturnFrame.off = *uBp.pu32; break; case 8: pFrame->AddrReturnFrame.off = *uBp.pu64; break; default: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_1); } pFrame->AddrReturnFrame.FlatPtr += pFrame->AddrReturnFrame.off - pFrame->AddrFrame.off; /* * Return PC and Stack Addresses. */ /** @todo AddrReturnStack is not correct for stdcall and pascal. (requires scope info) */ pFrame->AddrReturnStack = pFrame->AddrFrame; pFrame->AddrReturnStack.off += cbStackItem + cbRetAddr; pFrame->AddrReturnStack.FlatPtr += cbStackItem + cbRetAddr; pFrame->AddrReturnPC = pFrame->AddrPC; switch (pFrame->enmReturnType) { case DBGFRETURNTYPE_NEAR16: if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC)) { pFrame->AddrReturnPC.FlatPtr += *uRet.pu16 - pFrame->AddrReturnPC.off; pFrame->AddrReturnPC.off = *uRet.pu16; } else DBGFR3AddrFromFlat(pUVM, &pFrame->AddrReturnPC, *uRet.pu16); break; case DBGFRETURNTYPE_NEAR32: if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC)) { pFrame->AddrReturnPC.FlatPtr += *uRet.pu32 - pFrame->AddrReturnPC.off; pFrame->AddrReturnPC.off = *uRet.pu32; } else DBGFR3AddrFromFlat(pUVM, &pFrame->AddrReturnPC, *uRet.pu32); break; case DBGFRETURNTYPE_NEAR64: if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC)) { pFrame->AddrReturnPC.FlatPtr += *uRet.pu64 - pFrame->AddrReturnPC.off; pFrame->AddrReturnPC.off = *uRet.pu64; } else DBGFR3AddrFromFlat(pUVM, &pFrame->AddrReturnPC, *uRet.pu64); break; case DBGFRETURNTYPE_FAR16: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]); break; case DBGFRETURNTYPE_FAR32: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]); break; case DBGFRETURNTYPE_FAR64: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]); break; case DBGFRETURNTYPE_IRET16: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]); break; case DBGFRETURNTYPE_IRET32: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]); break; case DBGFRETURNTYPE_IRET32_PRIV: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]); break; case DBGFRETURNTYPE_IRET32_V86: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]); break; case DBGFRETURNTYPE_IRET64: DBGFR3AddrFromSelOff(pUVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]); break; default: AssertMsgFailed(("enmReturnType=%d\n", pFrame->enmReturnType)); return VERR_INVALID_PARAMETER; } pFrame->pSymReturnPC = DBGFR3AsSymbolByAddrA(pUVM, hAs, &pFrame->AddrReturnPC, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, NULL /*poffDisp*/, NULL /*phMod*/); pFrame->pLineReturnPC = DBGFR3AsLineByAddrA(pUVM, hAs, &pFrame->AddrReturnPC, NULL /*poffDisp*/, NULL /*phMod*/); /* * Frame bitness flag. */ switch (cbStackItem) { case 2: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_16BIT; break; case 4: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_32BIT; break; case 8: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_64BIT; break; default: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_2); } /* * The arguments. */ memcpy(&pFrame->Args, uArgs.pv, sizeof(pFrame->Args)); return VINF_SUCCESS; }
/** * @interface_method_impl{DBGCCMDHLP,pfnMemRead} */ static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead) { PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); DBGFADDRESS Address; int rc; /* * Dummy check. */ if (cbRead == 0) { if (*pcbRead) *pcbRead = 0; return VINF_SUCCESS; } /* * Convert Far addresses getting size and the correct base address. * Getting and checking the size is what makes this messy and slow. */ DBGCVAR Var = *pVarPointer; switch (pVarPointer->enmType) { case DBGCVAR_TYPE_GC_FAR: /* Use DBGFR3AddrFromSelOff for the conversion. */ Assert(pDbgc->pUVM); rc = DBGFR3AddrFromSelOff(pDbgc->pUVM, pDbgc->idCpu, &Address, Var.u.GCFar.sel, Var.u.GCFar.off); if (RT_FAILURE(rc)) return rc; /* don't bother with flat selectors (for now). */ if (!DBGFADDRESS_IS_FLAT(&Address)) { DBGFSELINFO SelInfo; rc = DBGFR3SelQueryInfo(pDbgc->pUVM, pDbgc->idCpu, Address.Sel, DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE, &SelInfo); if (RT_SUCCESS(rc)) { RTGCUINTPTR cb; /* -1 byte */ if (DBGFSelInfoIsExpandDown(&SelInfo)) { if ( !SelInfo.u.Raw.Gen.u1Granularity && Address.off > UINT16_C(0xffff)) return VERR_OUT_OF_SELECTOR_BOUNDS; if (Address.off <= SelInfo.cbLimit) return VERR_OUT_OF_SELECTOR_BOUNDS; cb = (SelInfo.u.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off; } else { if (Address.off > SelInfo.cbLimit) return VERR_OUT_OF_SELECTOR_BOUNDS; cb = SelInfo.cbLimit - Address.off; } if (cbRead - 1 > cb) { if (!pcbRead) return VERR_OUT_OF_SELECTOR_BOUNDS; cbRead = cb + 1; } } } Var.enmType = DBGCVAR_TYPE_GC_FLAT; Var.u.GCFlat = Address.FlatPtr; break; case DBGCVAR_TYPE_GC_FLAT: case DBGCVAR_TYPE_GC_PHYS: case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: break; default: return VERR_NOT_IMPLEMENTED; } /* * Copy page by page. */ size_t cbLeft = cbRead; for (;;) { /* * Calc read size. */ size_t cb = RT_MIN(PAGE_SIZE, cbLeft); switch (pVarPointer->enmType) { case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break; case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break; case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break; case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */ default: break; } /* * Perform read. */ switch (Var.enmType) { case DBGCVAR_TYPE_GC_FLAT: rc = DBGFR3MemRead(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromFlat(pDbgc->pUVM, &Address, Var.u.GCFlat), pvBuffer, cb); break; case DBGCVAR_TYPE_GC_PHYS: rc = DBGFR3MemRead(pDbgc->pUVM, pDbgc->idCpu, DBGFR3AddrFromPhys(pDbgc->pUVM, &Address, Var.u.GCPhys), pvBuffer, cb); break; case DBGCVAR_TYPE_HC_PHYS: case DBGCVAR_TYPE_HC_FLAT: { DBGCVAR Var2; rc = dbgcOpAddrFlat(pDbgc, &Var, DBGCVAR_CAT_ANY, &Var2); if (RT_SUCCESS(rc)) { /** @todo protect this!!! */ memcpy(pvBuffer, Var2.u.pvHCFlat, cb); rc = 0; } else rc = VERR_INVALID_POINTER; break; } default: rc = VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; } /* * Check for failure. */ if (RT_FAILURE(rc)) { if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0) return VINF_SUCCESS; return rc; } /* * Next. */ cbLeft -= cb; if (!cbLeft) break; pvBuffer = (char *)pvBuffer + cb; rc = DBGCCmdHlpEval(pCmdHlp, &Var, "%DV + %d", &Var, cb); if (RT_FAILURE(rc)) { if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0) return VINF_SUCCESS; return rc; } } /* * Done */ if (pcbRead) *pcbRead = cbRead; return 0; }
/** * Walks the entire stack allocating memory as we walk. */ static DECLCALLBACK(int) dbgfR3StackWalkCtxFull(PUVM pUVM, VMCPUID idCpu, PCCPUMCTXCORE pCtxCore, RTDBGAS hAs, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, PCDBGFADDRESS pAddrStack, PCDBGFADDRESS pAddrPC, DBGFRETURNTYPE enmReturnType, PCDBGFSTACKFRAME *ppFirstFrame) { /* alloc first frame. */ PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_STACK, sizeof(*pCur)); if (!pCur) return VERR_NO_MEMORY; /* * Initialize the frame. */ pCur->pNextInternal = NULL; pCur->pFirstInternal = pCur; int rc = VINF_SUCCESS; if (pAddrPC) pCur->AddrPC = *pAddrPC; else if (enmCodeType != DBGFCODETYPE_GUEST) DBGFR3AddrFromFlat(pUVM, &pCur->AddrPC, pCtxCore->rip); else rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrPC, pCtxCore->cs.Sel, pCtxCore->rip); if (RT_SUCCESS(rc)) { if (enmReturnType == DBGFRETURNTYPE_INVALID) switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) { case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break; case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break; case DBGFADDRESS_FLAGS_RING0: pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32; break; default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests } uint64_t fAddrMask; if (enmCodeType == DBGFCODETYPE_RING0) fAddrMask = HC_ARCH_BITS == 64 ? UINT64_MAX : UINT32_MAX; else if (enmCodeType == DBGFCODETYPE_HYPER) fAddrMask = UINT32_MAX; else if (DBGFADDRESS_IS_FAR16(&pCur->AddrPC)) fAddrMask = UINT16_MAX; else if (DBGFADDRESS_IS_FAR32(&pCur->AddrPC)) fAddrMask = UINT32_MAX; else if (DBGFADDRESS_IS_FAR64(&pCur->AddrPC)) fAddrMask = UINT64_MAX; else { PVMCPU pVCpu = VMMGetCpuById(pUVM->pVM, idCpu); CPUMMODE CpuMode = CPUMGetGuestMode(pVCpu); if (CpuMode == CPUMMODE_REAL) fAddrMask = UINT16_MAX; else if ( CpuMode == CPUMMODE_PROTECTED || !CPUMIsGuestIn64BitCode(pVCpu)) fAddrMask = UINT32_MAX; else fAddrMask = UINT64_MAX; } if (pAddrStack) pCur->AddrStack = *pAddrStack; else if (enmCodeType != DBGFCODETYPE_GUEST) DBGFR3AddrFromFlat(pUVM, &pCur->AddrStack, pCtxCore->rsp & fAddrMask); else rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrStack, pCtxCore->ss.Sel, pCtxCore->rsp & fAddrMask); if (pAddrFrame) pCur->AddrFrame = *pAddrFrame; else if (enmCodeType != DBGFCODETYPE_GUEST) DBGFR3AddrFromFlat(pUVM, &pCur->AddrFrame, pCtxCore->rbp & fAddrMask); else if (RT_SUCCESS(rc)) rc = DBGFR3AddrFromSelOff(pUVM, idCpu, &pCur->AddrFrame, pCtxCore->ss.Sel, pCtxCore->rbp & fAddrMask); } else pCur->enmReturnType = enmReturnType; /* * The first frame. */ if (RT_SUCCESS(rc)) rc = dbgfR3StackWalk(pUVM, idCpu, hAs, pCur); if (RT_FAILURE(rc)) { DBGFR3StackWalkEnd(pCur); return rc; } /* * The other frames. */ DBGFSTACKFRAME Next = *pCur; while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP))) { /* try walk. */ rc = dbgfR3StackWalk(pUVM, idCpu, hAs, &Next); if (RT_FAILURE(rc)) break; /* add the next frame to the chain. */ PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_STACK, sizeof(*pNext)); if (!pNext) { DBGFR3StackWalkEnd(pCur); return VERR_NO_MEMORY; } *pNext = Next; pCur->pNextInternal = pNext; pCur = pNext; Assert(pCur->pNextInternal == NULL); /* check for loop */ for (PCDBGFSTACKFRAME pLoop = pCur->pFirstInternal; pLoop && pLoop != pCur; pLoop = pLoop->pNextInternal) if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr) { pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP; break; } /* check for insane recursion */ if (pCur->iFrame >= 2048) pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH; } *ppFirstFrame = pCur->pFirstInternal; return rc; }