/** * @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; } }
/** * Subtraction operator (binary). * * @returns VINF_SUCCESS on success. * @returns VBox evaluation / parsing error code on failure. * The caller does the bitching. * @param pDbgc Debugger console instance data. * @param pArg1 The first argument. * @param pArg2 The 2nd argument. * @param pResult Where to store the result. */ static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult) { LogFlow(("dbgcOpSub\n")); /* * An subtraction operation will return the left side type in the expression. * However, if the left hand side is a number and the right hand a pointer of * some kind we'll convert the left hand side to the same type as the right hand. * Any symbols will be resolved, strings will be rejected. */ DBGCVAR Sym1, Sym2; if ( pArg2->enmType == DBGCVAR_TYPE_SYMBOL && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER || pArg1->enmType == DBGCVAR_TYPE_SYMBOL)) { int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2); if (RT_FAILURE(rc)) return rc; pArg2 = &Sym2; } if ( pArg1->enmType == DBGCVAR_TYPE_STRING || pArg2->enmType == DBGCVAR_TYPE_STRING) return VERR_DBGC_PARSE_INVALID_OPERATION; if (pArg1->enmType == DBGCVAR_TYPE_SYMBOL) { DBGCVARTYPE enmType; switch (pArg2->enmType) { case DBGCVAR_TYPE_NUMBER: enmType = DBGCVAR_TYPE_ANY; break; case DBGCVAR_TYPE_GC_FLAT: case DBGCVAR_TYPE_GC_PHYS: case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: enmType = pArg2->enmType; break; case DBGCVAR_TYPE_GC_FAR: enmType = DBGCVAR_TYPE_GC_FLAT; break; default: AssertFailedReturn(VERR_DBGC_IPE); } if (enmType != DBGCVAR_TYPE_STRING) { int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1); if (RT_FAILURE(rc)) return rc; pArg1 = &Sym1; } } else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER) { PFNDBGCOPUNARY pOp = NULL; switch (pArg2->enmType) { case DBGCVAR_TYPE_GC_FAR: case DBGCVAR_TYPE_GC_FLAT: pOp = dbgcOpAddrFlat; break; case DBGCVAR_TYPE_GC_PHYS: pOp = dbgcOpAddrPhys; break; case DBGCVAR_TYPE_HC_FLAT: pOp = dbgcOpAddrHost; break; case DBGCVAR_TYPE_HC_PHYS: pOp = dbgcOpAddrHostPhys; break; case DBGCVAR_TYPE_NUMBER: break; default: AssertFailedReturn(VERR_DBGC_IPE); } if (pOp) { int rc = pOp(pDbgc, pArg1, DBGCVAR_CAT_ANY, &Sym1); if (RT_FAILURE(rc)) return rc; pArg1 = &Sym1; } } /* * Normal processing. */ int rc; DBGCVAR Var; DBGCVAR Var2; switch (pArg1->enmType) { /* * GC Flat */ case DBGCVAR_TYPE_GC_FLAT: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; default: *pResult = *pArg1; rc = dbgcOpAddrFlat(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.GCFlat -= pArg2->u.GCFlat; break; } break; /* * GC Far */ case DBGCVAR_TYPE_GC_FAR: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; case DBGCVAR_TYPE_NUMBER: *pResult = *pArg1; pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number; break; default: rc = dbgcOpAddrFlat(pDbgc, pArg1, DBGCVAR_CAT_ANY, pResult); if (RT_FAILURE(rc)) return rc; rc = dbgcOpAddrFlat(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.GCFlat -= pArg2->u.GCFlat; break; } break; /* * GC Phys */ case DBGCVAR_TYPE_GC_PHYS: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; default: *pResult = *pArg1; rc = dbgcOpAddrPhys(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; if (Var.enmType != DBGCVAR_TYPE_GC_PHYS) return VERR_DBGC_PARSE_INVALID_OPERATION; pResult->u.GCPhys -= Var.u.GCPhys; break; } break; /* * HC Flat */ case DBGCVAR_TYPE_HC_FLAT: *pResult = *pArg1; rc = dbgcOpAddrHost(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var2); if (RT_FAILURE(rc)) return rc; rc = dbgcOpAddrFlat(pDbgc, &Var2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat; break; /* * HC Phys */ case DBGCVAR_TYPE_HC_PHYS: *pResult = *pArg1; rc = dbgcOpAddrHostPhys(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.HCPhys -= Var.u.HCPhys; break; /* * Numbers (see start of function) */ case DBGCVAR_TYPE_NUMBER: *pResult = *pArg1; switch (pArg2->enmType) { case DBGCVAR_TYPE_SYMBOL: rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var); if (RT_FAILURE(rc)) return rc; case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number -= pArg2->u.u64Number; break; default: return VERR_DBGC_PARSE_INVALID_OPERATION; } break; default: return VERR_DBGC_PARSE_INVALID_OPERATION; } 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; }
/** * Addition operator (binary). * * @returns VINF_SUCCESS on success. * @returns VBox evaluation / parsing error code on failure. * The caller does the bitching. * @param pDbgc Debugger console instance data. * @param pArg1 The first argument. * @param pArg2 The 2nd argument. * @param pResult Where to store the result. */ static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult) { LogFlow(("dbgcOpAdd\n")); /* * An addition operation will return (when possible) the left side type in the * expression. We make an omission for numbers, where we'll take the right side * type instead. An expression where only the left hand side is a symbol we'll * use the right hand type to try resolve it. */ if ( pArg1->enmType == DBGCVAR_TYPE_STRING || pArg2->enmType == DBGCVAR_TYPE_STRING) return VERR_DBGC_PARSE_INVALID_OPERATION; /** @todo string contactenation later. */ if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_SYMBOL) || (pArg1->enmType == DBGCVAR_TYPE_SYMBOL && pArg2->enmType != DBGCVAR_TYPE_SYMBOL)) { PCDBGCVAR pTmp = pArg2; pArg2 = pArg1; pArg1 = pTmp; } DBGCVAR Sym1, Sym2; if (pArg1->enmType == DBGCVAR_TYPE_SYMBOL) { int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1); if (RT_FAILURE(rc)) return rc; pArg1 = &Sym1; rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2); if (RT_FAILURE(rc)) return rc; pArg2 = &Sym2; } int rc; DBGCVAR Var; DBGCVAR Var2; switch (pArg1->enmType) { /* * GC Flat */ case DBGCVAR_TYPE_GC_FLAT: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; default: *pResult = *pArg1; rc = dbgcOpAddrFlat(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.GCFlat += pArg2->u.GCFlat; break; } break; /* * GC Far */ case DBGCVAR_TYPE_GC_FAR: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; case DBGCVAR_TYPE_NUMBER: *pResult = *pArg1; pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number; break; default: rc = dbgcOpAddrFlat(pDbgc, pArg1, DBGCVAR_CAT_ANY, pResult); if (RT_FAILURE(rc)) return rc; rc = dbgcOpAddrFlat(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.GCFlat += pArg2->u.GCFlat; break; } break; /* * GC Phys */ case DBGCVAR_TYPE_GC_PHYS: switch (pArg2->enmType) { case DBGCVAR_TYPE_HC_FLAT: case DBGCVAR_TYPE_HC_PHYS: return VERR_DBGC_PARSE_INVALID_OPERATION; default: *pResult = *pArg1; rc = dbgcOpAddrPhys(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; if (Var.enmType != DBGCVAR_TYPE_GC_PHYS) return VERR_DBGC_PARSE_INVALID_OPERATION; pResult->u.GCPhys += Var.u.GCPhys; break; } break; /* * HC Flat */ case DBGCVAR_TYPE_HC_FLAT: *pResult = *pArg1; rc = dbgcOpAddrHost(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var2); if (RT_FAILURE(rc)) return rc; rc = dbgcOpAddrFlat(pDbgc, &Var2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat; break; /* * HC Phys */ case DBGCVAR_TYPE_HC_PHYS: *pResult = *pArg1; rc = dbgcOpAddrHostPhys(pDbgc, pArg2, DBGCVAR_CAT_ANY, &Var); if (RT_FAILURE(rc)) return rc; pResult->u.HCPhys += Var.u.HCPhys; break; /* * Numbers (see start of function) */ case DBGCVAR_TYPE_NUMBER: *pResult = *pArg1; switch (pArg2->enmType) { case DBGCVAR_TYPE_SYMBOL: rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var); if (RT_FAILURE(rc)) return rc; case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number += pArg2->u.u64Number; break; default: return VERR_DBGC_PARSE_INVALID_OPERATION; } break; default: return VERR_DBGC_PARSE_INVALID_OPERATION; } return VINF_SUCCESS; }