VirtualBox

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

Last change on this file since 19502 was 19300, checked in by vboxsync, 16 years ago

VMReq,*: Replaced VMREQDEST with VMCPUID because it's a pain to have to cast CPU IDs all the time.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.9 KB
Line 
1/* $Id: DBGFStack.cpp 19300 2009-05-01 18:06:59Z 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 <VBox/mm.h>
30#include "DBGFInternal.h"
31#include <VBox/vm.h>
32#include <VBox/err.h>
33#include <VBox/log.h>
34#include <iprt/param.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37#include <iprt/alloca.h>
38
39
40
41/**
42 * Read stack memory.
43 */
44DECLINLINE(int) dbgfR3Read(PVM pVM, VMCPUID idCpu, void *pvBuf, PCDBGFADDRESS pSrcAddr, size_t cb, size_t *pcbRead)
45{
46 int rc = DBGFR3MemRead(pVM, idCpu, pSrcAddr, pvBuf, cb);
47 if (RT_FAILURE(rc))
48 {
49 /* fallback: byte by byte and zero the ones we fail to read. */
50 size_t cbRead;
51 for (cbRead = 0; cbRead < cb; cbRead++)
52 {
53 DBGFADDRESS Addr = *pSrcAddr;
54 rc = DBGFR3MemRead(pVM, idCpu, DBGFR3AddrAdd(&Addr, cbRead), (uint8_t *)pvBuf + 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, VMCPUID idCpu, 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, idCpu, u.pv,
121 pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID
122 ? &pFrame->AddrReturnFrame
123 : &pFrame->AddrFrame,
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, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
209 break;
210 case DBGFRETURNTYPE_FAR32:
211 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
212 break;
213 case DBGFRETURNTYPE_FAR64:
214 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
215 break;
216 case DBGFRETURNTYPE_IRET16:
217 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
218 break;
219 case DBGFRETURNTYPE_IRET32:
220 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
221 break;
222 case DBGFRETURNTYPE_IRET32_PRIV:
223 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
224 break;
225 case DBGFRETURNTYPE_IRET32_V86:
226 DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
227 break;
228 case DBGFRETURNTYPE_IRET64:
229 DBGFR3AddrFromSelOff(pVM, idCpu, &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, VMCPUID idCpu, PCCPUMCTXCORE pCtxCore, bool fGuest,
252 PCDBGFADDRESS pAddrFrame,
253 PCDBGFADDRESS pAddrStack,
254 PCDBGFADDRESS pAddrPC,
255 DBGFRETURNTYPE enmReturnType,
256 PCDBGFSTACKFRAME *ppFirstFrame)
257{
258 /* alloc first frame. */
259 PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_STACK, sizeof(*pCur));
260 if (!pCur)
261 return VERR_NO_MEMORY;
262
263 /*
264 * Initialize the frame.
265 */
266 pCur->pNextInternal = NULL;
267 pCur->pFirstInternal = pCur;
268
269 int rc = VINF_SUCCESS;
270 if (pAddrPC)
271 pCur->AddrPC = *pAddrPC;
272 else
273 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrPC, pCtxCore->cs, pCtxCore->rip);
274 if (RT_SUCCESS(rc))
275 {
276 if (enmReturnType == DBGFRETURNTYPE_INVALID)
277 switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
278 {
279 case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
280 case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
281 case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
282 default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests
283 }
284
285 uint64_t fAddrMask = UINT64_MAX;
286 if (!fGuest)
287 fAddrMask = UINT32_MAX;
288 else if (DBGFADDRESS_IS_FAR16(&pCur->AddrPC))
289 fAddrMask = UINT16_MAX;
290 else if (DBGFADDRESS_IS_FAR32(&pCur->AddrPC))
291 fAddrMask = UINT32_MAX;
292 else if (DBGFADDRESS_IS_FLAT(&pCur->AddrPC))
293 {
294 CPUMMODE CpuMode = CPUMGetGuestMode(VMMGetCpuById(pVM, idCpu));
295 if (CpuMode == CPUMMODE_REAL)
296 fAddrMask = UINT16_MAX;
297 else if (CpuMode == CPUMMODE_PROTECTED)
298 fAddrMask = UINT32_MAX;
299 }
300
301 if (pAddrStack)
302 pCur->AddrStack = *pAddrStack;
303 else
304 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrStack, pCtxCore->ss, pCtxCore->rsp & fAddrMask);
305
306 if (pAddrFrame)
307 pCur->AddrFrame = *pAddrFrame;
308 else if (RT_SUCCESS(rc))
309 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrFrame, pCtxCore->ss, pCtxCore->rbp & fAddrMask);
310 }
311 else
312 pCur->enmReturnType = enmReturnType;
313
314 /*
315 * The first frame.
316 */
317 if (RT_SUCCESS(rc))
318 rc = dbgfR3StackWalk(pVM, idCpu, pCur);
319 if (RT_FAILURE(rc))
320 {
321 DBGFR3StackWalkEnd(pCur);
322 return rc;
323 }
324
325 /*
326 * The other frames.
327 */
328 DBGFSTACKFRAME Next = *pCur;
329 while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP)))
330 {
331 /* try walk. */
332 rc = dbgfR3StackWalk(pVM, idCpu, &Next);
333 if (RT_FAILURE(rc))
334 break;
335
336 /* add the next frame to the chain. */
337 PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAlloc(pVM, MM_TAG_DBGF_STACK, sizeof(*pNext));
338 if (!pNext)
339 {
340 DBGFR3StackWalkEnd(pCur);
341 return VERR_NO_MEMORY;
342 }
343 *pNext = Next;
344 pCur->pNextInternal = pNext;
345 pCur = pNext;
346 Assert(pCur->pNextInternal == NULL);
347
348 /* check for loop */
349 for (PCDBGFSTACKFRAME pLoop = pCur->pFirstInternal;
350 pLoop && pLoop != pCur;
351 pLoop = pLoop->pNextInternal)
352 if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr)
353 {
354 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP;
355 break;
356 }
357
358 /* check for insane recursion */
359 if (pCur->iFrame >= 2048)
360 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH;
361 }
362
363 *ppFirstFrame = pCur->pFirstInternal;
364 return rc;
365}
366
367
368/**
369 * Common worker for DBGFR3StackWalkBeginGuestEx, DBGFR3StackWalkBeginHyperEx,
370 * DBGFR3StackWalkBeginGuest and DBGFR3StackWalkBeginHyper.
371 */
372static int dbgfR3StackWalkBeginCommon(PVM pVM,
373 VMCPUID idCpu,
374 bool fGuest,
375 PCDBGFADDRESS pAddrFrame,
376 PCDBGFADDRESS pAddrStack,
377 PCDBGFADDRESS pAddrPC,
378 DBGFRETURNTYPE enmReturnType,
379 PCDBGFSTACKFRAME *ppFirstFrame)
380{
381 /*
382 * Validate parameters.
383 */
384 *ppFirstFrame = NULL;
385 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
386 AssertReturn(idCpu < pVM->cCPUs, VERR_INVALID_CPU_ID);
387 if (pAddrFrame)
388 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrFrame), VERR_INVALID_PARAMETER);
389 if (pAddrStack)
390 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrStack), VERR_INVALID_PARAMETER);
391 if (pAddrPC)
392 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrPC), VERR_INVALID_PARAMETER);
393 AssertReturn(enmReturnType >= DBGFRETURNTYPE_INVALID && enmReturnType < DBGFRETURNTYPE_END, VERR_INVALID_PARAMETER);
394
395 /*
396 * Get the CPUM context pointer and pass it on the specified EMT.
397 */
398 PCCPUMCTXCORE pCtxCore = fGuest
399 ? CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu))
400 : CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu));
401 PVMREQ pReq;
402 int rc = VMR3ReqCall(pVM, idCpu, &pReq, RT_INDEFINITE_WAIT,
403 (PFNRT)dbgfR3StackWalkCtxFull, 9,
404 pVM, idCpu, pCtxCore, fGuest,
405 pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
406 if (RT_SUCCESS(rc))
407 rc = pReq->iStatus;
408 VMR3ReqFree(pReq);
409
410 return rc;
411
412}
413
414
415/**
416 * Begins a guest stack walk, extended version.
417 *
418 * This will walk the current stack, constructing a list of info frames which is
419 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
420 * list and DBGFR3StackWalkEnd to release it.
421 *
422 * @returns VINF_SUCCESS on success.
423 * @returns VERR_NO_MEMORY if we're out of memory.
424 *
425 * @param pVM The VM handle.
426 * @param idCpu The ID of the virtual CPU which stack we want to walk.
427 * @param pAddrFrame Frame address to start at. (Optional)
428 * @param pAddrStack Stack address to start at. (Optional)
429 * @param pAddrPC Program counter to start at. (Optional)
430 * @param enmReturnType The return address type. (Optional)
431 * @param ppFirstFrame Where to return the pointer to the first info frame.
432 */
433VMMR3DECL(int) DBGFR3StackWalkBeginGuestEx(PVM pVM,
434 VMCPUID idCpu,
435 PCDBGFADDRESS pAddrFrame,
436 PCDBGFADDRESS pAddrStack,
437 PCDBGFADDRESS pAddrPC,
438 DBGFRETURNTYPE enmReturnType,
439 PCDBGFSTACKFRAME *ppFirstFrame)
440{
441 return dbgfR3StackWalkBeginCommon(pVM, idCpu, true /*fGuest*/, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
442}
443
444
445/**
446 * Begins a guest stack walk.
447 *
448 * This will walk the current stack, constructing a list of info frames which is
449 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
450 * list and DBGFR3StackWalkEnd to release it.
451 *
452 * @returns VINF_SUCCESS on success.
453 * @returns VERR_NO_MEMORY if we're out of memory.
454 *
455 * @param pVM The VM handle.
456 * @param idCpu The ID of the virtual CPU which stack we want to walk.
457 * @param ppFirstFrame Where to return the pointer to the first info frame.
458 */
459VMMR3DECL(int) DBGFR3StackWalkBeginGuest(PVM pVM, VMCPUID idCpu, PCDBGFSTACKFRAME *ppFirstFrame)
460{
461 return dbgfR3StackWalkBeginCommon(pVM, idCpu, true /*fGuest*/, NULL, NULL, NULL, DBGFRETURNTYPE_INVALID, ppFirstFrame);
462}
463
464
465/**
466 * Begins a hyper stack walk, extended version.
467 *
468 * This will walk the current stack, constructing a list of info frames which is
469 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
470 * list and DBGFR3StackWalkEnd to release it.
471 *
472 * @returns VINF_SUCCESS on success.
473 * @returns VERR_NO_MEMORY if we're out of memory.
474 *
475 * @param pVM The VM handle.
476 * @param idCpu The ID of the virtual CPU which stack we want to walk.
477 * @param pAddrFrame Frame address to start at. (Optional)
478 * @param pAddrStack Stack address to start at. (Optional)
479 * @param pAddrPC Program counter to start at. (Optional)
480 * @param enmReturnType The return address type. (Optional)
481 * @param ppFirstFrame Where to return the pointer to the first info frame.
482 */
483VMMR3DECL(int) DBGFR3StackWalkBeginHyperEx(PVM pVM,
484 VMCPUID idCpu,
485 PCDBGFADDRESS pAddrFrame,
486 PCDBGFADDRESS pAddrStack,
487 PCDBGFADDRESS pAddrPC,
488 DBGFRETURNTYPE enmReturnType,
489 PCDBGFSTACKFRAME *ppFirstFrame)
490{
491 return dbgfR3StackWalkBeginCommon(pVM, idCpu, false /*fGuest*/, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
492}
493
494
495/**
496 * Begins a hyper stack walk.
497 *
498 * This will walk the current stack, constructing a list of info frames which is
499 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
500 * list and DBGFR3StackWalkEnd to release it.
501 *
502 * @returns VINF_SUCCESS on success.
503 * @returns VERR_NO_MEMORY if we're out of memory.
504 *
505 * @param pVM The VM handle.
506 * @param idCpu The ID of the virtual CPU which stack we want to walk.
507 * @param ppFirstFrame Where to return the pointer to the first info frame.
508 */
509VMMR3DECL(int) DBGFR3StackWalkBeginHyper(PVM pVM, VMCPUID idCpu, PCDBGFSTACKFRAME *ppFirstFrame)
510{
511 return dbgfR3StackWalkBeginCommon(pVM, idCpu, false /*fGuest*/, NULL, NULL, NULL, DBGFRETURNTYPE_INVALID, ppFirstFrame);
512}
513
514
515/**
516 * Gets the next stack frame.
517 *
518 * @returns Pointer to the info for the next stack frame.
519 * NULL if no more frames.
520 *
521 * @param pCurrent Pointer to the current stack frame.
522 *
523 */
524VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent)
525{
526 return pCurrent
527 ? pCurrent->pNextInternal
528 : NULL;
529}
530
531
532/**
533 * Ends a stack walk process.
534 *
535 * This *must* be called after a successful first call to any of the stack
536 * walker functions. If not called we will leak memory or other resources.
537 *
538 * @param pFirstFrame The frame returned by one of the the begin
539 * functions.
540 */
541VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame)
542{
543 if ( !pFirstFrame
544 || !pFirstFrame->pFirstInternal)
545 return;
546
547 PDBGFSTACKFRAME pFrame = (PDBGFSTACKFRAME)pFirstFrame->pFirstInternal;
548 while (pFrame)
549 {
550 PDBGFSTACKFRAME pCur = pFrame;
551 pFrame = (PDBGFSTACKFRAME)pCur->pNextInternal;
552 if (pFrame)
553 {
554 if (pCur->pSymReturnPC == pFrame->pSymPC)
555 pFrame->pSymPC = NULL;
556 if (pCur->pSymReturnPC == pFrame->pSymReturnPC)
557 pFrame->pSymReturnPC = NULL;
558
559 if (pCur->pSymPC == pFrame->pSymPC)
560 pFrame->pSymPC = NULL;
561 if (pCur->pSymPC == pFrame->pSymReturnPC)
562 pFrame->pSymReturnPC = NULL;
563
564 if (pCur->pLineReturnPC == pFrame->pLinePC)
565 pFrame->pLinePC = NULL;
566 if (pCur->pLineReturnPC == pFrame->pLineReturnPC)
567 pFrame->pLineReturnPC = NULL;
568
569 if (pCur->pLinePC == pFrame->pLinePC)
570 pFrame->pLinePC = NULL;
571 if (pCur->pLinePC == pFrame->pLineReturnPC)
572 pFrame->pLineReturnPC = NULL;
573 }
574
575 DBGFR3SymbolFree(pCur->pSymPC);
576 DBGFR3SymbolFree(pCur->pSymReturnPC);
577 DBGFR3LineFree(pCur->pLinePC);
578 DBGFR3LineFree(pCur->pLineReturnPC);
579
580 pCur->pNextInternal = NULL;
581 pCur->pFirstInternal = NULL;
582 pCur->fFlags = 0;
583 MMR3HeapFree(pCur);
584 }
585}
586
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