VirtualBox

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

Last change on this file since 22898 was 22890, checked in by vboxsync, 15 years ago

VM::cCPUs -> VM::cCpus so it matches all the other cCpus and aCpus members.

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