VirtualBox

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

Last change on this file since 30656 was 30320, checked in by vboxsync, 14 years ago

*: Replaced memchr(psz, '\0', cb) with RTStrEnd(psz, cb) and worked around memchr( RTSTR_MAX) issue in RTStrEnd. Here (linux.amd64 / glibc-2.10.1-r1) memchr fails for cb > ~(size_t)11. Since RTSTR_MAX is ~(size_t)0, this behavior breaks several IPRT string APIs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: DBGFMem.cpp 30320 2010-06-21 08:35:09Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Memory Methods.
4 */
5
6/*
7 * Copyright (C) 2007 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/dbgf.h>
24#include <VBox/pgm.h>
25#include <VBox/selm.h>
26#include <VBox/hwaccm.h>
27#include "DBGFInternal.h"
28#include <VBox/vm.h>
29#include <VBox/err.h>
30#include <VBox/log.h>
31#include <VBox/mm.h>
32
33
34
35/**
36 * Scan guest memory for an exact byte string.
37 *
38 * @returns VBox status code.
39 * @param pVM The VM handle.
40 * @param idCpu The ID of the CPU context to search in.
41 * @param pAddress Where to store the mixed address.
42 * @param puAlign The alignment restriction imposed on the search result.
43 * @param pcbRange The number of bytes to scan. Passed as a pointer because
44 * it may be 64-bit.
45 * @param pabNeedle What to search for - exact search.
46 * @param cbNeedle Size of the search byte string.
47 * @param pHitAddress Where to put the address of the first hit.
48 */
49static DECLCALLBACK(int) dbgfR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PCRTGCUINTPTR pcbRange, RTGCUINTPTR *puAlign,
50 const uint8_t *pabNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
51{
52 Assert(idCpu == VMMGetCpuId(pVM));
53
54 /*
55 * Validate the input we use, PGM does the rest.
56 */
57 RTGCUINTPTR cbRange = *pcbRange;
58 if (!DBGFR3AddrIsValid(pVM, pAddress))
59 return VERR_INVALID_POINTER;
60 if (!VALID_PTR(pHitAddress))
61 return VERR_INVALID_POINTER;
62 if (DBGFADDRESS_IS_HMA(pAddress))
63 return VERR_INVALID_POINTER;
64
65 /*
66 * Select DBGF worker by addressing mode.
67 */
68 int rc;
69 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
70 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
71 if ( enmMode == PGMMODE_REAL
72 || enmMode == PGMMODE_PROTECTED
73 || DBGFADDRESS_IS_PHYS(pAddress)
74 )
75 {
76 RTGCPHYS GCPhysAlign = *puAlign;
77 if (GCPhysAlign != *puAlign)
78 return VERR_OUT_OF_RANGE;
79 RTGCPHYS PhysHit;
80 rc = PGMR3DbgScanPhysical(pVM, pAddress->FlatPtr, cbRange, GCPhysAlign, 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, *puAlign, 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 uAlign The alignment restriction imposed on the result.
117 * Usually set to 1.
118 * @param pvNeedle What to search for - exact search.
119 * @param cbNeedle Size of the search byte string.
120 * @param pHitAddress Where to put the address of the first hit.
121 *
122 * @thread Any thread.
123 */
124VMMR3DECL(int) DBGFR3MemScan(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign,
125 const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress)
126{
127 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
128 return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3MemScan, 8,
129 pVM, idCpu, pAddress, &cbRange, &uAlign, pvNeedle, cbNeedle, pHitAddress);
130
131}
132
133
134/**
135 * Read guest memory.
136 *
137 * @returns VBox status code.
138 * @param pVM Pointer to the shared VM structure.
139 * @param pAddress Where to start reading.
140 * @param pvBuf Where to store the data we've read.
141 * @param cbRead The number of bytes to read.
142 */
143static DECLCALLBACK(int) dbgfR3MemRead(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead)
144{
145 Assert(idCpu == VMMGetCpuId(pVM));
146
147 /*
148 * Validate the input we use, PGM does the rest.
149 */
150 if (!DBGFR3AddrIsValid(pVM, pAddress))
151 return VERR_INVALID_POINTER;
152 if (!VALID_PTR(pvBuf))
153 return VERR_INVALID_POINTER;
154
155 /*
156 * HMA is special
157 */
158 int rc;
159 if (DBGFADDRESS_IS_HMA(pAddress))
160 {
161 if (DBGFADDRESS_IS_PHYS(pAddress))
162 rc = VERR_INVALID_POINTER;
163 else
164 rc = MMR3HyperReadGCVirt(pVM, pvBuf, pAddress->FlatPtr, cbRead);
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 return VMR3ReqCallWaitU(pVM->pUVM, idCpu, (PFNRT)dbgfR3MemRead, 5, pVM, idCpu, pAddress, pvBuf, cbRead);
213}
214
215
216/**
217 * Read a zero terminated string from guest memory.
218 *
219 * @returns VBox status code.
220 *
221 * @param pVM Pointer to the shared VM structure.
222 * @param idCpu The ID of the source CPU context (for the address).
223 * @param pAddress Where to start reading.
224 * @param pszBuf Where to store the string.
225 * @param cchBuf The size of the buffer.
226 */
227static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
228{
229 /*
230 * Validate the input we use, PGM does the rest.
231 */
232 if (!DBGFR3AddrIsValid(pVM, pAddress))
233 return VERR_INVALID_POINTER;
234 if (!VALID_PTR(pszBuf))
235 return VERR_INVALID_POINTER;
236
237 /*
238 * Let dbgfR3MemRead do the job.
239 */
240 int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf);
241
242 /*
243 * Make sure the result is terminated and that overflow is signaled.
244 * This may look a bit reckless with the rc but, it should be fine.
245 */
246 if (!RTStrEnd(pszBuf, cchBuf))
247 {
248 pszBuf[cchBuf - 1] = '\0';
249 rc = VINF_BUFFER_OVERFLOW;
250 }
251 /*
252 * Handle partial reads (not perfect).
253 */
254 else if (RT_FAILURE(rc))
255 {
256 if (pszBuf[0])
257 rc = VINF_SUCCESS;
258 }
259
260 return rc;
261}
262
263
264/**
265 * Read a zero terminated string from guest memory.
266 *
267 * @returns VBox status code.
268 *
269 * @param pVM Pointer to the shared VM structure.
270 * @param idCpu The ID of the source CPU context (for the address).
271 * @param pAddress Where to start reading.
272 * @param pszBuf Where to store the string.
273 * @param cchBuf The size of the buffer.
274 */
275VMMR3DECL(int) DBGFR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
276{
277 /*
278 * Validate and zero output.
279 */
280 if (!VALID_PTR(pszBuf))
281 return VERR_INVALID_POINTER;
282 if (cchBuf <= 0)
283 return VERR_INVALID_PARAMETER;
284 memset(pszBuf, 0, cchBuf);
285 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
286
287 /*
288 * Pass it on to the EMT.
289 */
290 return VMR3ReqCallWaitU(pVM->pUVM, idCpu, (PFNRT)dbgfR3MemReadString, 5, pVM, idCpu, pAddress, pszBuf, cchBuf);
291}
292
293
294/**
295 * Writes guest memory.
296 *
297 * @returns VBox status code.
298 *
299 * @param pVM Pointer to the shared VM structure.
300 * @param idCpu The ID of the target CPU context (for the address).
301 * @param pAddress Where to start writing.
302 * @param pvBuf The data to write.
303 * @param cbWrite The number of bytes to write.
304 */
305static DECLCALLBACK(int) dbgfR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
306{
307 /*
308 * Validate the input we use, PGM does the rest.
309 */
310 if (!DBGFR3AddrIsValid(pVM, pAddress))
311 return VERR_INVALID_POINTER;
312 if (!VALID_PTR(pvBuf))
313 return VERR_INVALID_POINTER;
314
315 /*
316 * HMA is always special.
317 */
318 int rc;
319 if (DBGFADDRESS_IS_HMA(pAddress))
320 {
321 /** @todo write to HMA. */
322 rc = VERR_ACCESS_DENIED;
323 }
324 else
325 {
326 /*
327 * Select PGM function by addressing mode.
328 */
329 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
330 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
331 if ( enmMode == PGMMODE_REAL
332 || enmMode == PGMMODE_PROTECTED
333 || DBGFADDRESS_IS_PHYS(pAddress) )
334 rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite);
335 else
336 {
337#if GC_ARCH_BITS > 32
338 if ( ( pAddress->FlatPtr >= _4G
339 || pAddress->FlatPtr + cbWrite > _4G)
340 && enmMode != PGMMODE_AMD64
341 && enmMode != PGMMODE_AMD64_NX)
342 return VERR_PAGE_TABLE_NOT_PRESENT;
343#endif
344 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite);
345 }
346 }
347 return rc;
348}
349
350
351/**
352 * Read guest memory.
353 *
354 * @returns VBox status code.
355 *
356 * @param pVM Pointer to the shared VM structure.
357 * @param idCpu The ID of the target CPU context (for the address).
358 * @param pAddress Where to start writing.
359 * @param pvBuf The data to write.
360 * @param cbRead The number of bytes to write.
361 */
362VMMR3DECL(int) DBGFR3MemWrite(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite)
363{
364 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
365 return VMR3ReqCallWaitU(pVM->pUVM, idCpu, (PFNRT)dbgfR3MemWrite, 5, pVM, idCpu, pAddress, pvBuf, cbWrite);
366}
367
368
369/**
370 * Worker for DBGFR3SelQueryInfo that calls into SELM.
371 */
372static DECLCALLBACK(int) dbgfR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
373{
374 /*
375 * Make the query.
376 */
377 int rc;
378 if (!(fFlags & DBGFSELQI_FLAGS_DT_SHADOW))
379 {
380 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
381 VMCPU_ASSERT_EMT(pVCpu);
382 rc = SELMR3GetSelectorInfo(pVM, pVCpu, Sel, pSelInfo);
383
384 /*
385 * 64-bit mode HACKS for making data and stack selectors wide open when
386 * queried. This is voodoo magic.
387 */
388 if (fFlags & DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)
389 {
390 /* Expand 64-bit data and stack selectors. The check is a bit bogus... */
391 if ( RT_SUCCESS(rc)
392 && (pSelInfo->fFlags & ( DBGFSELINFO_FLAGS_LONG_MODE | DBGFSELINFO_FLAGS_REAL_MODE | DBGFSELINFO_FLAGS_PROT_MODE
393 | DBGFSELINFO_FLAGS_GATE | DBGFSELINFO_FLAGS_HYPER
394 | DBGFSELINFO_FLAGS_INVALID | DBGFSELINFO_FLAGS_NOT_PRESENT))
395 == DBGFSELINFO_FLAGS_LONG_MODE
396 && pSelInfo->cbLimit != ~(RTGCPTR)0
397 && CPUMIsGuestIn64BitCode(pVCpu, CPUMGetGuestCtxCore(pVCpu)) )
398 {
399 pSelInfo->GCPtrBase = 0;
400 pSelInfo->cbLimit = ~(RTGCPTR)0;
401 }
402 else if ( Sel == 0
403 && CPUMIsGuestIn64BitCode(pVCpu, CPUMGetGuestCtxCore(pVCpu)))
404 {
405 pSelInfo->GCPtrBase = 0;
406 pSelInfo->cbLimit = ~(RTGCPTR)0;
407 pSelInfo->Sel = 0;
408 pSelInfo->SelGate = 0;
409 pSelInfo->fFlags = DBGFSELINFO_FLAGS_LONG_MODE;
410 pSelInfo->u.Raw64.Gen.u1Present = 1;
411 pSelInfo->u.Raw64.Gen.u1Long = 1;
412 pSelInfo->u.Raw64.Gen.u1DescType = 1;
413 rc = VINF_SUCCESS;
414 }
415 }
416 }
417 else
418 {
419 if (HWACCMIsEnabled(pVM))
420 rc = VERR_INVALID_STATE;
421 else
422 rc = SELMR3GetShadowSelectorInfo(pVM, Sel, pSelInfo);
423 }
424 return rc;
425}
426
427
428/**
429 * Gets information about a selector.
430 *
431 * Intended for the debugger mostly and will prefer the guest
432 * descriptor tables over the shadow ones.
433 *
434 * @returns VBox status code, the following are the common ones.
435 * @retval VINF_SUCCESS on success.
436 * @retval VERR_INVALID_SELECTOR if the selector isn't fully inside the
437 * descriptor table.
438 * @retval VERR_SELECTOR_NOT_PRESENT if the LDT is invalid or not present. This
439 * is not returned if the selector itself isn't present, you have to
440 * check that for yourself (see DBGFSELINFO::fFlags).
441 * @retval VERR_PAGE_TABLE_NOT_PRESENT or VERR_PAGE_NOT_PRESENT if the
442 * pagetable or page backing the selector table wasn't present.
443 *
444 * @param pVM VM handle.
445 * @param idCpu The ID of the virtual CPU context.
446 * @param Sel The selector to get info about.
447 * @param fFlags Flags, see DBGFQSEL_FLAGS_*.
448 * @param pSelInfo Where to store the information. This will always be
449 * updated.
450 *
451 * @remarks This is a wrapper around SELMR3GetSelectorInfo and
452 * SELMR3GetShadowSelectorInfo.
453 */
454VMMR3DECL(int) DBGFR3SelQueryInfo(PVM pVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo)
455{
456 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_PARAMETER);
457 AssertReturn(!(fFlags & ~(DBGFSELQI_FLAGS_DT_GUEST | DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE)), VERR_INVALID_PARAMETER);
458 AssertReturn( (fFlags & (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE))
459 != (DBGFSELQI_FLAGS_DT_SHADOW | DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE), VERR_INVALID_PARAMETER);
460
461 /* Clear the return data here on this thread. */
462 memset(pSelInfo, 0, sizeof(*pSelInfo));
463
464 /*
465 * Dispatch the request to a worker running on the target CPU.
466 */
467 return VMR3ReqCallWaitU(pVM->pUVM, idCpu, (PFNRT)dbgfR3SelQueryInfo, 5, pVM, idCpu, Sel, fFlags, pSelInfo);
468}
469
470
471/**
472 * Validates a CS selector.
473 *
474 * @returns VBox status code.
475 * @param pSelInfo Pointer to the selector information for the CS selector.
476 * @param SelCPL The selector defining the CPL (SS).
477 */
478VMMDECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL)
479{
480 /*
481 * Check if present.
482 */
483 if (pSelInfo->u.Raw.Gen.u1Present)
484 {
485 /*
486 * Type check.
487 */
488 if ( pSelInfo->u.Raw.Gen.u1DescType == 1
489 && (pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
490 {
491 /*
492 * Check level.
493 */
494 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
495 if ( !(pSelInfo->u.Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
496 ? uLevel <= pSelInfo->u.Raw.Gen.u2Dpl
497 : uLevel >= pSelInfo->u.Raw.Gen.u2Dpl /* hope I got this right now... */
498 )
499 return VINF_SUCCESS;
500 return VERR_INVALID_RPL;
501 }
502 return VERR_NOT_CODE_SELECTOR;
503 }
504 return VERR_SELECTOR_NOT_PRESENT;
505}
506
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