1
/* $Id: DBGFStack.cpp $ */
3
* DBGF - Debugger Facility, Call Stack Analyser.
7
* Copyright (C) 2006-2007 Oracle Corporation
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.
19
/*******************************************************************************
21
*******************************************************************************/
22
#define LOG_GROUP LOG_GROUP_DBGF
23
#include <VBox/dbgf.h>
24
#include <VBox/selm.h>
26
#include "DBGFInternal.h"
30
#include <iprt/param.h>
31
#include <iprt/assert.h>
32
#include <iprt/string.h>
33
#include <iprt/alloca.h>
40
DECLINLINE(int) dbgfR3Read(PVM pVM, VMCPUID idCpu, void *pvBuf, PCDBGFADDRESS pSrcAddr, size_t cb, size_t *pcbRead)
42
int rc = DBGFR3MemRead(pVM, idCpu, pSrcAddr, pvBuf, cb);
45
/* fallback: byte by byte and zero the ones we fail to read. */
47
for (cbRead = 0; cbRead < cb; cbRead++)
49
DBGFADDRESS Addr = *pSrcAddr;
50
rc = DBGFR3MemRead(pVM, idCpu, DBGFR3AddrAdd(&Addr, cbRead), (uint8_t *)pvBuf + cbRead, 1);
56
memset((char *)pvBuf + cbRead, 0, cb - cbRead);
66
* Internal worker routine.
68
* On x86 the typical stack frame layout is like this:
74
* 0 old ebp; current ebp points here
76
* @todo Add AMD64 support (needs teaming up with the module management for
79
static int dbgfR3StackWalk(PVM pVM, VMCPUID idCpu, RTDBGAS hAs, PDBGFSTACKFRAME pFrame)
82
* Stop if we got a read error in the previous run.
84
if (pFrame->fFlags & DBGFSTACKFRAME_FLAGS_LAST)
85
return VERR_NO_MORE_FILES;
88
* Read the raw frame data.
90
const DBGFADDRESS AddrOldPC = pFrame->AddrPC;
91
const unsigned cbRetAddr = DBGFReturnTypeSize(pFrame->enmReturnType);
93
switch (AddrOldPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
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;
100
switch (pFrame->enmReturnType)
102
case DBGFRETURNTYPE_FAR16:
103
case DBGFRETURNTYPE_IRET16:
104
case DBGFRETURNTYPE_IRET32_V86:
105
case DBGFRETURNTYPE_NEAR16: cbStackItem = 2; break;
107
case DBGFRETURNTYPE_FAR32:
108
case DBGFRETURNTYPE_IRET32:
109
case DBGFRETURNTYPE_IRET32_PRIV:
110
case DBGFRETURNTYPE_NEAR32: cbStackItem = 4; break;
112
case DBGFRETURNTYPE_FAR64:
113
case DBGFRETURNTYPE_IRET64:
114
case DBGFRETURNTYPE_NEAR64: cbStackItem = 8; break;
117
AssertMsgFailed(("%d\n", pFrame->enmReturnType));
130
} u, uRet, uArgs, uBp;
131
size_t cbRead = cbRetAddr + cbStackItem + sizeof(pFrame->Args);
132
u.pv = alloca(cbRead);
134
uRet.pb = u.pb + cbStackItem;
135
uArgs.pb = u.pb + cbStackItem + cbRetAddr;
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,
144
|| cbRead < cbRetAddr + cbStackItem)
145
pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_LAST;
148
* The first step is taken in a different way than the others.
150
if (!(pFrame->fFlags & DBGFSTACKFRAME_FLAGS_ALL_VALID))
152
pFrame->fFlags |= DBGFSTACKFRAME_FLAGS_ALL_VALID;
155
/* Current PC - set by caller, just find symbol & line. */
156
if (DBGFADDRESS_IS_VALID(&pFrame->AddrPC))
158
pFrame->pSymPC = DBGFR3AsSymbolByAddrA(pVM, hAs, &pFrame->AddrPC, NULL /*offDisp*/, NULL /*phMod*/);
159
pFrame->pLinePC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrPC.FlatPtr, NULL);
162
else /* 2nd and subsequent steps */
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;
170
/* increment the frame number. */
175
* Return Frame address.
177
pFrame->AddrReturnFrame = pFrame->AddrFrame;
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: AssertMsgFailed(("cbStackItem=%d\n", cbStackItem)); return VERR_INTERNAL_ERROR;
185
pFrame->AddrReturnFrame.FlatPtr += pFrame->AddrReturnFrame.off - pFrame->AddrFrame.off;
188
* Return PC and Stack Addresses.
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;
195
pFrame->AddrReturnPC = pFrame->AddrPC;
196
switch (pFrame->enmReturnType)
198
case DBGFRETURNTYPE_NEAR16:
199
if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
201
pFrame->AddrReturnPC.FlatPtr += *uRet.pu16 - pFrame->AddrReturnPC.off;
202
pFrame->AddrReturnPC.off = *uRet.pu16;
205
DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu16);
207
case DBGFRETURNTYPE_NEAR32:
208
if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
210
pFrame->AddrReturnPC.FlatPtr += *uRet.pu32 - pFrame->AddrReturnPC.off;
211
pFrame->AddrReturnPC.off = *uRet.pu32;
214
DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu32);
216
case DBGFRETURNTYPE_NEAR64:
217
if (DBGFADDRESS_IS_VALID(&pFrame->AddrReturnPC))
219
pFrame->AddrReturnPC.FlatPtr += *uRet.pu64 - pFrame->AddrReturnPC.off;
220
pFrame->AddrReturnPC.off = *uRet.pu64;
223
DBGFR3AddrFromFlat(pVM, &pFrame->AddrReturnPC, *uRet.pu64);
225
case DBGFRETURNTYPE_FAR16:
226
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
228
case DBGFRETURNTYPE_FAR32:
229
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
231
case DBGFRETURNTYPE_FAR64:
232
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
234
case DBGFRETURNTYPE_IRET16:
235
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[1], uRet.pu16[0]);
237
case DBGFRETURNTYPE_IRET32:
238
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
240
case DBGFRETURNTYPE_IRET32_PRIV:
241
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
243
case DBGFRETURNTYPE_IRET32_V86:
244
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[2], uRet.pu32[0]);
246
case DBGFRETURNTYPE_IRET64:
247
DBGFR3AddrFromSelOff(pVM, idCpu, &pFrame->AddrReturnPC, uRet.pu16[4], uRet.pu64[0]);
250
AssertMsgFailed(("enmReturnType=%d\n", pFrame->enmReturnType));
251
return VERR_INVALID_PARAMETER;
254
pFrame->pSymReturnPC = DBGFR3AsSymbolByAddrA(pVM, hAs, &pFrame->AddrReturnPC, NULL /*offDisp*/, NULL /*phMod*/);
255
pFrame->pLineReturnPC = DBGFR3LineByAddrAlloc(pVM, pFrame->AddrReturnPC.FlatPtr, NULL);
258
* Frame bitness flag.
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: AssertMsgFailed(("cbStackItem=%d\n", cbStackItem)); return VERR_INTERNAL_ERROR;
271
memcpy(&pFrame->Args, uArgs.pv, sizeof(pFrame->Args));
278
* Walks the entire stack allocating memory as we walk.
280
static 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)
288
/* alloc first frame. */
289
PDBGFSTACKFRAME pCur = (PDBGFSTACKFRAME)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_STACK, sizeof(*pCur));
291
return VERR_NO_MEMORY;
294
* Initialize the frame.
296
pCur->pNextInternal = NULL;
297
pCur->pFirstInternal = pCur;
299
int rc = VINF_SUCCESS;
301
pCur->AddrPC = *pAddrPC;
303
rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrPC, pCtxCore->cs, pCtxCore->rip);
306
if (enmReturnType == DBGFRETURNTYPE_INVALID)
307
switch (pCur->AddrPC.fFlags & DBGFADDRESS_FLAGS_TYPE_MASK)
309
case DBGFADDRESS_FLAGS_FAR16: pCur->enmReturnType = DBGFRETURNTYPE_NEAR16; break;
310
case DBGFADDRESS_FLAGS_FAR32: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break;
311
case DBGFADDRESS_FLAGS_FAR64: pCur->enmReturnType = DBGFRETURNTYPE_NEAR64; break;
312
case DBGFADDRESS_FLAGS_RING0: pCur->enmReturnType = HC_ARCH_BITS == 64 ? DBGFRETURNTYPE_NEAR64 : DBGFRETURNTYPE_NEAR32; break;
313
default: pCur->enmReturnType = DBGFRETURNTYPE_NEAR32; break; /// @todo 64-bit guests
317
if (enmCodeType == DBGFCODETYPE_RING0)
318
fAddrMask = HC_ARCH_BITS == 64 ? UINT64_MAX : UINT32_MAX;
319
else if (enmCodeType == DBGFCODETYPE_HYPER)
320
fAddrMask = UINT32_MAX;
321
else if (DBGFADDRESS_IS_FAR16(&pCur->AddrPC))
322
fAddrMask = UINT16_MAX;
323
else if (DBGFADDRESS_IS_FAR32(&pCur->AddrPC))
324
fAddrMask = UINT32_MAX;
325
else if (DBGFADDRESS_IS_FAR64(&pCur->AddrPC))
326
fAddrMask = UINT64_MAX;
329
PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu);
330
CPUMMODE CpuMode = CPUMGetGuestMode(pVCpu);
331
if (CpuMode == CPUMMODE_REAL)
332
fAddrMask = UINT16_MAX;
333
else if ( CpuMode == CPUMMODE_PROTECTED
334
|| !CPUMIsGuestIn64BitCode(pVCpu, pCtxCore))
335
fAddrMask = UINT32_MAX;
337
fAddrMask = UINT64_MAX;
341
pCur->AddrStack = *pAddrStack;
343
rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrStack, pCtxCore->ss, pCtxCore->rsp & fAddrMask);
346
pCur->AddrFrame = *pAddrFrame;
347
else if (RT_SUCCESS(rc))
348
rc = DBGFR3AddrFromSelOff(pVM, idCpu, &pCur->AddrFrame, pCtxCore->ss, pCtxCore->rbp & fAddrMask);
351
pCur->enmReturnType = enmReturnType;
357
rc = dbgfR3StackWalk(pVM, idCpu, hAs, pCur);
360
DBGFR3StackWalkEnd(pCur);
367
DBGFSTACKFRAME Next = *pCur;
368
while (!(pCur->fFlags & (DBGFSTACKFRAME_FLAGS_LAST | DBGFSTACKFRAME_FLAGS_MAX_DEPTH | DBGFSTACKFRAME_FLAGS_LOOP)))
371
rc = dbgfR3StackWalk(pVM, idCpu, hAs, &Next);
375
/* add the next frame to the chain. */
376
PDBGFSTACKFRAME pNext = (PDBGFSTACKFRAME)MMR3HeapAlloc(pVM, MM_TAG_DBGF_STACK, sizeof(*pNext));
379
DBGFR3StackWalkEnd(pCur);
380
return VERR_NO_MEMORY;
383
pCur->pNextInternal = pNext;
385
Assert(pCur->pNextInternal == NULL);
388
for (PCDBGFSTACKFRAME pLoop = pCur->pFirstInternal;
389
pLoop && pLoop != pCur;
390
pLoop = pLoop->pNextInternal)
391
if (pLoop->AddrFrame.FlatPtr == pCur->AddrFrame.FlatPtr)
393
pCur->fFlags |= DBGFSTACKFRAME_FLAGS_LOOP;
397
/* check for insane recursion */
398
if (pCur->iFrame >= 2048)
399
pCur->fFlags |= DBGFSTACKFRAME_FLAGS_MAX_DEPTH;
402
*ppFirstFrame = pCur->pFirstInternal;
408
* Common worker for DBGFR3StackWalkBeginGuestEx, DBGFR3StackWalkBeginHyperEx,
409
* DBGFR3StackWalkBeginGuest and DBGFR3StackWalkBeginHyper.
411
static int dbgfR3StackWalkBeginCommon(PVM pVM,
413
DBGFCODETYPE enmCodeType,
414
PCDBGFADDRESS pAddrFrame,
415
PCDBGFADDRESS pAddrStack,
416
PCDBGFADDRESS pAddrPC,
417
DBGFRETURNTYPE enmReturnType,
418
PCDBGFSTACKFRAME *ppFirstFrame)
421
* Validate parameters.
423
*ppFirstFrame = NULL;
424
VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
425
AssertReturn(idCpu < pVM->cCpus, VERR_INVALID_CPU_ID);
427
AssertReturn(DBGFR3AddrIsValid(pVM, pAddrFrame), VERR_INVALID_PARAMETER);
429
AssertReturn(DBGFR3AddrIsValid(pVM, pAddrStack), VERR_INVALID_PARAMETER);
431
AssertReturn(DBGFR3AddrIsValid(pVM, pAddrPC), VERR_INVALID_PARAMETER);
432
AssertReturn(enmReturnType >= DBGFRETURNTYPE_INVALID && enmReturnType < DBGFRETURNTYPE_END, VERR_INVALID_PARAMETER);
435
* Get the CPUM context pointer and pass it on the specified EMT.
438
PCCPUMCTXCORE pCtxCore;
441
case DBGFCODETYPE_GUEST:
442
pCtxCore = CPUMGetGuestCtxCore(VMMGetCpuById(pVM, idCpu));
443
hAs = DBGF_AS_GLOBAL;
445
case DBGFCODETYPE_HYPER:
446
pCtxCore = CPUMGetHyperCtxCore(VMMGetCpuById(pVM, idCpu));
447
hAs = DBGF_AS_RC_AND_GC_GLOBAL;
449
case DBGFCODETYPE_RING0:
450
pCtxCore = NULL; /* No valid context present. */
454
AssertFailedReturn(VERR_INVALID_PARAMETER);
456
return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3StackWalkCtxFull, 10,
457
pVM, idCpu, pCtxCore, hAs, enmCodeType,
458
pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
463
* Begins a guest stack walk, extended version.
465
* This will walk the current stack, constructing a list of info frames which is
466
* returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
467
* list and DBGFR3StackWalkEnd to release it.
469
* @returns VINF_SUCCESS on success.
470
* @returns VERR_NO_MEMORY if we're out of memory.
472
* @param pVM The VM handle.
473
* @param idCpu The ID of the virtual CPU which stack we want to walk.
474
* @param enmCodeType Code type
475
* @param pAddrFrame Frame address to start at. (Optional)
476
* @param pAddrStack Stack address to start at. (Optional)
477
* @param pAddrPC Program counter to start at. (Optional)
478
* @param enmReturnType The return address type. (Optional)
479
* @param ppFirstFrame Where to return the pointer to the first info frame.
481
VMMR3DECL(int) DBGFR3StackWalkBeginEx(PVM pVM,
483
DBGFCODETYPE enmCodeType,
484
PCDBGFADDRESS pAddrFrame,
485
PCDBGFADDRESS pAddrStack,
486
PCDBGFADDRESS pAddrPC,
487
DBGFRETURNTYPE enmReturnType,
488
PCDBGFSTACKFRAME *ppFirstFrame)
490
return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, pAddrFrame, pAddrStack, pAddrPC, enmReturnType, ppFirstFrame);
495
* Begins a guest stack walk.
497
* This will walk the current stack, constructing a list of info frames which is
498
* returned to the caller. The caller uses DBGFR3StackWalkNext to traverse the
499
* list and DBGFR3StackWalkEnd to release it.
501
* @returns VINF_SUCCESS on success.
502
* @returns VERR_NO_MEMORY if we're out of memory.
504
* @param pVM The VM handle.
505
* @param idCpu The ID of the virtual CPU which stack we want to walk.
506
* @param enmCodeType Code type
507
* @param ppFirstFrame Where to return the pointer to the first info frame.
509
VMMR3DECL(int) DBGFR3StackWalkBegin(PVM pVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFSTACKFRAME *ppFirstFrame)
511
return dbgfR3StackWalkBeginCommon(pVM, idCpu, enmCodeType, NULL, NULL, NULL, DBGFRETURNTYPE_INVALID, ppFirstFrame);
515
* Gets the next stack frame.
517
* @returns Pointer to the info for the next stack frame.
518
* NULL if no more frames.
520
* @param pCurrent Pointer to the current stack frame.
523
VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent)
526
? pCurrent->pNextInternal
532
* Ends a stack walk process.
534
* This *must* be called after a successful first call to any of the stack
535
* walker functions. If not called we will leak memory or other resources.
537
* @param pFirstFrame The frame returned by one of the the begin
540
VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame)
543
|| !pFirstFrame->pFirstInternal)
546
PDBGFSTACKFRAME pFrame = (PDBGFSTACKFRAME)pFirstFrame->pFirstInternal;
549
PDBGFSTACKFRAME pCur = pFrame;
550
pFrame = (PDBGFSTACKFRAME)pCur->pNextInternal;
553
if (pCur->pSymReturnPC == pFrame->pSymPC)
554
pFrame->pSymPC = NULL;
555
if (pCur->pSymReturnPC == pFrame->pSymReturnPC)
556
pFrame->pSymReturnPC = NULL;
558
if (pCur->pSymPC == pFrame->pSymPC)
559
pFrame->pSymPC = NULL;
560
if (pCur->pSymPC == pFrame->pSymReturnPC)
561
pFrame->pSymReturnPC = NULL;
563
if (pCur->pLineReturnPC == pFrame->pLinePC)
564
pFrame->pLinePC = NULL;
565
if (pCur->pLineReturnPC == pFrame->pLineReturnPC)
566
pFrame->pLineReturnPC = NULL;
568
if (pCur->pLinePC == pFrame->pLinePC)
569
pFrame->pLinePC = NULL;
570
if (pCur->pLinePC == pFrame->pLineReturnPC)
571
pFrame->pLineReturnPC = NULL;
574
RTDbgSymbolFree(pCur->pSymPC);
575
RTDbgSymbolFree(pCur->pSymReturnPC);
576
DBGFR3LineFree(pCur->pLinePC);
577
DBGFR3LineFree(pCur->pLineReturnPC);
579
pCur->pNextInternal = NULL;
580
pCur->pFirstInternal = NULL;