VirtualBox

source: vbox/trunk/src/VBox/VMM/DBGFMem.cpp@ 20374

Last change on this file since 20374 was 19576, checked in by vboxsync, 16 years ago

Compile fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.7 KB
Line 
1/* $Id: DBGFMem.cpp 19576 2009-05-11 12:43:48Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Memory Methods.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DBGF
27#include <VBox/dbgf.h>
28#include <VBox/pgm.h>
29#include <VBox/selm.h>
30#include <VBox/hwaccm.h>
31#include "DBGFInternal.h"
32#include <VBox/vm.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <VBox/mm.h>
36
37
38
39/**
40 * Scan guest memory for an exact byte string.
41 *
42 * @returns VBox status code.
43 * @param pVM The VM handle.
44 * @param idCpu The ID of the CPU context to search in.
45 * @param pAddress Where to store the mixed address.
46 * @param pcbRange The number of bytes to scan. Passed as a pointer because
47 * it may be 64-bit.
48 * @param pabNeedle What to search for - exact search.
49 * @param cbNeedle Size of the search byte string.
50 * @param pHitAddress Where to put the address of the first hit.
51 */
52static DECLCALLBACK(int) dbgfR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange,
53 const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
54{
55 Assert(idCpu == VMMGetCpuId(pVM));
56
57 /*
58 * Validate the input we use, PGM does the rest.
59 */
60 RTGCUINTPTR cbRange = *pcbRange;
61 if (!DBGFR3AddrIsValid(pVM, pAddress))
62 return VERR_INVALID_POINTER;
63 if (!VALID_PTR(pHitAddress))
64 return VERR_INVALID_POINTER;
65 if (DBGFADDRESS_IS_HMA(pAddress))
66 return VERR_INVALID_POINTER;
67
68 /*
69 * Select DBGF worker by addressing mode.
70 */
71 int rc;
72 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
73 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
74 if ( enmMode == PGMMODE_REAL
75 || enmMode == PGMMODE_PROTECTED
76 || DBGFADDRESS_IS_PHYS(pAddress)
77 )
78 {
79 RTGCPHYS PhysHit;
80 rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &PhysHit);
81 if (RT_SUCCESS(rc))
82 DBGFR3AddrFromPhys(pVM, pHitAddress, PhysHit);
83 }
84 else
85 {
86#if GC_ARCH_BITS > 32
87 if ( ( pAddress->FlatPtr >= _4G
88 || pAddress->FlatPtr + cbRange > _4G)
89 && enmMode != PGMMODE_AMD64
90 && enmMode != PGMMODE_AMD64_NX)
91 return VERR_DBGF_MEM_NOT_FOUND;
92#endif
93 RTGCUINTPTR GCPtrHit;
94 rc = PGMR3DbgScanVirtual(pVM, pVCpu, pAddress->FlatPtr, cbRange, pabNeedle, cbNeedle, &GCPtrHit);
95 if (RT_SUCCESS(rc))
96 DBGFR3AddrFromFlat(pVM, pHitAddress, GCPtrHit);
97 }
98
99 return rc;
100}
101
102
103/**
104 * Scan guest memory for an exact byte string.
105 *
106 * @returns VBox status codes:
107 * @retval VINF_SUCCESS and *pGCPtrHit on success.
108 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
109 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
110 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
111 *
112 * @param pVM The VM handle.
113 * @param idCpu The ID of the CPU context to search in.
114 * @param pAddress Where to store the mixed address.
115 * @param cbRange The number of bytes to scan.
116 * @param pabNeedle What to search for - exact search.
117 * @param cbNeedle Size of the search byte string.
118 * @param pHitAddress Where to put the address of the first hit.
119 *
120 * @thread Any thread.
121 */
122VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
123{
124 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_PARAMETER);
125
126 PVMREQ pReq;
127 int rc = VMR3ReqCall(pVM, idCpu, &pReq, RT_INDEFINITE_WAIT,
128 (PFNRT)dbgfR3MemScan, 7, pVM, idCpu, pAddress, &cbRange, pabNeedle, cbNeedle, pHitAddress);
129 if (RT_SUCCESS(rc))
130 rc = pReq->iStatus;
131 VMR3ReqFree(pReq);
132
133 return rc;
134}
135
136
137/**
138 * Read guest memory.
139 *
140 * @returns VBox status code.
141 * @param pVM Pointer to the shared VM structure.
142 * @param pAddress Where to start reading.
143 * @param pvBuf Where to store the data we've read.
144 * @param cbRead The number of bytes to read.
145 */
146static DECLCALLBACK(int) dbgfR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
147{
148 Assert(idCpu == VMMGetCpuId(pVM));
149
150 /*
151 * Validate the input we use, PGM does the rest.
152 */
153 if (!DBGFR3AddrIsValid(pVM, pAddress))
154 return VERR_INVALID_POINTER;
155 if (!VALID_PTR(pvBuf))
156 return VERR_INVALID_POINTER;
157
158 /*
159 * HMA is special
160 */
161 int rc;
162 if (DBGFADDRESS_IS_HMA(pAddress))
163 {
164 rc = VERR_INVALID_POINTER;
165 }
166 else
167 {
168 /*
169 * Select DBGF worker by addressing mode.
170 */
171 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
172 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
173 if ( enmMode == PGMMODE_REAL
174 || enmMode == PGMMODE_PROTECTED
175 || DBGFADDRESS_IS_PHYS(pAddress) )
176 rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead);
177 else
178 {
179#if GC_ARCH_BITS > 32
180 if ( ( pAddress->FlatPtr >= _4G
181 || pAddress->FlatPtr + cbRead > _4G)
182 && enmMode != PGMMODE_AMD64
183 && enmMode != PGMMODE_AMD64_NX)
184 return VERR_PAGE_TABLE_NOT_PRESENT;
185#endif
186 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvBuf, pAddress->FlatPtr, cbRead);
187 }
188 }
189 return rc;
190}
191
192
193/**
194 * Read guest memory.
195 *
196 * @returns VBox status code.
197 *
198 * @param pVM Pointer to the shared VM structure.
199 * @param idCpu The ID of the source CPU context (for the address).
200 * @param pAddress Where to start reading.
201 * @param pvBuf Where to store the data we've read.
202 * @param cbRead The number of bytes to read.
203 */
204VMMR3DECL(int) DBGFR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
205{
206 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_PARAMETER);
207 if ((pAddress->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0)
208 {
209 AssertCompile(sizeof(RTHCUINTPTR) <= sizeof(pAddress->FlatPtr));
210 return VMMR3ReadR0Stack(pVM, idCpu, (RTHCUINTPTR)pAddress->FlatPtr, pvBuf, cbRead);
211 }
212 else
213 {
214 PVMREQ pReq;
215 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
216 (PFNRT)dbgfR3MemRead, 5, pVM, idCpu, pAddress, pvBuf, cbRead);
217 if (RT_SUCCESS(rc))
218 rc = pReq->iStatus;
219 VMR3ReqFree(pReq);
220 return rc;
221 }
222}
223
224
225/**
226 * Read a zero terminated string from guest memory.
227 *
228 * @returns VBox status code.
229 *
230 * @param pVM Pointer to the shared VM structure.
231 * @param idCpu The ID of the source CPU context (for the address).
232 * @param pAddress Where to start reading.
233 * @param pszBuf Where to store the string.
234 * @param cchBuf The size of the buffer.
235 */
236static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
237{
238 /*
239 * Validate the input we use, PGM does the rest.
240 */
241 if (!DBGFR3AddrIsValid(pVM, pAddress))
242 return VERR_INVALID_POINTER;
243 if (!VALID_PTR(pszBuf))
244 return VERR_INVALID_POINTER;
245
246 /*
247 * Let dbgfR3MemRead do the job.
248 */
249 int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf);
250
251 /*
252 * Make sure the result is terminated and that overflow is signaled.
253 * This may look a bit reckless with the rc but, it should be fine.
254 */
255 if (!memchr(pszBuf, '\0', cchBuf))
256 {
257 pszBuf[cchBuf - 1] = '\0';
258 rc = VINF_BUFFER_OVERFLOW;
259 }
260 /*
261 * Handle partial reads (not perfect).
262 */
263 else if (RT_FAILURE(rc))
264 {
265 if (pszBuf[0])
266 rc = VINF_SUCCESS;
267 }
268
269 return rc;
270}
271
272
273/**
274 * Read a zero terminated string from guest memory.
275 *
276 * @returns VBox status code.
277 *
278 * @param pVM Pointer to the shared VM structure.
279 * @param idCpu The ID of the source CPU context (for the address).
280 * @param pAddress Where to start reading.
281 * @param pszBuf Where to store the string.
282 * @param cchBuf The size of the buffer.
283 */
284VMMR3DECL(int) DBGFR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
285{
286 /*
287 * Validate and zero output.
288 */
289 if (!VALID_PTR(pszBuf))
290 return VERR_INVALID_POINTER;
291 if (cchBuf <= 0)
292 return VERR_INVALID_PARAMETER;
293 memset(pszBuf, 0, cchBuf);
294 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_PARAMETER);
295
296 /*
297 * Pass it on to the EMT.
298 */
299 PVMREQ pReq;
300 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
301 (PFNRT)dbgfR3MemReadString, 5, pVM, idCpu, pAddress, pszBuf, cchBuf);
302 if (RT_SUCCESS(rc))
303 rc = pReq->iStatus;
304 VMR3ReqFree(pReq);
305
306 return rc;
307}
308
309
310/**
311 * Writes guest memory.
312 *
313 * @returns VBox status code.
314 *
315 * @param pVM Pointer to the shared VM structure.
316 * @param idCpu The ID of the target CPU context (for the address).
317 * @param pAddress Where to start writing.
318 * @param pvBuf The data to write.
319 * @param cbRead The number of bytes to write.
320 */
321static DECLCALLBACK(int) dbgfR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
322{
323 /*
324 * Validate the input we use, PGM does the rest.
325 */
326 if (!DBGFR3AddrIsValid(pVM, pAddress))
327 return VERR_INVALID_POINTER;
328 if (!VALID_PTR(pvBuf))
329 return VERR_INVALID_POINTER;
330
331 /*
332 * HMA is always special.
333 */
334 int rc;
335 if (DBGFADDRESS_IS_HMA(pAddress))
336 {
337 /** @todo write to HMA. */
338 rc = VERR_ACCESS_DENIED;
339 }
340 else
341 {
342 /*
343 * Select PGM function by addressing mode.
344 */
345 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
346 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
347 if ( enmMode == PGMMODE_REAL
348 || enmMode == PGMMODE_PROTECTED
349 || DBGFADDRESS_IS_PHYS(pAddress) )
350 rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite);
351 else
352 {
353#if GC_ARCH_BITS > 32
354 if ( ( pAddress->FlatPtr >= _4G
355 || pAddress->FlatPtr + cbWrite > _4G)
356 && enmMode != PGMMODE_AMD64
357 && enmMode != PGMMODE_AMD64_NX)
358 return VERR_PAGE_TABLE_NOT_PRESENT;
359#endif
360 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite);
361 }
362 }
363 return rc;
364}
365
366
367/**
368 * Read guest memory.
369 *
370 * @returns VBox status code.
371 *
372 * @param pVM Pointer to the shared VM structure.
373 * @param idCpu The ID of the target CPU context (for the address).
374 * @param pAddress Where to start writing.
375 * @param pvBuf The data to write.
376 * @param cbRead The number of bytes to write.
377 */
378VMMR3DECL(int) DBGFR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
379{
380 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_PARAMETER);
381
382 PVMREQ pReq;
383 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
384 (PFNRT)dbgfR3MemWrite, 5, pVM, idCpu, pAddress, pvBuf, cbWrite);
385 if (RT_SUCCESS(rc))
386 rc = pReq->iStatus;
387 VMR3ReqFree(pReq);
388
389 return rc;
390}
391
392
393/**
394 * Worker for DBGFR3SelQueryInfo that calls into SELM.
395 */
396static DECLCALLBACK(int) dbgfR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
397{
398 /*
399 * Make the query.
400 */
401 int rc;
402 if (!(fFlags & DBGFSELQI_FLAGS_DT_GUEST))
403 {
404 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
405 VMCPU_ASSERT_EMT(pVCpu);
406 rc = SELMR3GetSelectorInfo(pVM, pVCpu, Sel, pSelInfo);
407 }
408 else
409 {
410 if (HWACCMIsEnabled(pVM))
411 rc = VERR_INVALID_STATE;
412 else
413 rc = SELMR3GetShadowSelectorInfo(pVM, Sel, pSelInfo);
414 }
415 return rc;
416}
417
418
419/**
420 * Gets information about a selector.
421 *
422 * Intended for the debugger mostly and will prefer the guest
423 * descriptor tables over the shadow ones.
424 *
425 * @returns VBox status code, the following are the common ones.
426 * @retval VINF_SUCCESS on success.
427 * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the
428 * descriptor table.
429 * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This
430 * is not returned if the selector itself isn't present, you have to
431 * check that for yourself (see DBGFSELINFO::fFlags).
432 * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the
433 * pagetable or page backing the selector table wasn't present.
434 *
435 * @param pVM VM handle.
436 * @param idCpu The ID of the virtual CPU context.
437 * @param Sel The selector to get info about.
438 * @param fFlags Flags, see DBGFQSEL_FLAGS_*.
439 * @param pSelInfo Where to store the information. This will always be
440 * updated.
441 *
442 * @remarks This is a wrapper around SELMR3GetSelectorInfo and
443 * SELMR3GetShadowSelectorInfo.
444 */
445VMMR3DECL(int) DBGFR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
446{
447 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_PARAMETER);
448 AssertReturn(!(fFlags & ~(DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_SHADOW)), VERR_INVALID_PARAMETER);
449
450 /* Clear the return data here on this thread. */
451 memset(pSelInfo, 0, sizeof(*pSelInfo));
452
453 /*
454 * Dispatch the request to a worker running on the target CPU.
455 */
456 PVMREQ pReq;
457 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
458 (PFNRT)dbgfR3SelQueryInfo, 5, pVM, idCpu, Sel, fFlags, pSelInfo);
459 if (RT_SUCCESS(rc))
460 rc = pReq->iStatus;
461 VMR3ReqFree(pReq);
462
463 return rc;
464}
465
466
467/**
468 * Validates a CS selector.
469 *
470 * @returns VBox status code.
471 * @param pSelInfo Pointer to the selector information for the CS selector.
472 * @param SelCPL The selector defining the CPL (SS).
473 */
474VMMDECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL)
475{
476 /*
477 * Check if present.
478 */
479 if (pSelInfo->u.Raw.Gen.u1Present)
480 {
481 /*
482 * Type check.
483 */
484 if ( pSelInfo->u.Raw.Gen.u1DescType == 1
485 && (pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
486 {
487 /*
488 * Check level.
489 */
490 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
491 if ( !(pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
492 ? uLevel <= pSelInfo->u.Raw.Gen.u2Dpl
493 : uLevel >= pSelInfo->u.Raw.Gen.u2Dpl /* hope I got this right now... */
494 )
495 return VINF_SUCCESS;
496 return VERR_INVALID_RPL;
497 }
498 return VERR_NOT_CODE_SELECTOR;
499 }
500 return VERR_SELECTOR_NOT_PRESENT;
501}
502
503
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette