VirtualBox

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

最後變更 在這個檔案從23011是 23011,由 vboxsync 提交於 16 年 前

VMM,VMMDev: Some VMMR3ReqCall refactoring.

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

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