VirtualBox

source: vbox/trunk/src/VBox/VMM/DBGFStack.cpp@ 19167

Last change on this file since 19167 was 18927, checked in by vboxsync, 16 years ago

Big step to separate VMM data structures for guest SMP. (pgm, em)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.1 KB
Line 
1/* $Id: DBGFStack.cpp 18927 2009-04-16 11:41:38Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Call Stack Analyser.
4 */
5
6/*
7 * Copyright (C) 2006-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/selm.h>
29#include "DBGFInternal.h"
30#include <VBox/vm.h>
31#include <VBox/mm.h>
32#include <VBox/err.h>
33#include <VBox/log.h>
34#include <iprt/assert.h>
35#include <iprt/string.h>
36#include <iprt/alloca.h>
37
38
39
40/**
41 * Read stack memory.
42 */
43DECLINLINE(int) dbgfR3Read(PVM pVM, void *pvBuf, RTGCUINTPTR GCPtr, size_t cb, size_t *pcbRead)
44{
45 /* @todo SMP support! */
46 PVMCPU pVCpu = &pVM->aCpus[0];
47
48 int rc = DBGFR3ReadGCVirt(pVM, pVCpu, pvBuf, GCPtr, cb);
49 if (RT_FAILURE(rc))
50 {
51 size_t cbRead;
52 for (cbRead = 0; cbRead < cb; cbRead++)
53 {
54 rc = DBGFR3ReadGCVirt(pVM, pVCpu, (uint8_t *)pvBuf + cbRead, GCPtr + cbRead, 1);
55 if (RT_FAILURE(rc))
56 break;
57 }
58 if (cbRead)
59 rc = VINF_SUCCESS;
60 memset((char *)pvBuf + cbRead, 0, cb - cbRead);
61 *pcbRead = cbRead;
62 }
63 else
64 *pcbRead = cb;
65 return rc;
66}
67
68
69/**
70 * Internal worker routine.
71 *
72 * On x86 the typical stack frame layout is like this:
73 * .. ..
74 * 16 parameter 2
75 * 12 parameter 1
76 * 8 parameter 0
77 * 4 return address
78 * 0 old ebp; current ebp points here
79 *
80 * @todo Add AMD64 support (needs teaming up with the module management for
81 * unwind tables).
82 */
83static int dbgfR3StackWalk(PVM pVM, PDBGFSTACKFRAME pFrame)
84{
85 /*
86 * Stop if we got a read error in the previous run.
87 */
88 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST)
89 return VERR_NO_MORE_FILES;
90
91 /*
92 * Read the raw frame data.
93 */
94 const DBGFADDRESS AddrOldPC = pFrame->AddrPC;
95 const unsigned cbRetAddr = DBGFReturnTypeSize(pFrame->enmReturnType);
96 unsigned cbStackItem;
97 switch (AddrOldPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
98 {
99 case DBGFADDRESS_FLAGS_FAR16: cbStackItem = 2; break;
100 case DBGFADDRESS_FLAGS_FAR32: cbStackItem = 4; break;
101 case DBGFADDRESS_FLAGS_FAR64: cbStackItem = 8; break;
102 default: cbStackItem = 4; break; /// @todo 64-bit guests.
103 }
104
105 union
106 {
107 uint64_t *pu64;
108 uint32_t *pu32;
109 uint16_t *pu16;
110 uint8_t *pb;
111 void *pv;
112 } u, uRet, uArgs, uBp;
113 size_t cbRead = cbRetAddr + cbStackItem + sizeof(pFrame->Args);
114 u.pv = alloca(cbRead);
115 uBp = u;
116 uRet.pb = u.pb + cbStackItem;
117 uArgs.pb = u.pb + cbStackItem + cbRetAddr;
118
119 Assert(DBGFADDRESS_IS_VALID(&pFrame->AddrFrame));
120 int rc = dbgfR3Read(pVM, u.pv,
121 pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID
122 ? pFrame->AddrReturnFrame.FlatPtr
123 : pFrame->AddrFrame.FlatPtr,
124 cbRead, &cbRead);
125 if ( RT_FAILURE(rc)
126 || cbRead < cbRetAddr + cbStackItem)
127 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_LAST;
128
129 /*
130 * The first step is taken in a different way than the others.
131 */
132 if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID))
133 {
134 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_ALL_VALID;
135 pFrame->iFrame = 0;
136
137 /* Current PC - set by caller, just find symbol & line. */
138 if (DBGFADDRESS_IS_VALID(&pFrame->AddrPC))
139 {
140 pFrame->pSymPC = DBGFR3SymbolByAddrAlloc(pVM, pFrame->AddrPC.FlatPtr, NULL);
141 pFrame->pLinePC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrPC.FlatPtr, NULL);
142 }
143 }
144 else /* 2nd and subsequent steps */
145 {
146 /* frame, pc and stack is taken from the existing frames return members. */
147 pFrame->AddrFrame = pFrame->AddrReturnFrame;
148 pFrame->AddrPC = pFrame->AddrReturnPC;
149 pFrame->pSymPC = pFrame->pSymReturnPC;
150 pFrame->pLinePC = pFrame->pLineReturnPC;
151
152 /* increment the frame number. */
153 pFrame->iFrame++;
154 }
155
156 /*
157 * Return Frame address.
158 */
159 pFrame->AddrReturnFrame = pFrame->AddrFrame;
160 switch (cbStackItem)
161 {
162 case 2: pFrame->AddrReturnFrame.off = *uBp.pu16; break;
163 case 4: pFrame->AddrReturnFrame.off = *uBp.pu32; break;
164 case 8: pFrame->AddrReturnFrame.off = *uBp.pu64; break;
165 default: AssertMsgFailed(("cbStackItem=%d\n", cbStackItem)); return VERR_INTERNAL_ERROR;
166 }
167 pFrame->AddrReturnFrame.FlatPtr += pFrame->AddrReturnFrame.off - pFrame->AddrFrame.off;
168
169 /*
170 * Return PC and Stack Addresses.
171 */
172 /** @todo AddrReturnStack is not correct for stdcall and pascal. (requires scope info) */
173 pFrame->AddrReturnStack = pFrame->AddrFrame;
174 pFrame->AddrReturnStack.off += cbStackItem + cbRetAddr;
175 pFrame->AddrReturnStack.FlatPtr += cbStackItem + cbRetAddr;
176
177 pFrame->AddrReturnPC = pFrame->AddrPC;
178 switch (pFrame->enmReturnType)
179 {
180 case DBGFRETURNTYPE_NEAR16:
181 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
182 {
183 pFrame->AddrReturnPC.FlatPtr += *uRet.pu16 - pFrame->AddrReturnPC.off;
184 pFrame->AddrReturnPC.off = *uRet.pu16;
185 }
186 else
187 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu16);
188 break;
189 case DBGFRETURNTYPE_NEAR32:
190 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
191 {
192 pFrame->AddrReturnPC.FlatPtr += *uRet.pu32 - pFrame->AddrReturnPC.off;
193 pFrame->AddrReturnPC.off = *uRet.pu32;
194 }
195 else
196 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu32);
197 break;
198 case DBGFRETURNTYPE_NEAR64:
199 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
200 {
201 pFrame->AddrReturnPC.FlatPtr += *uRet.pu64 - pFrame->AddrReturnPC.off;
202 pFrame->AddrReturnPC.off = *uRet.pu64;
203 }
204 else
205 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu64);
206 break;
207 case DBGFRETURNTYPE_FAR16:
208 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
209 break;
210 case DBGFRETURNTYPE_FAR32:
211 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
212 break;
213 case DBGFRETURNTYPE_FAR64:
214 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
215 break;
216 case DBGFRETURNTYPE_IRET16:
217 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
218 break;
219 case DBGFRETURNTYPE_IRET32:
220 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
221 break;
222 case DBGFRETURNTYPE_IRET32_PRIV:
223 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
224 break;
225 case DBGFRETURNTYPE_IRET32_V86:
226 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
227 break;
228 case DBGFRETURNTYPE_IRET64:
229 DBGFR3AddrFromSelOff(pVM, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
230 break;
231 default:
232 AssertMsgFailed(("enmReturnType=%d\n", pFrame->enmReturnType));
233 return VERR_INVALID_PARAMETER;
234 }
235
236 pFrame->pSymReturnPC = DBGFR3SymbolByAddrAlloc(pVM, pFrame->AddrReturnPC.FlatPtr, NULL);
237 pFrame->pLineReturnPC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrReturnPC.FlatPtr, NULL);
238
239 /*
240 * The arguments.
241 */
242 memcpy(&pFrame->Args, uArgs.pv, sizeof(pFrame->Args));
243
244 return VINF_SUCCESS;
245}
246
247
248/**
249 * Walks the entire stack allocating memory as we walk.
250 */
251static DECLCALLBACK(int) dbgfR3StackWalkCtxFull(PVM pVM, PDBGFSTACKFRAME pFrame, PCCPUMCTXCORE pCtxCore, bool fGuest)
252{
253 pFrame->pNext = NULL;
254 pFrame->pFirst = NULL;
255
256 /* alloc first frame. */
257 PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_STACK, sizeof(*pCur));
258 if (!pCur)
259 return VERR_NO_MEMORY;
260
261 /* copy input frame */
262 pCur->AddrFrame = pFrame->AddrFrame;
263 pCur->AddrStack = pFrame->AddrStack;
264 pCur->AddrPC = pFrame->AddrPC;
265 pCur->enmReturnType = pFrame->enmReturnType;
266 pCur->pNext = NULL;
267 pCur->pFirst = pCur;
268
269 int rc = VINF_SUCCESS;
270 if (!DBGFADDRESS_IS_VALID(&pCur->AddrPC))
271 rc = DBGFR3AddrFromSelOff(pVM, &pCur->AddrPC, pCtxCore->cs, pCtxCore->eip);
272 if (RT_SUCCESS(rc) /*&& pCur->enmReturnType == DBGFRETURNTYPE_INVALID*/)
273 {
274 switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
275 {
276 case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
277 case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
278 case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
279 default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests
280 }
281 }
282 uint64_t u64Mask = UINT64_MAX;
283 if (RT_SUCCESS(rc) && DBGFADDRESS_IS_FAR16(&pCur->AddrPC) && fGuest)
284 u64Mask = UINT16_MAX;
285 if (RT_SUCCESS(rc) && !DBGFADDRESS_IS_VALID(&pCur->AddrStack))
286 rc = DBGFR3AddrFromSelOff(pVM, &pCur->AddrStack, pCtxCore->ss, pCtxCore->esp & u64Mask);
287 if (RT_SUCCESS(rc) && !DBGFADDRESS_IS_VALID(&pCur->AddrFrame))
288 rc = DBGFR3AddrFromSelOff(pVM, &pCur->AddrFrame, pCtxCore->ss, pCtxCore->ebp & u64Mask);
289
290 /*
291 * The first frame.
292 */
293 if (RT_SUCCESS(rc))
294 rc = dbgfR3StackWalk(pVM, pCur);
295 if (RT_FAILURE(rc))
296 {
297 DBGFR3StackWalkEnd(pVM, pCur);
298 return rc;
299 }
300
301 /*
302 * The other frames.
303 */
304 DBGFSTACKFRAME Next = *pCur;
305 while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP)))
306 {
307 /* try walk. */
308 rc = dbgfR3StackWalk(pVM, &Next);
309 if (RT_FAILURE(rc))
310 break;
311
312 /* add the next frame to the chain. */
313 PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAlloc(pVM, MM_TAG_DBGF_STACK, sizeof(*pNext));
314 if (!pNext)
315 {
316 DBGFR3StackWalkEnd(pVM, pCur);
317 return VERR_NO_MEMORY;
318 }
319 *pNext = Next;
320 pCur = pCur->pNext = pNext;
321 Assert(pCur->pNext == NULL);
322
323 /* check for loop */
324 for (PDBGFSTACKFRAME pLoop = pCur->pFirst; pLoop && pLoop != pCur; pLoop = pLoop->pNext)
325 if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr)
326 {
327 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP;
328 break;
329 }
330
331 /* check for insane recursion */
332 if (pCur->iFrame >= 2048)
333 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH;
334 }
335
336 *pFrame = *pCur->pFirst;
337 return rc;
338}
339
340
341/**
342 * Begins a stack walk.
343 * This will construct and obtain the first frame.
344 *
345 * @returns VINF_SUCCESS on success.
346 * @returns VERR_NO_MEMORY if we're out of memory.
347 * @param pVM The VM handle.
348 * @param pFrame The stack frame info structure.
349 * On input this structure must be memset to zero.
350 * If wanted, the AddrPC, AddrStack and AddrFrame fields may be set
351 * to valid addresses after memsetting it. Any of those fields not set
352 * will be fetched from the guest CPU state.
353 * On output the structure will contain all the information we were able to
354 * obtain about the stack frame.
355 */
356VMMR3DECL(int) DBGFR3StackWalkBeginGuest(PVM pVM, PDBGFSTACKFRAME pFrame)
357{
358 pFrame->pFirst = NULL;
359 pFrame->pNext = NULL;
360
361 PVMREQ pReq;
362 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3StackWalkCtxFull, 4,
363 pVM, pFrame, CPUMGetGuestCtxCore(VMMGetCpu(pVM)), true); /* @todo SMP support!! */
364 if (RT_SUCCESS(rc))
365 rc = pReq->iStatus;
366 VMR3ReqFree(pReq);
367
368 return rc;
369}
370
371
372/**
373 * Begins a stack walk.
374 * This will construct and obtain the first frame.
375 *
376 * @returns VINF_SUCCESS on success.
377 * @returns VERR_NO_MEMORY if we're out of memory.
378 * @param pVM The VM handle.
379 * @param pFrame The stack frame info structure.
380 * On input this structure must be memset to zero.
381 * If wanted, the AddrPC, AddrStack and AddrFrame fields may be set
382 * to valid addresses after memsetting it. Any of those fields not set
383 * will be fetched from the hypervisor CPU state.
384 * On output the structure will contain all the information we were able to
385 * obtain about the stack frame.
386 */
387VMMR3DECL(int) DBGFR3StackWalkBeginHyper(PVM pVM, PDBGFSTACKFRAME pFrame)
388{
389 /* @todo SMP support! */
390 PVMCPU pVCpu = &pVM->aCpus[0];
391
392 pFrame->pFirst = NULL;
393 pFrame->pNext = NULL;
394
395 PVMREQ pReq;
396 int rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)dbgfR3StackWalkCtxFull, 4,
397 pVM, pFrame, CPUMGetHyperCtxCore(pVCpu), 4);
398 if (RT_SUCCESS(rc))
399 rc = pReq->iStatus;
400 VMR3ReqFree(pReq);
401
402 return rc;
403}
404
405
406/**
407 * Gets the next stack frame.
408 *
409 * @returns VINF_SUCCESS
410 * @returns VERR_NO_MORE_FILES if not more stack frames.
411 * @param pVM The VM handle.
412 * @param pFrame Pointer to the current frame on input, content is replaced with the next frame on successful return.
413 */
414VMMR3DECL(int) DBGFR3StackWalkNext(PVM pVM, PDBGFSTACKFRAME pFrame)
415{
416 if (pFrame->pNext)
417 {
418 *pFrame = *pFrame->pNext;
419 return VINF_SUCCESS;
420 }
421 return VERR_NO_MORE_FILES;
422}
423
424
425/**
426 * Ends a stack walk process.
427 *
428 * This *must* be called after a successful first call to any of the stack
429 * walker functions. If not called we will leak memory or other resources.
430 *
431 * @param pVM The VM handle.
432 * @param pFrame The stackframe as returned by the last stack walk call.
433 */
434VMMR3DECL(void) DBGFR3StackWalkEnd(PVM pVM, PDBGFSTACKFRAME pFrame)
435{
436 if (!pFrame || !pFrame->pFirst)
437 return;
438
439 pFrame = pFrame->pFirst;
440 while (pFrame)
441 {
442 PDBGFSTACKFRAME pCur = pFrame;
443 pFrame = pCur->pNext;
444 if (pFrame)
445 {
446 if (pCur->pSymReturnPC == pFrame->pSymPC)
447 pFrame->pSymPC = NULL;
448 if (pCur->pSymReturnPC == pFrame->pSymReturnPC)
449 pFrame->pSymReturnPC = NULL;
450
451 if (pCur->pSymPC == pFrame->pSymPC)
452 pFrame->pSymPC = NULL;
453 if (pCur->pSymPC == pFrame->pSymReturnPC)
454 pFrame->pSymReturnPC = NULL;
455
456 if (pCur->pLineReturnPC == pFrame->pLinePC)
457 pFrame->pLinePC = NULL;
458 if (pCur->pLineReturnPC == pFrame->pLineReturnPC)
459 pFrame->pLineReturnPC = NULL;
460
461 if (pCur->pLinePC == pFrame->pLinePC)
462 pFrame->pLinePC = NULL;
463 if (pCur->pLinePC == pFrame->pLineReturnPC)
464 pFrame->pLineReturnPC = NULL;
465 }
466
467 DBGFR3SymbolFree(pCur->pSymPC);
468 DBGFR3SymbolFree(pCur->pSymReturnPC);
469 DBGFR3LineFree(pCur->pLinePC);
470 DBGFR3LineFree(pCur->pLineReturnPC);
471
472 pCur->pNext = NULL;
473 pCur->pFirst = NULL;
474 pCur->fFlags = 0;
475 MMR3HeapFree(pCur);
476 }
477}
478
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