VirtualBox

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

Last change on this file since 44360 was 42449, checked in by vboxsync, 12 years ago

DBGFStack.cpp: Forced it to work with hypervisor stacks again (the selector turns out a bit weird, but we get something out of it).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 21.1 KB
Line 
1/* $Id: DBGFStack.cpp 42449 2012-07-30 15:10:30Z 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: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_1);
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: AssertMsgFailedReturn(("cbStackItem=%d\n", cbStackItem), VERR_DBGF_STACK_IPE_2);
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 if (enmCodeType != DBGFCODETYPE_GUEST)
303 DBGFR3AddrFromFlat(pVM, &pCur->AddrPC, pCtxCore->rip);
304 else
305 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrPC, pCtxCore->cs.Sel, pCtxCore->rip);
306 if (RT_SUCCESS(rc))
307 {
308 if (enmReturnType == DBGFRETURNTYPE_INVALID)
309 switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
310 {
311 case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
312 case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
313 case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
314 case DBGFADDRESS_FLAGS_RING0: pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32; break;
315 default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests
316 }
317
318 uint64_t fAddrMask;
319 if (enmCodeType == DBGFCODETYPE_RING0)
320 fAddrMask = HC_ARCH_BITS == 64 ? UINT64_MAX : UINT32_MAX;
321 else if (enmCodeType == DBGFCODETYPE_HYPER)
322 fAddrMask = UINT32_MAX;
323 else if (DBGFADDRESS_IS_FAR16(&pCur->AddrPC))
324 fAddrMask = UINT16_MAX;
325 else if (DBGFADDRESS_IS_FAR32(&pCur->AddrPC))
326 fAddrMask = UINT32_MAX;
327 else if (DBGFADDRESS_IS_FAR64(&pCur->AddrPC))
328 fAddrMask = UINT64_MAX;
329 else
330 {
331 PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
332 CPUMMODE CpuMode = CPUMGetGuestMode(pVCpu);
333 if (CpuMode == CPUMMODE_REAL)
334 fAddrMask = UINT16_MAX;
335 else if ( CpuMode == CPUMMODE_PROTECTED
336 || !CPUMIsGuestIn64BitCode(pVCpu))
337 fAddrMask = UINT32_MAX;
338 else
339 fAddrMask = UINT64_MAX;
340 }
341
342 if (pAddrStack)
343 pCur->AddrStack = *pAddrStack;
344 else if (enmCodeType != DBGFCODETYPE_GUEST)
345 DBGFR3AddrFromFlat(pVM, &pCur->AddrStack, pCtxCore->rsp & fAddrMask);
346 else
347 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrStack, pCtxCore->ss.Sel, pCtxCore->rsp & fAddrMask);
348
349 if (pAddrFrame)
350 pCur->AddrFrame = *pAddrFrame;
351 else if (enmCodeType != DBGFCODETYPE_GUEST)
352 DBGFR3AddrFromFlat(pVM, &pCur->AddrFrame, pCtxCore->rbp & fAddrMask);
353 else if (RT_SUCCESS(rc))
354 rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrFrame, pCtxCore->ss.Sel, pCtxCore->rbp & fAddrMask);
355 }
356 else
357 pCur->enmReturnType = enmReturnType;
358
359 /*
360 * The first frame.
361 */
362 if (RT_SUCCESS(rc))
363 rc = dbgfR3StackWalk(pVM, idCpu, hAs, pCur);
364 if (RT_FAILURE(rc))
365 {
366 DBGFR3StackWalkEnd(pCur);
367 return rc;
368 }
369
370 /*
371 * The other frames.
372 */
373 DBGFSTACKFRAME Next = *pCur;
374 while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP)))
375 {
376 /* try walk. */
377 rc = dbgfR3StackWalk(pVM, idCpu, hAs, &Next);
378 if (RT_FAILURE(rc))
379 break;
380
381 /* add the next frame to the chain. */
382 PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAlloc(pVM, MM_TAG_DBGF_STACK, sizeof(*pNext));
383 if (!pNext)
384 {
385 DBGFR3StackWalkEnd(pCur);
386 return VERR_NO_MEMORY;
387 }
388 *pNext = Next;
389 pCur->pNextInternal = pNext;
390 pCur = pNext;
391 Assert(pCur->pNextInternal == NULL);
392
393 /* check for loop */
394 for (PCDBGFSTACKFRAME pLoop = pCur->pFirstInternal;
395 pLoop && pLoop != pCur;
396 pLoop = pLoop->pNextInternal)
397 if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr)
398 {
399 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP;
400 break;
401 }
402
403 /* check for insane recursion */
404 if (pCur->iFrame >= 2048)
405 pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH;
406 }
407
408 *ppFirstFrame = pCur->pFirstInternal;
409 return rc;
410}
411
412
413/**
414 * Common worker for DBGFR3StackWalkBeginGuestEx, DBGFR3StackWalkBeginHyperEx,
415 * DBGFR3StackWalkBeginGuest and DBGFR3StackWalkBeginHyper.
416 */
417static int dbgfR3StackWalkBeginCommon(PVM pVM,
418 VMCPUID idCpu,
419 DBGFCODETYPE enmCodeType,
420 PCDBGFADDRESS pAddrFrame,
421 PCDBGFADDRESS pAddrStack,
422 PCDBGFADDRESS pAddrPC,
423 DBGFRETURNTYPE enmReturnType,
424 PCDBGFSTACKFRAME *ppFirstFrame)
425{
426 /*
427 * Validate parameters.
428 */
429 *ppFirstFrame = NULL;
430 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
431 AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
432 if (pAddrFrame)
433 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrFrame), VERR_INVALID_PARAMETER);
434 if (pAddrStack)
435 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrStack), VERR_INVALID_PARAMETER);
436 if (pAddrPC)
437 AssertReturn(DBGFR3AddrIsValid(pVM, pAddrPC), VERR_INVALID_PARAMETER);
438 AssertReturn(enmReturnType >= DBGFRETURNTYPE_INVALID && enmReturnType < DBGFRETURNTYPE_END, VERR_INVALID_PARAMETER);
439
440 /*
441 * Get the CPUM context pointer and pass it on the specified EMT.
442 */
443 RTDBGAS hAs;
444 PCCPUMCTXCORE pCtxCore;
445 switch (enmCodeType)
446 {
447 case DBGFCODETYPE_GUEST:
448 pCtxCore = CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu));
449 hAs = DBGF_AS_GLOBAL;
450 break;
451 case DBGFCODETYPE_HYPER:
452 pCtxCore = CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu));
453 hAs = DBGF_AS_RC_AND_GC_GLOBAL;
454 break;
455 case DBGFCODETYPE_RING0:
456 pCtxCore = NULL; /* No valid context present. */
457 hAs = DBGF_AS_R0;
458 break;
459 default:
460 AssertFailedReturn(VERR_INVALID_PARAMETER);
461 }
462 return VMR3ReqPriorityCallWait(pVM, idCpu, (PFNRT)dbgfR3StackWalkCtxFull, 10,
463 pVM, idCpu, pCtxCore, hAs, enmCodeType,
464 pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
465}
466
467
468/**
469 * Begins a guest stack walk, extended version.
470 *
471 * This will walk the current stack, constructing a list of info frames which is
472 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
473 * list and DBGFR3StackWalkEnd to release it.
474 *
475 * @returns VINF_SUCCESS on success.
476 * @returns VERR_NO_MEMORY if we're out of memory.
477 *
478 * @param pVM Pointer to the VM.
479 * @param idCpu The ID of the virtual CPU which stack we want to walk.
480 * @param enmCodeType Code type
481 * @param pAddrFrame Frame address to start at. (Optional)
482 * @param pAddrStack Stack address to start at. (Optional)
483 * @param pAddrPC Program counter to start at. (Optional)
484 * @param enmReturnType The return address type. (Optional)
485 * @param ppFirstFrame Where to return the pointer to the first info frame.
486 */
487VMMR3DECL(int) DBGFR3StackWalkBeginEx(PVM pVM,
488 VMCPUID idCpu,
489 DBGFCODETYPE enmCodeType,
490 PCDBGFADDRESS pAddrFrame,
491 PCDBGFADDRESS pAddrStack,
492 PCDBGFADDRESS pAddrPC,
493 DBGFRETURNTYPE enmReturnType,
494 PCDBGFSTACKFRAME *ppFirstFrame)
495{
496 return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
497}
498
499
500/**
501 * Begins a guest stack walk.
502 *
503 * This will walk the current stack, constructing a list of info frames which is
504 * returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
505 * list and DBGFR3StackWalkEnd to release it.
506 *
507 * @returns VINF_SUCCESS on success.
508 * @returns VERR_NO_MEMORY if we're out of memory.
509 *
510 * @param pVM Pointer to the VM.
511 * @param idCpu The ID of the virtual CPU which stack we want to walk.
512 * @param enmCodeType Code type
513 * @param ppFirstFrame Where to return the pointer to the first info frame.
514 */
515VMMR3DECL(int) DBGFR3StackWalkBegin(PVM pVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFSTACKFRAME *ppFirstFrame)
516{
517 return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, NULL, NULL, NULL, DBGFRETURNTYPE_INVALID, ppFirstFrame);
518}
519
520/**
521 * Gets the next stack frame.
522 *
523 * @returns Pointer to the info for the next stack frame.
524 * NULL if no more frames.
525 *
526 * @param pCurrent Pointer to the current stack frame.
527 *
528 */
529VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent)
530{
531 return pCurrent
532 ? pCurrent->pNextInternal
533 : NULL;
534}
535
536
537/**
538 * Ends a stack walk process.
539 *
540 * This *must* be called after a successful first call to any of the stack
541 * walker functions. If not called we will leak memory or other resources.
542 *
543 * @param pFirstFrame The frame returned by one of the begin functions.
544 */
545VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame)
546{
547 if ( !pFirstFrame
548 || !pFirstFrame->pFirstInternal)
549 return;
550
551 PDBGFSTACKFRAME pFrame = (PDBGFSTACKFRAME)pFirstFrame->pFirstInternal;
552 while (pFrame)
553 {
554 PDBGFSTACKFRAME pCur = pFrame;
555 pFrame = (PDBGFSTACKFRAME)pCur->pNextInternal;
556 if (pFrame)
557 {
558 if (pCur->pSymReturnPC == pFrame->pSymPC)
559 pFrame->pSymPC = NULL;
560 if (pCur->pSymReturnPC == pFrame->pSymReturnPC)
561 pFrame->pSymReturnPC = NULL;
562
563 if (pCur->pSymPC == pFrame->pSymPC)
564 pFrame->pSymPC = NULL;
565 if (pCur->pSymPC == pFrame->pSymReturnPC)
566 pFrame->pSymReturnPC = NULL;
567
568 if (pCur->pLineReturnPC == pFrame->pLinePC)
569 pFrame->pLinePC = NULL;
570 if (pCur->pLineReturnPC == pFrame->pLineReturnPC)
571 pFrame->pLineReturnPC = NULL;
572
573 if (pCur->pLinePC == pFrame->pLinePC)
574 pFrame->pLinePC = NULL;
575 if (pCur->pLinePC == pFrame->pLineReturnPC)
576 pFrame->pLineReturnPC = NULL;
577 }
578
579 RTDbgSymbolFree(pCur->pSymPC);
580 RTDbgSymbolFree(pCur->pSymReturnPC);
581 DBGFR3LineFree(pCur->pLinePC);
582 DBGFR3LineFree(pCur->pLineReturnPC);
583
584 pCur->pNextInternal = NULL;
585 pCur->pFirstInternal = NULL;
586 pCur->fFlags = 0;
587 MMR3HeapFree(pCur);
588 }
589}
590
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