DBGFMem.cpp revision 4ae0468b4ae87a83e1a5f8c4f98ff78e840fde85
2N/A/* $Id$ */
2N/A/** @file
2N/A * DBGF - Debugger Facility, Memory Methods.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (C) 2007 Sun Microsystems, Inc.
2N/A *
2N/A * This file is part of VirtualBox Open Source Edition (OSE), as
2N/A * available from http://www.virtualbox.org. This file is free software;
2N/A * you can redistribute it and/or modify it under the terms of the GNU
2N/A * General Public License (GPL) as published by the Free Software
2N/A * Foundation, in version 2 as it comes in the "COPYING" file of the
2N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2N/A *
2N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
2N/A * Clara, CA 95054 USA or visit http://www.sun.com if you need
2N/A * additional information or have any questions.
2N/A */
2N/A
2N/A
2N/A/*******************************************************************************
2N/A* Header Files *
2N/A*******************************************************************************/
2N/A#define LOG_GROUP LOG_GROUP_DBGF
2N/A#include <VBox/dbgf.h>
2N/A#include <VBox/pgm.h>
2N/A#include "DBGFInternal.h"
2N/A#include <VBox/vm.h>
2N/A#include <VBox/err.h>
2N/A#include <VBox/log.h>
2N/A
2N/A
2N/A
2N/A/**
2N/A * Scan guest memory for an exact byte string.
2N/A *
2N/A * @returns VBox status code.
2N/A * @param pVM The VM handle.
2N/A * @param pAddress Where to store the mixed address.
2N/A * @param cbRange The number of bytes to scan.
2N/A * @param pabNeedle What to search for - exact search.
2N/A * @param cbNeedle Size of the search byte string.
2N/A * @param pHitAddress Where to put the address of the first hit.
2N/A */
2N/Astatic DECLCALLBACK(int) dbgfR3MemScan(PVM pVM, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle,
2N/A PDBGFADDRESS pHitAddress)
2N/A{
2N/A /*
2N/A * Validate the input we use, PGM does the rest.
2N/A */
2N/A if (!DBGFR3AddrIsValid(pVM, pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A if (!VALID_PTR(pHitAddress))
2N/A return VERR_INVALID_POINTER;
2N/A if (DBGFADDRESS_IS_HMA(pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A
2N/A /*
2N/A * Select DBGF worker by addressing mode.
2N/A */
2N/A int rc;
2N/A PGMMODE enmMode = PGMGetGuestMode(pVM);
2N/A if ( enmMode == PGMMODE_REAL
2N/A || enmMode == PGMMODE_PROTECTED
2N/A || DBGFADDRESS_IS_PHYS(pAddress)
2N/A )
2N/A {
2N/A RTGCPHYS PhysHit;
2N/A rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &PhysHit);
2N/A if (RT_SUCCESS(rc))
2N/A DBGFR3AddrFromPhys(pVM, pHitAddress, PhysHit);
2N/A }
2N/A else
2N/A {
2N/A#if GC_ARCH_BITS > 32
2N/A if ( ( pAddress->FlatPtr >= _4G
2N/A || pAddress->FlatPtr + cbRange > _4G)
2N/A && enmMode != PGMMODE_AMD64
2N/A && enmMode != PGMMODE_AMD64_NX)
2N/A return VERR_DBGF_MEM_NOT_FOUND;
2N/A#endif
2N/A RTGCUINTPTR GCPtrHit;
2N/A rc = PGMR3DbgScanVirtual(pVM, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &GCPtrHit);
2N/A if (RT_SUCCESS(rc))
2N/A DBGFR3AddrFromFlat(pVM, pHitAddress, GCPtrHit);
2N/A }
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A/**
2N/A * Scan guest memory for an exact byte string.
2N/A *
2N/A * @returns VBox status codes:
2N/A * @retval VINF_SUCCESS and *pGCPtrHit on success.
2N/A * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
2N/A * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
2N/A * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
2N/A *
2N/A * @param pVM The VM handle.
2N/A * @param pAddress Where to store the mixed address.
2N/A * @param cbRange The number of bytes to scan.
2N/A * @param pabNeedle What to search for - exact search.
2N/A * @param cbNeedle Size of the search byte string.
2N/A * @param pHitAddress Where to put the address of the first hit.
2N/A *
2N/A * @thread Any thread.
2N/A */
2N/AVMMR3DECL(int) DBGFR3MemScan(PVM pVM, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
2N/A{
2N/A PVMREQ pReq;
2N/A int rc = VMR3ReqCall(pVM, VMREQDEST_ALL, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3MemScan, 6,
2N/A pVM, pAddress, cbRange, pabNeedle, cbNeedle, pHitAddress);
2N/A if (VBOX_SUCCESS(rc))
2N/A rc = pReq->iStatus;
2N/A VMR3ReqFree(pReq);
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A/**
2N/A * Read guest memory.
2N/A *
2N/A * @returns VBox status code.
2N/A * @param pVM Pointer to the shared VM structure.
2N/A * @param pAddress Where to start reading.
2N/A * @param pvBuf Where to store the data we've read.
2N/A * @param cbRead The number of bytes to read.
2N/A */
2N/Astatic DECLCALLBACK(int) dbgfR3MemRead(PVM pVM, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
2N/A{
2N/A /*
2N/A * Validate the input we use, PGM does the rest.
2N/A */
2N/A if (!DBGFR3AddrIsValid(pVM, pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A if (!VALID_PTR(pvBuf))
2N/A return VERR_INVALID_POINTER;
2N/A if (DBGFADDRESS_IS_HMA(pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A
2N/A /*
2N/A * Select DBGF worker by addressing mode.
2N/A */
2N/A int rc;
2N/A PGMMODE enmMode = PGMGetGuestMode(pVM);
2N/A if ( enmMode == PGMMODE_REAL
2N/A || enmMode == PGMMODE_PROTECTED
2N/A || DBGFADDRESS_IS_PHYS(pAddress) )
2N/A rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead);
2N/A else
2N/A {
2N/A#if GC_ARCH_BITS > 32
2N/A if ( ( pAddress->FlatPtr >= _4G
2N/A || pAddress->FlatPtr + cbRead > _4G)
2N/A && enmMode != PGMMODE_AMD64
2N/A && enmMode != PGMMODE_AMD64_NX)
2N/A return VERR_PAGE_TABLE_NOT_PRESENT;
2N/A#endif
2N/A rc = PGMPhysSimpleReadGCPtr(pVM, pvBuf, pAddress->FlatPtr, cbRead);
2N/A }
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A/**
2N/A * Read guest memory.
2N/A *
2N/A * @returns VBox status code.
2N/A * @param pVM Pointer to the shared VM structure.
2N/A * @param pAddress Where to start reading.
2N/A * @param pvBuf Where to store the data we've read.
2N/A * @param cbRead The number of bytes to read.
2N/A */
2N/AVMMR3DECL(int) DBGFR3MemRead(PVM pVM, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
2N/A{
2N/A PVMREQ pReq;
2N/A int rc = VMR3ReqCallU(pVM->pUVM, VMREQDEST_ALL, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)dbgfR3MemRead, 4,
2N/A pVM, pAddress, pvBuf, cbRead);
2N/A if (VBOX_SUCCESS(rc))
2N/A rc = pReq->iStatus;
2N/A VMR3ReqFree(pReq);
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A/**
2N/A * Read a zero terminated string from guest memory.
2N/A *
2N/A * @returns VBox status code.
2N/A * @param pVM Pointer to the shared VM structure.
2N/A * @param pAddress Where to start reading.
2N/A * @param pszBuf Where to store the string.
2N/A * @param cchBuf The size of the buffer.
2N/A */
2N/Astatic DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
2N/A{
2N/A /*
2N/A * Validate the input we use, PGM does the rest.
2N/A */
2N/A if (!DBGFR3AddrIsValid(pVM, pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A if (!VALID_PTR(pszBuf))
2N/A return VERR_INVALID_POINTER;
2N/A if (DBGFADDRESS_IS_HMA(pAddress))
2N/A return VERR_INVALID_POINTER;
2N/A
2N/A /*
2N/A * Select DBGF worker by addressing mode.
2N/A */
2N/A int rc;
2N/A PGMMODE enmMode = PGMGetGuestMode(pVM);
2N/A if ( enmMode == PGMMODE_REAL
2N/A || enmMode == PGMMODE_PROTECTED
2N/A || DBGFADDRESS_IS_PHYS(pAddress) )
2N/A rc = PGMPhysSimpleReadGCPhys(pVM, pszBuf, pAddress->FlatPtr, cchBuf);
2N/A else
2N/A {
2N/A#if GC_ARCH_BITS > 32
2N/A if ( ( pAddress->FlatPtr >= _4G
2N/A || pAddress->FlatPtr + cchBuf > _4G)
2N/A && enmMode != PGMMODE_AMD64
2N/A && enmMode != PGMMODE_AMD64_NX)
2N/A return VERR_PAGE_TABLE_NOT_PRESENT;
2N/A#endif
2N/A rc = PGMPhysSimpleReadGCPtr(pVM, pszBuf, pAddress->FlatPtr, cchBuf);
2N/A }
2N/A
2N/A /*
2N/A * Make sure the result is terminated and that overflow is signaled.
2N/A */
2N/A if (!memchr(pszBuf, '\0', cchBuf))
2N/A {
2N/A pszBuf[cchBuf - 1] = '\0';
2N/A rc = VINF_BUFFER_OVERFLOW;
2N/A }
2N/A /*
2N/A * Handle partial reads (not perfect).
2N/A */
2N/A else if (RT_FAILURE(rc))
2N/A {
2N/A if (pszBuf[0])
2N/A rc = VINF_SUCCESS;
2N/A }
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A/**
2N/A * Read a zero terminated string from guest memory.
2N/A *
2N/A * @returns VBox status code.
2N/A * @param pVM Pointer to the shared VM structure.
2N/A * @param pAddress Where to start reading.
2N/A * @param pszBuf Where to store the string.
2N/A * @param cchBuf The size of the buffer.
2N/A */
2N/AVMMR3DECL(int) DBGFR3MemReadString(PVM pVM, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
2N/A{
2N/A /*
2N/A * Validate and zero output.
2N/A */
2N/A if (!VALID_PTR(pszBuf))
2N/A return VERR_INVALID_POINTER;
2N/A if (cchBuf <= 0)
2N/A return VERR_INVALID_PARAMETER;
2N/A memset(pszBuf, 0, cchBuf);
2N/A
2N/A /*
2N/A * Pass it on to the EMT.
2N/A */
2N/A PVMREQ pReq;
2N/A int rc = VMR3ReqCallU(pVM->pUVM, VMREQDEST_ALL, &pReq, RT_INDEFINITE_WAIT, 0, (PFNRT)dbgfR3MemReadString, 4,
2N/A pVM, pAddress, pszBuf, cchBuf);
2N/A if (VBOX_SUCCESS(rc))
2N/A rc = pReq->iStatus;
2N/A VMR3ReqFree(pReq);
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A