VirtualBox

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

Last change on this file since 60380 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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