VirtualBox

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

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

DBGFStack: Take odd saved BP as a hint of far returns.

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