VirtualBox

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

Last change on this file since 22997 was 22890, checked in by vboxsync, 15 years ago

VM::cCPUs -> VM::cCpus so it matches all the other cCpus and aCpus members.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.6 KB
Line 
1/* $Id: DBGFMem.cpp 22890 2009-09-09 23:11:31Z 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 if (DBGFADDRESS_IS_PHYS(pAddress))
165 rc = VERR_INVALID_POINTER;
166 else
167 rc = MMR3HyperReadGCVirt(pVM, pvBuf, pAddress->FlatPtr, cbRead);
168 }
169 else
170 {
171 /*
172 * Select DBGF worker by addressing mode.
173 */
174 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
175 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
176 if ( enmMode == PGMMODE_REAL
177 || enmMode == PGMMODE_PROTECTED
178 || DBGFADDRESS_IS_PHYS(pAddress) )
179 rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, pAddress->FlatPtr, cbRead);
180 else
181 {
182#if GC_ARCH_BITS > 32
183 if ( ( pAddress->FlatPtr >= _4G
184 || pAddress->FlatPtr + cbRead > _4G)
185 && enmMode != PGMMODE_AMD64
186 && enmMode != PGMMODE_AMD64_NX)
187 return VERR_PAGE_TABLE_NOT_PRESENT;
188#endif
189 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvBuf, pAddress->FlatPtr, cbRead);
190 }
191 }
192 return rc;
193}
194
195
196/**
197 * Read guest memory.
198 *
199 * @returns VBox status code.
200 *
201 * @param pVM Pointer to the shared VM structure.
202 * @param idCpu The ID of the source CPU context (for the address).
203 * @param pAddress Where to start reading.
204 * @param pvBuf Where to store the data we've read.
205 * @param cbRead The number of bytes to read.
206 */
207VMMR3DECL(int) DBGFR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
208{
209 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
210 if ((pAddress->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0)
211 {
212 AssertCompile(sizeof(RTHCUINTPTR) <= sizeof(pAddress->FlatPtr));
213 return VMMR3ReadR0Stack(pVM, idCpu, (RTHCUINTPTR)pAddress->FlatPtr, pvBuf, cbRead);
214 }
215 else
216 {
217 PVMREQ pReq;
218 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
219 (PFNRT)dbgfR3MemRead, 5, pVM, idCpu, pAddress, pvBuf, cbRead);
220 if (RT_SUCCESS(rc))
221 rc = pReq->iStatus;
222 VMR3ReqFree(pReq);
223 return rc;
224 }
225}
226
227
228/**
229 * Read a zero terminated string from guest memory.
230 *
231 * @returns VBox status code.
232 *
233 * @param pVM Pointer to the shared VM structure.
234 * @param idCpu The ID of the source CPU context (for the address).
235 * @param pAddress Where to start reading.
236 * @param pszBuf Where to store the string.
237 * @param cchBuf The size of the buffer.
238 */
239static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
240{
241 /*
242 * Validate the input we use, PGM does the rest.
243 */
244 if (!DBGFR3AddrIsValid(pVM, pAddress))
245 return VERR_INVALID_POINTER;
246 if (!VALID_PTR(pszBuf))
247 return VERR_INVALID_POINTER;
248
249 /*
250 * Let dbgfR3MemRead do the job.
251 */
252 int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf);
253
254 /*
255 * Make sure the result is terminated and that overflow is signaled.
256 * This may look a bit reckless with the rc but, it should be fine.
257 */
258 if (!memchr(pszBuf, '\0', cchBuf))
259 {
260 pszBuf[cchBuf - 1] = '\0';
261 rc = VINF_BUFFER_OVERFLOW;
262 }
263 /*
264 * Handle partial reads (not perfect).
265 */
266 else if (RT_FAILURE(rc))
267 {
268 if (pszBuf[0])
269 rc = VINF_SUCCESS;
270 }
271
272 return rc;
273}
274
275
276/**
277 * Read a zero terminated string from guest memory.
278 *
279 * @returns VBox status code.
280 *
281 * @param pVM Pointer to the shared VM structure.
282 * @param idCpu The ID of the source CPU context (for the address).
283 * @param pAddress Where to start reading.
284 * @param pszBuf Where to store the string.
285 * @param cchBuf The size of the buffer.
286 */
287VMMR3DECL(int) DBGFR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
288{
289 /*
290 * Validate and zero output.
291 */
292 if (!VALID_PTR(pszBuf))
293 return VERR_INVALID_POINTER;
294 if (cchBuf <= 0)
295 return VERR_INVALID_PARAMETER;
296 memset(pszBuf, 0, cchBuf);
297 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
298
299 /*
300 * Pass it on to the EMT.
301 */
302 PVMREQ pReq;
303 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
304 (PFNRT)dbgfR3MemReadString, 5, pVM, idCpu, pAddress, pszBuf, cchBuf);
305 if (RT_SUCCESS(rc))
306 rc = pReq->iStatus;
307 VMR3ReqFree(pReq);
308
309 return rc;
310}
311
312
313/**
314 * Writes guest memory.
315 *
316 * @returns VBox status code.
317 *
318 * @param pVM Pointer to the shared VM structure.
319 * @param idCpu The ID of the target CPU context (for the address).
320 * @param pAddress Where to start writing.
321 * @param pvBuf The data to write.
322 * @param cbRead The number of bytes to write.
323 */
324static DECLCALLBACK(int) dbgfR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
325{
326 /*
327 * Validate the input we use, PGM does the rest.
328 */
329 if (!DBGFR3AddrIsValid(pVM, pAddress))
330 return VERR_INVALID_POINTER;
331 if (!VALID_PTR(pvBuf))
332 return VERR_INVALID_POINTER;
333
334 /*
335 * HMA is always special.
336 */
337 int rc;
338 if (DBGFADDRESS_IS_HMA(pAddress))
339 {
340 /** @todo write to HMA. */
341 rc = VERR_ACCESS_DENIED;
342 }
343 else
344 {
345 /*
346 * Select PGM function by addressing mode.
347 */
348 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
349 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
350 if ( enmMode == PGMMODE_REAL
351 || enmMode == PGMMODE_PROTECTED
352 || DBGFADDRESS_IS_PHYS(pAddress) )
353 rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite);
354 else
355 {
356#if GC_ARCH_BITS > 32
357 if ( ( pAddress->FlatPtr >= _4G
358 || pAddress->FlatPtr + cbWrite > _4G)
359 && enmMode != PGMMODE_AMD64
360 && enmMode != PGMMODE_AMD64_NX)
361 return VERR_PAGE_TABLE_NOT_PRESENT;
362#endif
363 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite);
364 }
365 }
366 return rc;
367}
368
369
370/**
371 * Read guest memory.
372 *
373 * @returns VBox status code.
374 *
375 * @param pVM Pointer to the shared VM structure.
376 * @param idCpu The ID of the target CPU context (for the address).
377 * @param pAddress Where to start writing.
378 * @param pvBuf The data to write.
379 * @param cbRead The number of bytes to write.
380 */
381VMMR3DECL(int) DBGFR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
382{
383 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
384
385 PVMREQ pReq;
386 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
387 (PFNRT)dbgfR3MemWrite, 5, pVM, idCpu, pAddress, pvBuf, cbWrite);
388 if (RT_SUCCESS(rc))
389 rc = pReq->iStatus;
390 VMR3ReqFree(pReq);
391
392 return rc;
393}
394
395
396/**
397 * Worker for DBGFR3SelQueryInfo that calls into SELM.
398 */
399static DECLCALLBACK(int) dbgfR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
400{
401 /*
402 * Make the query.
403 */
404 int rc;
405 if (!(fFlags & DBGFSELQI_FLAGS_DT_SHADOW))
406 {
407 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
408 VMCPU_ASSERT_EMT(pVCpu);
409 rc = SELMR3GetSelectorInfo(pVM, pVCpu, Sel, pSelInfo);
410
411 /*
412 * 64-bit mode HACKS for making data and stack selectors wide open when
413 * queried. This is voodoo magic.
414 */
415 if (fFlags & DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)
416 {
417 /* Expand 64-bit data and stack selectors. The check is a bit bogus... */
418 if ( RT_SUCCESS(rc)
419 && (pSelInfo->fFlags & ( DBGFSELINFO_FLAGS_LONG_MODE | DBGFSELINFO_FLAGS_REAL_MODE | DBGFSELINFO_FLAGS_PROT_MODE
420 | DBGFSELINFO_FLAGS_GATE | DBGFSELINFO_FLAGS_HYPER
421 | DBGFSELINFO_FLAGS_INVALID | DBGFSELINFO_FLAGS_NOT_PRESENT))
422 == DBGFSELINFO_FLAGS_LONG_MODE
423 && pSelInfo->cbLimit != ~(RTGCPTR)0
424 && CPUMIsGuestIn64BitCode(pVCpu, CPUMGetGuestCtxCore(pVCpu)) )
425 {
426 pSelInfo->GCPtrBase = 0;
427 pSelInfo->cbLimit = ~(RTGCPTR)0;
428 }
429 else if ( Sel == 0
430 && CPUMIsGuestIn64BitCode(pVCpu, CPUMGetGuestCtxCore(pVCpu)))
431 {
432 pSelInfo->GCPtrBase = 0;
433 pSelInfo->cbLimit = ~(RTGCPTR)0;
434 pSelInfo->Sel = 0;
435 pSelInfo->SelGate = 0;
436 pSelInfo->fFlags = DBGFSELINFO_FLAGS_LONG_MODE;
437 pSelInfo->u.Raw64.Gen.u1Present = 1;
438 pSelInfo->u.Raw64.Gen.u1Long = 1;
439 pSelInfo->u.Raw64.Gen.u1DescType = 1;
440 rc = VINF_SUCCESS;
441 }
442 }
443 }
444 else
445 {
446 if (HWACCMIsEnabled(pVM))
447 rc = VERR_INVALID_STATE;
448 else
449 rc = SELMR3GetShadowSelectorInfo(pVM, Sel, pSelInfo);
450 }
451 return rc;
452}
453
454
455/**
456 * Gets information about a selector.
457 *
458 * Intended for the debugger mostly and will prefer the guest
459 * descriptor tables over the shadow ones.
460 *
461 * @returns VBox status code, the following are the common ones.
462 * @retval VINF_SUCCESS on success.
463 * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the
464 * descriptor table.
465 * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This
466 * is not returned if the selector itself isn't present, you have to
467 * check that for yourself (see DBGFSELINFO::fFlags).
468 * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the
469 * pagetable or page backing the selector table wasn't present.
470 *
471 * @param pVM VM handle.
472 * @param idCpu The ID of the virtual CPU context.
473 * @param Sel The selector to get info about.
474 * @param fFlags Flags, see DBGFQSEL_FLAGS_*.
475 * @param pSelInfo Where to store the information. This will always be
476 * updated.
477 *
478 * @remarks This is a wrapper around SELMR3GetSelectorInfo and
479 * SELMR3GetShadowSelectorInfo.
480 */
481VMMR3DECL(int) DBGFR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
482{
483 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
484 AssertReturn(!(fFlags & ~(DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)), VERR_INVALID_PARAMETER);
485 AssertReturn( (fFlags & (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE))
486 != (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE), VERR_INVALID_PARAMETER);
487
488 /* Clear the return data here on this thread. */
489 memset(pSelInfo, 0, sizeof(*pSelInfo));
490
491 /*
492 * Dispatch the request to a worker running on the target CPU.
493 */
494 PVMREQ pReq;
495 int rc = VMR3ReqCallU(pVM->pUVM, idCpu, &pReq, RT_INDEFINITE_WAIT, 0,
496 (PFNRT)dbgfR3SelQueryInfo, 5, pVM, idCpu, Sel, fFlags, pSelInfo);
497 if (RT_SUCCESS(rc))
498 rc = pReq->iStatus;
499 VMR3ReqFree(pReq);
500
501 return rc;
502}
503
504
505/**
506 * Validates a CS selector.
507 *
508 * @returns VBox status code.
509 * @param pSelInfo Pointer to the selector information for the CS selector.
510 * @param SelCPL The selector defining the CPL (SS).
511 */
512VMMDECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL)
513{
514 /*
515 * Check if present.
516 */
517 if (pSelInfo->u.Raw.Gen.u1Present)
518 {
519 /*
520 * Type check.
521 */
522 if ( pSelInfo->u.Raw.Gen.u1DescType == 1
523 && (pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
524 {
525 /*
526 * Check level.
527 */
528 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
529 if ( !(pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
530 ? uLevel <= pSelInfo->u.Raw.Gen.u2Dpl
531 : uLevel >= pSelInfo->u.Raw.Gen.u2Dpl /* hope I got this right now... */
532 )
533 return VINF_SUCCESS;
534 return VERR_INVALID_RPL;
535 }
536 return VERR_NOT_CODE_SELECTOR;
537 }
538 return VERR_SELECTOR_NOT_PRESENT;
539}
540
541
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