VirtualBox

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

Last change on this file since 39082 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.8 KB
Line 
1/* $Id: DBGFStack.cpp 38838 2011-09-23 11:21:55Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Call Stack Analyser.
4 */
5
6/*
7 * Copyright (C) 2006-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/vmm/dbgf.h>
24#include <VBox/vmm/selm.h>
25#include <VBox/vmm/mm.h>
26#include "DBGFInternal.h"
27#include <VBox/vmm/vm.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30#include <iprt/param.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <iprt/alloca.h>
34
35
36
37/**
38 * Read stack memory.
39 */
40DECLINLINE(int) dbgfR3Read(PVM pVM, VMCPUID idCpu, void *pvBuf, PCDBGFADDRESS pSrcAddr, size_t cb, size_t *pcbRead)
41{
42 int rc = DBGFR3MemRead(pVM, idCpu, pSrcAddr, pvBuf, cb);
43 if (RT_FAILURE(rc))
44 {
45 /* fallback: byte by byte and zero the ones we fail to read. */
46 size_t cbRead;
47 for (cbRead = 0; cbRead < cb; cbRead++)
48 {
49 DBGFADDRESS Addr = *pSrcAddr;
50 rc = DBGFR3MemRead(pVM, idCpu, DBGFR3AddrAdd(&Addr, cbRead), (uint8_t *)pvBuf + cbRead, 1);
51 if (RT_FAILURE(rc))
52 break;
53 }
54 if (cbRead)
55 rc = VINF_SUCCESS;
56 memset((char *)pvBuf + cbRead, 0, cb - cbRead);
57 *pcbRead = cbRead;
58 }
59 else
60 *pcbRead = cb;
61 return rc;
62}
63
64
65/**
66 * Internal worker routine.
67 *
68 * On x86 the typical stack frame layout is like this:
69 * .. ..
70 * 16 parameter 2
71 * 12 parameter 1
72 * 8 parameter 0
73 * 4 return address
74 * 0 old ebp; current ebp points here
75 *
76 * @todo Add AMD64 support (needs teaming up with the module management for
77 * unwind tables).
78 */
79static int dbgfR3StackWalk(PVM pVM, VMCPUID idCpu, RTDBGAS hAs, PDBGFSTACKFRAME pFrame)
80{
81 /*
82 * Stop if we got a read error in the previous run.
83 */
84 if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST)
85 return VERR_NO_MORE_FILES;
86
87 /*
88 * Read the raw frame data.
89 */
90 const DBGFADDRESS AddrOldPC = pFrame->AddrPC;
91 const unsigned cbRetAddr = DBGFReturnTypeSize(pFrame->enmReturnType);
92 unsigned cbStackItem;
93 switch (AddrOldPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
94 {
95 case DBGFADDRESS_FLAGS_FAR16: cbStackItem = 2; break;
96 case DBGFADDRESS_FLAGS_FAR32: cbStackItem = 4; break;
97 case DBGFADDRESS_FLAGS_FAR64: cbStackItem = 8; break;
98 case DBGFADDRESS_FLAGS_RING0: cbStackItem = sizeof(RTHCUINTPTR); break;
99 default:
100 switch (pFrame->enmReturnType)
101 {
102 case DBGFRETURNTYPE_FAR16:
103 case DBGFRETURNTYPE_IRET16:
104 case DBGFRETURNTYPE_IRET32_V86:
105 case DBGFRETURNTYPE_NEAR16: cbStackItem = 2; break;
106
107 case DBGFRETURNTYPE_FAR32:
108 case DBGFRETURNTYPE_IRET32:
109 case DBGFRETURNTYPE_IRET32_PRIV:
110 case DBGFRETURNTYPE_NEAR32: cbStackItem = 4; break;
111
112 case DBGFRETURNTYPE_FAR64:
113 case DBGFRETURNTYPE_IRET64:
114 case DBGFRETURNTYPE_NEAR64: cbStackItem = 8; break;
115
116 default:
117 AssertMsgFailed(("%d\n", pFrame->enmReturnType));
118 cbStackItem = 4;
119 break;
120 }
121 }
122
123 union
124 {
125 uint64_t *pu64;
126 uint32_t *pu32;
127 uint16_t *pu16;
128 uint8_t *pb;
129 void *pv;
130 } u, uRet, uArgs, uBp;
131 size_t cbRead = cbRetAddr + cbStackItem + sizeof(pFrame->Args);
132 u.pv = alloca(cbRead);
133 uBp = u;
134 uRet.pb = u.pb + cbStackItem;
135 uArgs.pb = u.pb + cbStackItem + cbRetAddr;
136
137 Assert(DBGFADDRESS_IS_VALID(&pFrame->AddrFrame));
138 int rc = dbgfR3Read(pVM, idCpu, u.pv,
139 pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID
140 ? &pFrame->AddrReturnFrame
141 : &pFrame->AddrFrame,
142 cbRead, &cbRead);
143 if ( RT_FAILURE(rc)
144 || cbRead < cbRetAddr + cbStackItem)
145 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_LAST;
146
147 /*
148 * The first step is taken in a different way than the others.
149 */
150 if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID))
151 {
152 pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_ALL_VALID;
153 pFrame->iFrame = 0;
154
155 /* Current PC - set by caller, just find symbol & line. */
156 if (DBGFADDRESS_IS_VALID(&pFrame->AddrPC))
157 {
158 pFrame->pSymPC = DBGFR3AsSymbolByAddrA(pVM, hAs, &pFrame->AddrPC, NULL /*offDisp*/, NULL /*phMod*/);
159 pFrame->pLinePC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrPC.FlatPtr, NULL);
160 }
161 }
162 else /* 2nd and subsequent steps */
163 {
164 /* frame, pc and stack is taken from the existing frames return members. */
165 pFrame->AddrFrame = pFrame->AddrReturnFrame;
166 pFrame->AddrPC = pFrame->AddrReturnPC;
167 pFrame->pSymPC = pFrame->pSymReturnPC;
168 pFrame->pLinePC = pFrame->pLineReturnPC;
169
170 /* increment the frame number. */
171 pFrame->iFrame++;
172 }
173
174 /*
175 * Return Frame address.
176 */
177 pFrame->AddrReturnFrame = pFrame->AddrFrame;
178 switch (cbStackItem)
179 {
180 case 2: pFrame->AddrReturnFrame.off = *uBp.pu16; break;
181 case 4: pFrame->AddrReturnFrame.off = *uBp.pu32; break;
182 case 8: pFrame->AddrReturnFrame.off = *uBp.pu64; break;
183 default: AssertMsgFailed(("cbStackItem=%d\n", cbStackItem)); return VERR_INTERNAL_ERROR;
184 }
185 pFrame->AddrReturnFrame.FlatPtr += pFrame->AddrReturnFrame.off - pFrame->AddrFrame.off;
186
187 /*
188 * Return PC and Stack Addresses.
189 */
190 /** @todo AddrReturnStack is not correct for stdcall and pascal. (requires scope info) */
191 pFrame->AddrReturnStack = pFrame->AddrFrame;
192 pFrame->AddrReturnStack.off += cbStackItem + cbRetAddr;
193 pFrame->AddrReturnStack.FlatPtr += cbStackItem + cbRetAddr;
194
195 pFrame->AddrReturnPC = pFrame->AddrPC;
196 switch (pFrame->enmReturnType)
197 {
198 case DBGFRETURNTYPE_NEAR16:
199 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
200 {
201 pFrame->AddrReturnPC.FlatPtr += *uRet.pu16 - pFrame->AddrReturnPC.off;
202 pFrame->AddrReturnPC.off = *uRet.pu16;
203 }
204 else
205 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu16);
206 break;
207 case DBGFRETURNTYPE_NEAR32:
208 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
209 {
210 pFrame->AddrReturnPC.FlatPtr += *uRet.pu32 - pFrame->AddrReturnPC.off;
211 pFrame->AddrReturnPC.off = *uRet.pu32;
212 }
213 else
214 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu32);
215 break;
216 case DBGFRETURNTYPE_NEAR64:
217 if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
218 {
219 pFrame->AddrReturnPC.FlatPtr += *uRet.pu64 - pFrame->AddrReturnPC.off;
220 pFrame->AddrReturnPC.off = *uRet.pu64;
221 }
222 else
223 DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu64);
224 break;
225 case DBGFRETURNTYPE_FAR16:
226 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
227 break;
228 case DBGFRETURNTYPE_FAR32:
229 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
230 break;
231 case DBGFRETURNTYPE_FAR64:
232 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
233 break;
234 case DBGFRETURNTYPE_IRET16:
235 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
236 break;
237 case DBGFRETURNTYPE_IRET32:
238 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
239 break;
240 case DBGFRETURNTYPE_IRET32_PRIV:
241 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
242 break;
243 case DBGFRETURNTYPE_IRET32_V86:
244 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
245 break;
246 case DBGFRETURNTYPE_IRET64:
247 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
248 break;
249 default:
250 AssertMsgFailed(("enmReturnType=%d\n", pFrame->enmReturnType));
251 return VERR_INVALID_PARAMETER;
252 }
253
254 pFrame->pSymReturnPC = DBGFR3AsSymbolByAddrA(pVM, hAs, &pFrame->AddrReturnPC, NULL /*offDisp*/, NULL /*phMod*/);
255 pFrame->pLineReturnPC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrReturnPC.FlatPtr, NULL);
256
257 /*
258 * Frame bitness flag.
259 */
260 switch (cbStackItem)
261 {
262 case 2: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_16BIT; break;
263 case 4: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_32BIT; break;
264 case 8: pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_64BIT; break;
265 default: AssertMsgFailed(("cbStackItem=%d\n", cbStackItem)); return VERR_INTERNAL_ERROR;
266 }
267
268 /*
269 * The arguments.
270 */
271 memcpy(&pFrame->Args, uArgs.pv, sizeof(pFrame->Args));
272
273 return VINF_SUCCESS;
274}
275
276
277/**
278 * Walks the entire stack allocating memory as we walk.
279 */
280static DECLCALLBACK(int) dbgfR3StackWalkCtxFull(PVM pVM, VMCPUID idCpu, PCCPUMCTXCORE pCtxCore, RTDBGAS hAs,
281 DBGFCODETYPE enmCodeType,
282 PCDBGFADDRESS pAddrFrame,
283 PCDBGFADDRESS pAddrStack,
284 PCDBGFADDRESS pAddrPC,
285 DBGFRETURNTYPE enmReturnType,
286 PCDBGFSTACKFRAME *ppFirstFrame)
287{
288 /* alloc first frame. */
289 PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_STACK, sizeof(*pCur));
290 if (!pCur)
291 return VERR_NO_MEMORY;
292
293 /*
294 * Initialize the frame.
295 */
296 pCur->pNextInternal = NULL;
297 pCur->pFirstInternal = pCur;
298
299 int rc = VINF_SUCCESS;
300 if (pAddrPC)
301 pCur->AddrPC = *pAddrPC;
302 else
303 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrPC, pCtxCore->cs, pCtxCore->rip);
304 if (RT_SUCCESS(rc))
305 {
306 if (enmReturnType == DBGFRETURNTYPE_INVALID)
307 switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
308 {
309 case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
310 case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
311 case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
312 case DBGFADDRESS_FLAGS_RING0: pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32; break;
313 default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests
314 }
315
316 uint64_t fAddrMask;
317 if (enmCodeType == DBGFCODETYPE_RING0)
318 fAddrMask = HC_ARCH_BITS == 64 ? UINT64_MAX : UINT32_MAX;
319 else if (enmCodeType == DBGFCODETYPE_HYPER)
320 fAddrMask = UINT32_MAX;
321 else if (DBGFADDRESS_IS_FAR16(&pCur->AddrPC))
322 fAddrMask = UINT16_MAX;
323 else if (DBGFADDRESS_IS_FAR32(&pCur->AddrPC))
324 fAddrMask = UINT32_MAX;
325 else if (DBGFADDRESS_IS_FAR64(&pCur->AddrPC))
326 fAddrMask = UINT64_MAX;
327 else
328 {
329 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
330 CPUMMODE CpuMode = CPUMGetGuestMode(pVCpu);
331 if (CpuMode == CPUMMODE_REAL)
332 fAddrMask = UINT16_MAX;
333 else if ( CpuMode == CPUMMODE_PROTECTED
334 || !CPUMIsGuestIn64BitCode(pVCpu, pCtxCore))
335 fAddrMask = UINT32_MAX;
336 else
337 fAddrMask = UINT64_MAX;
338 }
339
340 if (pAddrStack)
341 pCur->AddrStack = *pAddrStack;
342 else
343 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrStack, pCtxCore->ss, pCtxCore->rsp & fAddrMask);
344
345 if (pAddrFrame)
346 pCur->AddrFrame = *pAddrFrame;
347 else if (RT_SUCCESS(rc))
348 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrFrame, pCtxCore->ss, pCtxCore->rbp & fAddrMask);
349 }
350 else
351 pCur->enmReturnType = enmReturnType;
352
353 /*
354 * The first frame.
355 */
356 if (RT_SUCCESS(rc))
357 rc = dbgfR3StackWalk(pVM, idCpu, hAs, pCur);
358 if (RT_FAILURE(rc))
359 {
360 DBGFR3StackWalkEnd(pCur);
361 return rc;
362 }
363
364 /*
365 * The other frames.
366 */
367 DBGFSTACKFRAME Next = *pCur;
368 while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP)))
369 {
370 /* try walk. */
371 rc = dbgfR3StackWalk(pVM, idCpu, hAs, &Next);
372 if (RT_FAILURE(rc))
373 break;
374
375 /* add the next frame to the chain. */
376 PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAlloc(pVM, MM_TAG_DBGF_STACK, sizeof(*pNext));
377 if (!pNext)
378 {
379 DBGFR3StackWalkEnd(pCur);
380 return VERR_NO_MEMORY;
381 }
382 *pNext = Next;
383 pCur->pNextInternal = pNext;
384 pCur = pNext;
385 Assert(pCur->pNextInternal == NULL);
386
387 /* check for loop */
388 for (PCDBGFSTACKFRAME pLoop = pCur->pFirstInternal;
389 pLoop && pLoop != pCur;
390 pLoop = pLoop->pNextInternal)
391 if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr)
392 {
393 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP;
394 break;
395 }
396
397 /* check for insane recursion */
398 if (pCur->iFrame >= 2048)
399 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH;
400 }
401
402 *ppFirstFrame = pCur->pFirstInternal;
403 return rc;
404}
405
406
407/**
408 * Common worker for DBGFR3StackWalkBeginGuestEx, DBGFR3StackWalkBeginHyperEx,
409 * DBGFR3StackWalkBeginGuest and DBGFR3StackWalkBeginHyper.
410 */
411static int dbgfR3StackWalkBeginCommon(PVM pVM,
412 VMCPUID idCpu,
413 DBGFCODETYPE enmCodeType,
414 PCDBGFADDRESS pAddrFrame,
415 PCDBGFADDRESS pAddrStack,
416 PCDBGFADDRESS pAddrPC,
417 DBGFRETURNTYPE enmReturnType,
418 PCDBGFSTACKFRAME *ppFirstFrame)
419{
420 /*
421 * Validate parameters.
422 */
423 *ppFirstFrame = NULL;
424 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
425 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
426 if (pAddrFrame)
427 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrFrame), VERR_INVALID_PARAMETER);
428 if (pAddrStack)
429 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrStack), VERR_INVALID_PARAMETER);
430 if (pAddrPC)
431 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrPC), VERR_INVALID_PARAMETER);
432 AssertReturn(enmReturnType >= DBGFRETURNTYPE_INVALID && enmReturnType < DBGFRETURNTYPE_END, VERR_INVALID_PARAMETER);
433
434 /*
435 * Get the CPUM context pointer and pass it on the specified EMT.
436 */
437 RTDBGAS hAs;
438 PCCPUMCTXCORE pCtxCore;
439 switch (enmCodeType)
440 {
441 case DBGFCODETYPE_GUEST:
442 pCtxCore = CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu));
443 hAs = DBGF_AS_GLOBAL;
444 break;
445 case DBGFCODETYPE_HYPER:
446 pCtxCore = CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu));
447 hAs = DBGF_AS_RC_AND_GC_GLOBAL;
448 break;
449 case DBGFCODETYPE_RING0:
450 pCtxCore = NULL; /* No valid context present. */
451 hAs = DBGF_AS_R0;
452 break;
453 default:
454 AssertFailedReturn(VERR_INVALID_PARAMETER);
455 }
456 return VMR3ReqPriorityCallWait(pVM, idCpu, (PFNRT)dbgfR3StackWalkCtxFull, 10,
457 pVM, idCpu, pCtxCore, hAs, enmCodeType,
458 pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
459}
460
461
462/**
463 * Begins a guest stack walk, extended version.
464 *
465 * This will walk the current stack, constructing a list of info frames which is
466 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
467 * list and DBGFR3StackWalkEnd to release it.
468 *
469 * @returns VINF_SUCCESS on success.
470 * @returns VERR_NO_MEMORY if we're out of memory.
471 *
472 * @param pVM The VM handle.
473 * @param idCpu The ID of the virtual CPU which stack we want to walk.
474 * @param enmCodeType Code type
475 * @param pAddrFrame Frame address to start at. (Optional)
476 * @param pAddrStack Stack address to start at. (Optional)
477 * @param pAddrPC Program counter to start at. (Optional)
478 * @param enmReturnType The return address type. (Optional)
479 * @param ppFirstFrame Where to return the pointer to the first info frame.
480 */
481VMMR3DECL(int) DBGFR3StackWalkBeginEx(PVM pVM,
482 VMCPUID idCpu,
483 DBGFCODETYPE enmCodeType,
484 PCDBGFADDRESS pAddrFrame,
485 PCDBGFADDRESS pAddrStack,
486 PCDBGFADDRESS pAddrPC,
487 DBGFRETURNTYPE enmReturnType,
488 PCDBGFSTACKFRAME *ppFirstFrame)
489{
490 return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
491}
492
493
494/**
495 * Begins a guest stack walk.
496 *
497 * This will walk the current stack, constructing a list of info frames which is
498 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
499 * list and DBGFR3StackWalkEnd to release it.
500 *
501 * @returns VINF_SUCCESS on success.
502 * @returns VERR_NO_MEMORY if we're out of memory.
503 *
504 * @param pVM The VM handle.
505 * @param idCpu The ID of the virtual CPU which stack we want to walk.
506 * @param enmCodeType Code type
507 * @param ppFirstFrame Where to return the pointer to the first info frame.
508 */
509VMMR3DECL(int) DBGFR3StackWalkBegin(PVM pVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFSTACKFRAME *ppFirstFrame)
510{
511 return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, NULL, NULL, NULL, DBGFRETURNTYPE_INVALID, ppFirstFrame);
512}
513
514/**
515 * Gets the next stack frame.
516 *
517 * @returns Pointer to the info for the next stack frame.
518 * NULL if no more frames.
519 *
520 * @param pCurrent Pointer to the current stack frame.
521 *
522 */
523VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent)
524{
525 return pCurrent
526 ? pCurrent->pNextInternal
527 : NULL;
528}
529
530
531/**
532 * Ends a stack walk process.
533 *
534 * This *must* be called after a successful first call to any of the stack
535 * walker functions. If not called we will leak memory or other resources.
536 *
537 * @param pFirstFrame The frame returned by one of the the begin
538 * functions.
539 */
540VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame)
541{
542 if ( !pFirstFrame
543 || !pFirstFrame->pFirstInternal)
544 return;
545
546 PDBGFSTACKFRAME pFrame = (PDBGFSTACKFRAME)pFirstFrame->pFirstInternal;
547 while (pFrame)
548 {
549 PDBGFSTACKFRAME pCur = pFrame;
550 pFrame = (PDBGFSTACKFRAME)pCur->pNextInternal;
551 if (pFrame)
552 {
553 if (pCur->pSymReturnPC == pFrame->pSymPC)
554 pFrame->pSymPC = NULL;
555 if (pCur->pSymReturnPC == pFrame->pSymReturnPC)
556 pFrame->pSymReturnPC = NULL;
557
558 if (pCur->pSymPC == pFrame->pSymPC)
559 pFrame->pSymPC = NULL;
560 if (pCur->pSymPC == pFrame->pSymReturnPC)
561 pFrame->pSymReturnPC = NULL;
562
563 if (pCur->pLineReturnPC == pFrame->pLinePC)
564 pFrame->pLinePC = NULL;
565 if (pCur->pLineReturnPC == pFrame->pLineReturnPC)
566 pFrame->pLineReturnPC = NULL;
567
568 if (pCur->pLinePC == pFrame->pLinePC)
569 pFrame->pLinePC = NULL;
570 if (pCur->pLinePC == pFrame->pLineReturnPC)
571 pFrame->pLineReturnPC = NULL;
572 }
573
574 RTDbgSymbolFree(pCur->pSymPC);
575 RTDbgSymbolFree(pCur->pSymReturnPC);
576 DBGFR3LineFree(pCur->pLinePC);
577 DBGFR3LineFree(pCur->pLineReturnPC);
578
579 pCur->pNextInternal = NULL;
580 pCur->pFirstInternal = NULL;
581 pCur->fFlags = 0;
582 MMR3HeapFree(pCur);
583 }
584}
585
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