VirtualBox

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

Last change on this file since 24912 was 24061, checked in by vboxsync, 15 years ago

DBGF,DBGPlugInDiggers: Extended DBGFR3MemScan with an alignment restriction. Added DBGFR3CpuGetMode. Started on the WinNT debug digger - can detect the 32-bit kernel, locate the module list and report the nt version.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use