Windows2000/private/windbg64/windbg/callswin.c
2020-09-30 17:12:32 +02:00

2196 lines
62 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
callswin.c
Abstract:
This module contains the main line code for display of calls window.
Author:
Wesley Witt (wesw) 6-Sep-1993
Environment:
Win32, User Mode
--*/
#include "precomp.h"
#pragma hdrstop
#include "include\cntxthlp.h"
extern CXF CxfIp;
extern LPSHF Lpshf;
// Magic values found in reserved fields of STACKFRAME
#define SAVE_EBP(f) f.Reserved[0]
#define TRAP_TSS(f) f.Reserved[1]
#define TRAP_EDITED(f) f.Reserved[1]
#define SAVE_TRAP(f) f.Reserved[2]
#define ADDREQ(a,b) ((a).Offset == (b).Offset && \
(a).Segment == (b).Segment && \
(a).Mode == (b).Mode )
#ifndef NEW_WINDOWING_CODE
HWND hWndCalls;
#endif
DWORD FrameCountSave;
STACKFRAME stkFrameSave;
STACKINFO StackInfo[MAX_FRAMES];
DWORD FrameCount;
HWND hwndList;
int myView;
HFONT hFontList;
HBRUSH hbrBackground;
extern LPPD LppdCommand;
extern LPTD LptdCommand;
extern HWND GetLocalHWND(void);
VOID FillStackFrameWindow(HWND hwndList, BOOL fRefresh);
#if !defined( NEW_WINDOWING_CODELONG )
LONG CreateCallsWindow(HWND hWnd, WPARAM wParam, LPARAM lParam);
#endif
void FormatStackFrameString(LPSTR lsz, DWORD cb, const STACKINFO * const si, DWORD width);
BOOL GoUntilStackFrame(LPSTACKINFO si);
VOID BuildStackInfo(LPSTACKINFO si, LPSTACKFRAME stkFrame, int frameNum, HPID hpid, HTID vhtid, BOOL fFull);
HTID WalkToFrame(HPID hpid, HTID htid, int iCall);
HWND GetCallsHWND(VOID)
/*++
Routine Description:
Helper function that returns the window handle for the calls window.
Return Value:
HWND for the calls window, or NULL if the window is closed.
--*/
{
#ifdef NEW_WINDOWING_CODE
return(g_DebuggerWindows.hwndCalls);
#else
return(hWndCalls);
#endif
}
BOOL IsCallsInFocus(VOID)
/*++
Routine Description:
Determines whether the calls window is in focus.
Return Value:
TRUE - the calls window is in focus
FALSE - the calls window is not in focus
--*/
{
HWND hwndFocus = GetFocus();
if (hwndFocus == GetCallsHWND() || hwndFocus == hwndList) {
return TRUE;
}
return FALSE;
}
#ifdef NEW_WINDOWING_CODE
LRESULT
CALLBACK
NewCalls_WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT lbItem;
PCALLSWIN_DATA pCallsWinData = GetCallsWinData(hwnd);
switch (uMsg) {
case WM_CREATE:
{
RECT rc;
Assert(NULL == pCallsWinData);
pCallsWinData = new CALLSWIN_DATA;
if (!pCallsWinData) {
return -1; // Fail window creation
}
pCallsWinData->hwndList = CreateWindowEx(
0, // Extended style
"LISTBOX", // class name
NULL, // title
WS_CHILD | WS_VISIBLE
| WS_MAXIMIZE
| WS_HSCROLL | WS_VSCROLL
| LBS_NOTIFY | LBS_WANTKEYBOARDINPUT
| LBS_DISABLENOSCROLL, // style
0, // x
0, // y
CW_USEDEFAULT, // width
CW_USEDEFAULT, // height
hwnd, // parent
(HMENU) IDC_LIST_CALLS, // control id
g_hInst, // hInstance
NULL); // user defined data
if (!pCallsWinData->hwndList) {
delete pCallsWinData;
return -1; // Fail window creation
}
g_DebuggerWindows.hwndCalls = hwnd;
// store this in the window
SetCallsWinData(hwnd, pCallsWinData);
}
memset( &stkFrameSave.AddrFrame, 0, sizeof(ADDRESS) );
memset( &stkFrameSave.AddrReturn, 0, sizeof(ADDRESS) );
return 0;
case WM_COMMAND:
if (HIWORD(wParam) == LBN_DBLCLK) {
lbItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
if (LB_ERR != lbItem) {
GotoFrame( (int) lbItem, TRUE ); // User activated
}
}
if (LOWORD(wParam) == IDM_DEBUG_RUNTOCURSOR) {
lbItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
if (LB_ERR != lbItem) {
if (!GoUntilStackFrame( &StackInfo[lbItem] )) {
MessageBeep( MB_OK );
}
}
}
break;
case WM_VKEYTOITEM:
if (LOWORD(wParam) == VK_RETURN) {
lbItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
if (LB_ERR != lbItem) {
// User activated
GotoFrame( (int) lbItem, TRUE );
}
} else if ('G' == LOWORD(wParam)) {
lbItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
if (LB_ERR != lbItem) {
if (!GoUntilStackFrame( &StackInfo[lbItem] )) {
MessageBeep( MB_OK );
}
}
} else if ('R' == LOWORD(wParam)) {
FillStackFrameWindow( hwndList, TRUE );
}
break;
case WU_OPTIONS:
FillStackFrameWindow( hwndList, TRUE );
return TRUE;
case WU_UPDATE:
FillStackFrameWindow( hwndList, TRUE );
return TRUE;
case WU_INFO:
return TRUE;
case WU_DBG_LOADEM:
return TRUE;
case WU_DBG_LOADEE:
return TRUE;
case WU_SETWATCH:
return TRUE;
case WU_AUTORUN:
return TRUE;
case WU_DBG_UNLOADEE:
case WU_DBG_UNLOADEM:
case WU_INVALIDATE:
SendMessage( hwndList, LB_RESETCONTENT, 0, 0 );
FrameCount = 0;
return FALSE;
case WM_SETFONT:
//SendMessage( hwndList, WM_SETFONT, (WPARAM)hFontList, (LPARAM)FALSE );
//InvalidateRect(hwndList, NULL, TRUE);
//InvalidateRect(hwnd, NULL, TRUE);
//FillStackFrameWindow( hwndList, TRUE );
return TRUE;
case WU_CLR_BACKCHANGE:
DeleteObject( hbrBackground );
hbrBackground = CreateSolidBrush( StringColors[CallsWindow].BkgndColor);
return TRUE;
case WU_CLR_FORECHANGE:
return TRUE;
case WM_CTLCOLORLISTBOX:
SetBkColor( (HDC)wParam, StringColors[CallsWindow].BkgndColor );
SetTextColor( (HDC)wParam, StringColors[CallsWindow].FgndColor);
return (LRESULT)(hbrBackground);
case WM_DESTROY:
DeleteObject( hbrBackground );
DeleteWindowMenuItem (myView);
g_DebuggerWindows.hwndCalls = NULL;
FrameCount = 0;
hwndList = NULL;
break;
}
return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
}
#else //NEW_WINDOWING_CODE
LRESULT
CallsWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
Window procedure for the calls stack window.
Arguments:
hwnd - window handle
msg - message number
wParam - first message parameter
lParam - second message parameter
Return Value:
TRUE - did not process the message
FALSE - did process the message
--*/
{
DWORD_PTR lbItem;
RECT cRect;
LPCHOOSEFONT cf;
switch (msg)
{
case WM_CREATE:
memset(&stkFrameSave.AddrFrame, 0, sizeof(ADDRESS));
memset(&stkFrameSave.AddrReturn, 0, sizeof(ADDRESS));
return CreateCallsWindow(hwnd, wParam, lParam);
case WM_MDIACTIVATE:
if (hwnd == (HWND) lParam) {
hwndActive = hwnd;
hwndActiveEdit = hwnd;
curView = myView;
EnableToolbarControls();
}
else {
hwndActive = NULL;
hwndActiveEdit = NULL;
curView = -1;
}
break;
case WM_MOUSEACTIVATE:
return MA_ACTIVATE;
case WM_WINDOWPOSCHANGED:
if (((LPWINDOWPOS) lParam)->flags & SWP_NOSIZE) {
break;
}
GetClientRect(hwnd, &cRect);
MoveWindow(hwndList,
0,
0,
cRect.right - cRect.left,
cRect.bottom - cRect.top,
TRUE
);
FillStackFrameWindow(hwndList, FALSE);
break;
case WM_SETFOCUS:
SetFocus(hwndList);
return 0;
case WM_COMMAND:
if (HIWORD(wParam) == LBN_DBLCLK) {
lbItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
// User activated
GotoFrame((int) lbItem, TRUE);
}
if (LOWORD(wParam) == IDM_DEBUG_RUNTOCURSOR) {
lbItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
if (!GoUntilStackFrame(&StackInfo[lbItem])) {
MessageBeep(MB_OK);
}
}
break;
case WM_VKEYTOITEM:
if (LOWORD(wParam) == VK_RETURN) {
lbItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
// User activated
GotoFrame((int) lbItem, TRUE);
}
else if ('G' == LOWORD(wParam)) {
lbItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
if (!GoUntilStackFrame(&StackInfo[lbItem])) {
MessageBeep(MB_OK);
}
}
else if ('R' == LOWORD(wParam)) {
FillStackFrameWindow(hwndList, TRUE);
}
break;
case WU_OPTIONS:
FillStackFrameWindow(hwndList, TRUE);
return TRUE;
case WU_UPDATE:
FillStackFrameWindow(hwndList, TRUE);
return TRUE;
case WU_INFO:
return TRUE;
case WU_DBG_LOADEM:
return TRUE;
case WU_DBG_LOADEE:
return TRUE;
case WU_SETWATCH:
return TRUE;
case WU_AUTORUN:
return TRUE;
case WU_DBG_UNLOADEE:
case WU_DBG_UNLOADEM:
case WU_INVALIDATE:
SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
FrameCount = 0;
return FALSE;
case WM_SETFONT:
cf = (LPCHOOSEFONT) lParam;
DeleteObject(hFontList);
hFontList = CreateFontIndirect(cf->lpLogFont);
Views[myView].font = hFontList;
SendMessage(hwndList, WM_SETFONT, (WPARAM) hFontList, (LPARAM) FALSE);
InvalidateRect(hwndList, NULL, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
FillStackFrameWindow(hwndList, TRUE);
return TRUE;
case WU_CLR_BACKCHANGE:
DeleteObject(hbrBackground);
hbrBackground = CreateSolidBrush(StringColors[CallsWindow].BkgndColor);
return TRUE;
case WU_CLR_FORECHANGE:
return TRUE;
case WM_CTLCOLORLISTBOX:
SetBkColor((HDC) wParam, StringColors[CallsWindow].BkgndColor);
SetTextColor((HDC) wParam, StringColors[CallsWindow].FgndColor);
return (LRESULT) (hbrBackground);
case WM_DESTROY:
DeleteObject(hbrBackground);
DeleteWindowMenuItem(myView);
Views[myView].Doc = -1;
hWndCalls = NULL;
FrameCount = 0;
hwndList = NULL;
break;
}
return DefMDIChildProc( hwnd, msg, wParam, lParam );
}
#endif // NEW_WINDOWING_CODE
VOID FillStackFrameWindow(HWND hwndList, BOOL fRefresh)
/*++
Routine Description:
This functions clears the calls stack window and fills it with the stack trace information contained in the StackInfo structure.
If the fRefresh flag is TRUE then the stack trace is refreshed.
Arguments:
hwndList - Window handle for the listbox that contains the call stack
fRefresh - TRUE - the stack trace should be refreshed
FALSE - the current stack trace is simply displayed
--*/
{
DWORD i;
char buf[1024*4];
HFONT hFont;
HDC hdc;
TEXTMETRIC tm;
DWORD width;
RECT rect;
DWORD_PTR lbItem;
SIZE size;
WPARAM cxExtent = 0;
i = g_contGlobalPreferences_WkSp.m_dwMaxFrames;
if (GetCompleteStackTrace( 0, 0, 0, StackInfo, &i, !fRefresh, TRUE )) {
FrameCount = i;
}
lbItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
SendMessage( hwndList, WM_SETREDRAW, FALSE, 0L );
SendMessage( hwndList, LB_RESETCONTENT, 0, 0 );
// get the text metrics for the font currently in use
hdc = GetDC( hwndList );
hFont = (HFONT)SendMessage( hwndList, WM_GETFONT, 0, 0 );
if (hFont != NULL) {
SelectObject( hdc, hFont );
}
GetTextMetrics( hdc, &tm );
// is it a fixed pitched font? (yes using not is correct!)
if (!(tm.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
// calculate the width of the listbox in characters
GetWindowRect( hwndList, &rect );
if (IsRectEmpty(&rect)) {
width = 0;
} else {
if (FrameCount > (DWORD)((rect.bottom - rect.top) / tm.tmHeight)) {
// there will be a vertical scroll bar in the listbox
// so we must subtract the width of the scroll bar
// from the width
width = (rect.right - rect.left - GetSystemMetrics(SM_CXVSCROLL) - 1)
/ tm.tmMaxCharWidth;
} else {
width = (rect.right - rect.left) / tm.tmMaxCharWidth;
}
}
} else {
width = 0;// zero says do not right justify the source info
}
for (i=0; i<FrameCount; i++) {
// format the string
FormatStackFrameString( buf, sizeof(buf), &StackInfo[i], width );
// get the width of the item
GetTextExtentPoint( hdc, buf, strlen(buf), &size );
if (size.cx > (LONG)cxExtent) {
cxExtent = size.cx;
}
// now lets add the data to the listbox
SendMessage( hwndList, LB_ADDSTRING, 0, (LPARAM) buf );
}
cxExtent = cxExtent + tm.tmMaxCharWidth;
if (g_contGlobalPreferences_WkSp.m_bHorzScrollBars) {
SendMessage( hwndList, LB_SETHORIZONTALEXTENT, cxExtent, 0L );
}
SendMessage( hwndList, LB_SETCURSEL, (lbItem>FrameCount)?0:lbItem, 0 );
SendMessage( hwndList, WM_SETREDRAW, TRUE, 0L );
ReleaseDC( hwndList, hdc );
return;
}
void
CreateAddress(
LPADDRESS64 lpaddress,
LPADDR lpaddr
)
/*++
Routine Description:
Helper function that transforms a LPADDRESS into a LPADDR. This is
necessary because DBGHELP and WINDBG do not use the same address
packet structures.
Arguments:
lpaddress - pointer to a source LPADDRESS structure
lpaddr - pointer to a destination LPADDR structure
Return Value:
None.
--*/
{
ZeroMemory( lpaddr, sizeof(*lpaddr) );
lpaddr->addr.off = lpaddress->Offset;
lpaddr->addr.seg = lpaddress->Segment;
lpaddr->mode.fFlat = lpaddress->Mode == AddrModeFlat;
lpaddr->mode.fOff32 = lpaddress->Mode == AddrMode1632;
lpaddr->mode.fReal = lpaddress->Mode == AddrModeReal;
OSDUnFixupAddr( LppdCur->hpid, LptdCur->htid, lpaddr );
}
void LoadSymbols(LPADDRESS64 lpaddress)
/*++
Routine Description:
Helper function that ensures that symbols are loaded for the address specified in the lpaddress argument.
Arguments:
lpaddress - pointer to a source LPADDRESS structure
--*/
{
ADDR addr;
CreateAddress( lpaddress, &addr );
if ( (HPID)emiAddr( addr ) == LppdCur->hpid ) {
// Get right EMI and load symbols if defered
emiAddr( addr ) = 0;
ADDR_IS_LI( addr ) = FALSE;
#ifdef OSDEBUG4
OSDSetEmi( LppdCur->hpid, LptdCur->htid, &addr );
#else
OSDPtrace( osdSetEmi, wNull, &addr, LppdCur->hpid, LptdCur->htid );
#endif
if ( (HPID)emiAddr( addr ) != LppdCur->hpid ) {
SHWantSymbols( (HEXE)emiAddr( addr ) );
}
}
}
VOID
GetSymbolFromAddr(
LPADDR lpaddr,
PHSYM lpsymbol,
LPDWORD lpclt,
LPBOOL lpfInProlog
)
/*++
Routine Description:
This function gets an HSYM for the address provided.
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
lpsymbol - The HSYM that receives the HSYM for lpaddr.
lpclt - Indicates the symbol type.
lpfInProlog - Is the address in the function prolog?
--*/
{
ADDR addrT;
HBLK hblk;
ADDR addr;
ADDR addr2;
CHAR rgch[256];
CXT cxt;
addr = *lpaddr;
addr2 = *lpaddr;
SYUnFixupAddr( &addr2 );
ZeroMemory( &cxt, sizeof ( CXT ) );
SHSetCxt( &addr, &cxt );
if (SHHPROCFrompCXT(&cxt)) {
*lpsymbol = (HSYM) SHHPROCFrompCXT ( &cxt );
*lpclt = cltProc;
SHAddrFromHsym( &addrT, *lpsymbol );
SetAddrOff( &addr, GetAddrOff(addrT) );
*lpfInProlog = SHIsInProlog( &cxt );
} else if (SHHBLKFrompCXT( &cxt )) {
hblk = SHHBLKFrompCXT( &cxt );
ZeroMemory( &addrT, sizeof ( ADDR ) );
SHAddrFromHsym( &addrT, (HSYM) hblk );
if (SHGetSymName((HSYM)hblk,rgch) != NULL ) {
*lpsymbol = (HSYM) hblk;
*lpclt = cltBlk;
} else {
*lpsymbol = (HSYM) NULL;
*lpclt = cltNone;
}
SetAddrOff( &addr, GetAddrOff ( addrT ) );
*lpfInProlog = FALSE;
} else
if ( PHGetNearestHsym( &addr2,
(HEXE)(SHpADDRFrompCXT( &cxt ) ->emi),
(PHSYM) lpsymbol ) < 0xFFFFFFFF ) {
ZeroMemory( &addrT, sizeof ( ADDR ) );
SHAddrFromHsym( &addrT, *lpsymbol );
*lpclt = cltPub;
SetAddrOff( &addr, GetAddrOff( addrT ) );
*lpfInProlog = FALSE;
} else {
*lpsymbol = (HSYM) NULL;
*lpclt = cltNone;
*lpfInProlog = FALSE;
}
}
VOID
GetContextString(
LPADDR lpaddr,
HSYM symbol,
DWORD clt,
LPSTR lpszContext
)
/*++
Routine Description:
This function formats a context string for the address provided.
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
symbol - The HSYM for lpaddr.
clt - Indicates the symbol type.
lpszContext - Buffer that receives the context string.
--*/
{
ADDR addrT;
ADDR addr;
HDEP hstr;
CXT cxt;
if (clt == cltNone) {
return;
}
if (symbol == 0) {
return;
}
addr = *lpaddr;
ZeroMemory( &cxt, sizeof(CXT) );
SHSetCxt( &addr, &cxt );
if (clt != cltNone) {
*SHpADDRFrompCXT( &cxt ) = addr;
} else {
*SHpADDRFrompCXT( &cxt ) = *lpaddr;
}
SHHMODFrompCXT( &cxt ) = SHHMODFrompCXT( &cxt );
if (clt == cltProc) {
SHAddrFromHsym( &addrT, symbol );
SetAddrOff( SHpADDRFrompCXT( &cxt ), GetAddrOff( addrT ) );
SHHPROCFrompCXT( &cxt ) = (HPROC) symbol;
} else if (clt == cltBlk) {
SHHBLKFrompCXT( &cxt ) = (HBLK) symbol;
}
EEFormatCXTFromPCXT( &cxt, &hstr, g_contWorkspace_WkSp.m_bShortContext );
if (g_contWorkspace_WkSp.m_bShortContext) {
strcpy( lpszContext, (LPSTR)MMLpvLockMb(hstr) );
} else {
BPShortenContext( (LPSTR)MMLpvLockMb(hstr), lpszContext );
}
MMbUnlockMb(hstr);
EEFreeStr(hstr);
}
VOID
GetDisplacement(
LPADDR lpaddr,
HSYM symbol,
ADDRESS64 addrPC,
PDWORDLONG lpqwDisplacement,
LPADDR lpProcAddr
)
/*++
Routine Description:
This function get the function address and the displacement that lpaddr is from the beginning of the function.
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
symbol - The HSYM for lpaddr.
addrPC - Current program counter that is used for the displacement
calculation.
lpdwDisplacement - Pointer to a DWORD that receives the displacement.
lpProcAddr - Pointer to an ADDR that receives the function address.
--*/
{
ADDR addr;
CXT cxt;
if (symbol == 0) {
return;
}
addr = *lpaddr;
ZeroMemory( &cxt, sizeof ( CXT ) );
SHSetCxt( &addr, &cxt );
addr = *SHpAddrFrompCxt( &cxt );
SHAddrFromHsym( &addr, symbol );
SYFixupAddr( &addr );
*lpProcAddr = addr;
SYUnFixupAddr( lpProcAddr );
*lpqwDisplacement = addrPC.Offset - GetAddrOff(addr);
}
VOID GetModuleName(LPADDR lpaddr, LPSTR lpszModule)
/*++
Routine Description:
This function get the module name for the lpaddr provided.
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
lpszModule - Buffer that receives the module name.
--*/
{
ADDR addr;
addr = *lpaddr;
SYFixupAddr( &addr );
SHGetModule( &addr, lpszModule );
CharUpper( lpszModule );
}
VOID GetFrameInfo(LPADDR lpaddr, ADDRESS64 AddrFrame, PCXF lpCxf, HTID vhtid)
/*++
Routine Description:
This function fills in the FRAME structure in the lpCxf passed in.
The FRAME information is used to position the debugger at a virtual frame for the purposes of examining the locals at that frame.
It is also used to evaluate an expression in the context of a previous stack frame.
Arguments:
lpaddr - Supplies an ADDR struct contining the address of the symbol.
AddrFrame - Supplies desired stack frame address.
lpCxf - Supplies pointer to a CXF structure that receives the FRAME.
vhtid - Supplies OSDebug handle for frame
--*/
{
ADDR addrData;
ADDR addrT;
addrT = *lpaddr;
SYFixupAddr( &addrT );
*SHpADDRFrompCXT(SHpCXTFrompCXF( lpCxf )) = addrT;
SHhFrameFrompCXF(lpCxf) = (HFRAME) vhtid;
if (!ADDR_IS_LI(addrT)) {
SYUnFixupAddr( &addrT );
}
SHSetCxt(&addrT, SHpCXTFrompCXF( lpCxf ));
}
VOID
GetFunctionName(
LPADDR lpaddr,
HSYM symbol,
LPSTR lpszProcName
)
/*++
Routine Description:
This function get the function name for the provided symbol.
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
symbol - The HSYM for lpaddr.
lpszProcName - Buffer that receives the function name.
--*/
{
if (symbol) {
SHGetSymName( symbol, lpszProcName );
} else {
sprintf( lpszProcName, "0x%016I64X", lpaddr->addr.off );
}
}
VOID
GetFunctionParameters(
LPADDR lpaddr,
HSYM symbol,
DWORD FrameNum,
LPSTR lpszParams,
CXF Cxf
)
/*++
Routine Description:
This function formats a string that represents the parameters to the function specified by symbol.
THIS FUNCTION SHOULD ONLY BE CALLED BY BuildStackInfo!
Arguments:
lpaddr - An ADDR struct contining the address of the symbol.
symbol - The HSYM for lpaddr.
FrameNum - Frame number (zero relative).
lpszParams - Buffer that receives the parameters string.
Cxf - Frame context. This must have been properly initialized
for the current stack frame.
--*/
{
ADDR addr;
CXT cxt;
HTM htm;
DWORD strIndex;
DWORD cParm = 0;
SHFLAG shflag = FALSE;
LPSTR p;
DWORD i;
HTM htmParm;
EEHSTR hName;
LPSTR lpch;
HFRAME hframe;
if (symbol == 0) {
return;
}
addr = *lpaddr;
ZeroMemory( &cxt, sizeof ( CXT ) );
SHSetCxt( &addr, &cxt );
if (EEGetTMFromHSYM( symbol, &cxt, &htm, &strIndex, TRUE, FALSE ) != EENOERROR) {
goto exit;
}
if (EEcParamTM( &htm, &cParm, &shflag ) != EENOERROR) {
goto exit;
}
p = lpszParams;
hframe = SHhFrameFrompCXF( &Cxf );
for ( i = 0; i < cParm; i++ ) {
if (EEGetParmTM( &htm, (EERADIX) i, &htmParm, &strIndex, FALSE ) == EENOERROR ) {
EEvaluateTM( &htmParm, hframe, EEVERTICAL );
if (EEGetValueFromTM( &htmParm, radix, (PEEFORMAT)"p", &hName ) == EENOERROR ) {
lpch = (PSTR) MMLpvLockMb ( hName );
memcpy ( p, lpch, strlen(lpch) );
p += strlen(lpch);
MMbUnlockMb ( hName );
EEFreeStr ( hName );
*p++ = ',';
*p++ = ' ';
}
EEFreeTM (&htmParm);
}
}
if (shflag) {
memcpy( p, "...", 3 );
p += 3;
}
while (( *( p - 1 ) == ' ' ) || ( *( p - 1 ) == ',' ) ) {
p--;
}
*p = '\0';
exit:
EEFreeTM ( &htm );
}
VOID
BuildStackInfo(
LPSTACKINFO si,
LPSTACKFRAME stkFrame,
int frameNum,
HPID hpid,
HTID vhtid,
BOOL fFull
)
/*++
Routine Description:
This function fills in the STACKINFO structure with all of the necessary information for a stack trace display.
THIS FUNCTION MUST BE CALLED WITH A VALID VHTID FROM OSDGetFrame.
Only the most recent call to OSDGetFrame is valid.
Arguments:
si - pointer to a STACKINFO structure
stkFrame
frameNum
hpid - valid HPID. Supplies process.
vhtid
fFull
--*/
{
HSYM symbol;
ADDR addr;
DWORD clt;
ZeroMemory( si, sizeof(STACKINFO));
si->StkFrame = *stkFrame;
si->FrameNum = frameNum;
// load symbols
LoadSymbols( &si->StkFrame.AddrPC );
LoadSymbols( &si->StkFrame.AddrReturn );
// fixup the address
CreateAddress( &si->StkFrame.AddrPC, &addr );
GetSymbolFromAddr( &addr, &symbol, &clt, &si->fInProlog );
if (fFull) {
GetContextString( &addr, symbol, clt, si->Context );
GetFunctionName( &addr, symbol, si->ProcName );
GetModuleName( &addr, si->Module );
// HACK: kcarlos - If SAPI did not load any symbols for this module
// then we use the module list to get the module name.
if (!*si->Module) {
// If SAPI did not load any symbols, the module name will be
// blank. Use the EM's module list to get the module name.
OSDGetModuleNameFromAddress(hpid,
addr.addr.off,
si->Module,
sizeof(si->Module)
);
}
}
GetDisplacement( &addr, symbol, si->StkFrame.AddrPC, &si->Displacement, &si->ProcAddr );
GetFrameInfo( &addr, si->StkFrame.AddrFrame, &si->Cxf, vhtid );
if (fFull) {
GetFunctionParameters( &addr, symbol, si->FrameNum, si->Params, si->Cxf );
}
}
BOOL
GotoFrame(
int iCall,
BOOL bUserActivated
)
/*++
Routine Description:
This function positions either the source window or the disassembly window to the address referenced by the STACKINFO structure that is indexed by iCall.
Arguments:
iCall - index of the desired STACKINFO structure
bUserActivated - Indicates whether this action was initiated by the user or by windbg. The value is to determine the Z order of any windows that are opened.
--*/
{
PCXF cxf = ChangeFrame(iCall);
if (!cxf) {
return FALSE;
}
if (!MoveEditorToAddr(SHpADDRFrompCXT(SHpCXTFrompCXF(cxf)), bUserActivated)) {
if (disasmView == -1) {
OpenDebugWindow(DISASM_WIN, bUserActivated);
}
ActivateMDIChild(Views[disasmView].hwndFrame, bUserActivated);
}
if (disasmView != -1) {
ViewDisasm(SHpADDRFrompCXT(SHpCXTFrompCXF(cxf)), disasmForce);
}
if ( GetLocalHWND() != 0) {
SendMessage(GetLocalHWND(), WU_UPDATE, (WPARAM)(LPSTR)cxf, 0L);
}
return TRUE;
}
void
OpenCallsWindow(
int type,
LPWININFO lpWinInfo,
int Preference,
BOOL bUserActivated
)
/*++
Routine Description:
This function opend a calls window.
Arguments:
type - window type (calls window)
lpWinInfo - initial window position
Preference - view index
bUserActivated - Indicates whether this action was initiated by the user or by windbg. The value is to determine the Z order of any windows that are opened.
--*/
{
WORD classId;
WORD winTitle;
HWND hWnd;
int view;
MDICREATESTRUCT mcs;
char szClass[MAX_MSG_TXT];
char title[MAX_MSG_TXT];
char final[MAX_MSG_TXT+4];
ZeroMemory(&mcs, sizeof(mcs));
classId = SYS_Calls_wClass;
winTitle = SYS_CallsWin_Title;
hWnd = GetCallsHWND();
if (hWnd) {
if (IsIconic(hWnd)) {
OpenIcon(hWnd);
}
ActivateMDIChild(hWnd, bUserActivated);
return;
}
// Determine which view index we are going to use
if ( (Preference != -1) && (Views[Preference].Doc == -1) ) {
view = Preference;
}
else {
for (view=0; (view<MAX_VIEWS)&&(Views[view].Doc!=-1); view++);
}
if (view == MAX_VIEWS) {
ErrorBox(ERR_Too_Many_Opened_Views);
return;
}
// Get the Window Title and Window Class
Dbg(LoadString(g_hInst, classId, szClass, MAX_MSG_TXT));
Dbg(LoadString(g_hInst, winTitle, title, MAX_MSG_TXT));
RemoveMnemonic(title,title);
sprintf(final,"%s", title);
// Make sure the Menu gets setup
AddWindowMenuItem(-type, view);
// Have MDI Client create the Child
mcs.szTitle = final;
mcs.szClass = szClass;
mcs.hOwner = g_hInst;
if (lpWinInfo) {
mcs.x = lpWinInfo->coord.left;
mcs.y = lpWinInfo->coord.top;
mcs.cx = lpWinInfo->coord.right - lpWinInfo->coord.left;
mcs.cy = lpWinInfo->coord.bottom - lpWinInfo->coord.top;
mcs.style = lpWinInfo->style;
} else {
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = 0;
}
mcs.style |= WS_VISIBLE;
if (hwndActive && ( IsZoomed(hwndActive) || IsZoomed(GetParent(hwndActive)) ) ) {
mcs.style |= WS_MAXIMIZE;
}
mcs.lParam = (ULONG) (type | (view << 16));
hWnd = (HWND) SendMessage(g_hwndMDIClient, WM_MDICREATE, 0, (LPARAM) &mcs);
SetWindowWord(hWnd, GWW_VIEW, (WORD)view);
Views[view].hwndFrame = hWnd;
Views[view].hwndClient = 0;
Views[view].NextView = -1; /* No next view */
Views[view].Doc = -type;
}
#if defined( NEW_WINDOWING_CODE )
HWND CreateWindow_NewCalls(HWND hwndParent)
/*++
Routine Description:
Create the command window.
Arguments:
hwndParent - The parent window to the command window. In an MDI document, this is usually the handle to the MDI client window: g_hwndMDIClient
Return Value:
If successful, creates a valid window handle to the new command window.
NULL if the window was not created.
--*/
{
char szClassName[MAX_MSG_TXT];
char szWinTitle[MAX_MSG_TXT];
CREATESTRUCT cs;
HWND hwnd;
// get class name
Dbg(LoadString(g_hInst, SYS_NewCalls_wClass, szClassName, sizeof(szClassName)));
// Get the title
{
char sz[MAX_MSG_TXT];
Dbg(LoadString(g_hInst, SYS_CmdWin_Title, sz, sizeof(sz)));
RemoveMnemonic(sz, szWinTitle);
}
ZeroMemory(&cs, sizeof(cs));
return CreateWindowEx(
WS_EX_MDICHILD | WS_EX_CONTROLPARENT, // Extended style
szClassName, // class name
szWinTitle, // title
WS_CLIPCHILDREN | WS_CLIPSIBLINGS
| WS_OVERLAPPEDWINDOW | WS_VISIBLE, // style
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
CW_USEDEFAULT, // width
CW_USEDEFAULT, // height
hwndParent, // parent
NULL, // menu
g_hInst, // hInstance
NULL // user defined data
);
}
#else //NEW_WINDOWING_CODE
LONG
CreateCallsWindow(
HWND hwnd,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
This function creates a calls window and fills the window with a current stack trace.
Arguments:
hwnd - calls window handle
wParam - font handle
lParam - pointer to a CREATESTRUCT
Return Value:
Zero.
--*/
{
MDICREATESTRUCT *mdi;
int iView;
int iType;
RECT cRect;
DWORD dwStyle;
mdi = (MDICREATESTRUCT*)(((CREATESTRUCT*)lParam)->lpCreateParams);
myView = iView = HIWORD(mdi->lParam);
iType = (WORD)(mdi->lParam & 0xffff);
hWndCalls = hwnd;
GetClientRect( hwnd, &cRect );
dwStyle = WS_CHILD |
WS_VISIBLE |
LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT |
LBS_WANTKEYBOARDINPUT;
if (g_contGlobalPreferences_WkSp.m_bVertScrollBars) {
dwStyle |= WS_VSCROLL;
}
if (g_contGlobalPreferences_WkSp.m_bHorzScrollBars) {
dwStyle |= WS_HSCROLL;
}
hwndList = CreateWindow( "LISTBOX",
NULL,
dwStyle,
cRect.left,
cRect.top,
cRect.right - cRect.left,
cRect.bottom - cRect.top,
hwnd,
NULL,
GetModuleHandle(NULL),
NULL
);
hFontList = Views[myView].font;
if (!hFontList) {
Views[myView].font = hFontList = CreateFontIndirect( &g_logfontDefault );
}
SendMessage( hwndList, WM_SETFONT, (WPARAM)hFontList, (LPARAM)FALSE );
hbrBackground = CreateSolidBrush( StringColors[CallsWindow].BkgndColor );
FillStackFrameWindow( hwndList, TRUE );
return 0;
}
#endif //NEW_WINDOWING_CODE
LOGERR NEAR PASCAL LogCallStack(LPSTR lpsz)
/*++
Routine Description:
This function will dump a call stack to the command window.
Arguments:
lpsz - arguments to callstack
Return Value:
log error code
--*/
{
LPSTACKINFO StackInfo = NULL;
BOOL bSpecial = FALSE;
BOOL bColumnTitles = FALSE;
LPPD LppdT = LppdCur;
LPTD LptdT = LptdCur;
LOGERR rVal = LOGERROR_NOERROR;
DWORD i;
DWORD k = MAX_FRAMES;
int err;
int cch;
XOSD xosd = xosdNone;
CHAR buf[512];
CHAR errmsg[512];
DWORD64 StackAddr = 0;
DWORD64 FrameAddr = 0;
DWORD64 PCAddr = 0;
LPSTR p;
DWORD dwFrames = g_contGlobalPreferences_WkSp.m_dwMaxFrames;
CmdInsertInit();
IsKdCmdAllowed();
PDWildInvalid();
PreRunInvalid();
if (LptdCommand == (LPTD)-1) {
if (LppdCur == NULL) {
return LOGERROR_UNKNOWN;
}
for (LptdCommand = LppdCur->lptdList;
LptdCommand && rVal == LOGERROR_NOERROR;
LptdCommand = LptdCommand->lptdNext) {
ThreadStatForThread(LptdCommand);
rVal = LogCallStack(lpsz);
if (LptdCommand->lptdNext) {
CmdLogFmt("\n");
}
}
return rVal;
}
LppdCur = LppdCommand;
LptdCur = LptdCommand;
i = sizeof(STACKINFO) * dwFrames;
StackInfo = (LPSTACKINFO) malloc( i );
if (!StackInfo) {
CmdLogFmt( "Could not allocate memory for stack trace\n" );
goto done;
}
ZeroMemory( StackInfo, i );
// this code processes the 'K' command modifiers
// b - print first 3 parameters from stack
// s - print source information (file & lineno)
// v - runtime function information (fpo/pdata)
// t - display column titles
lpsz = CPSkipWhitespace(lpsz);
while (lpsz && *lpsz && *lpsz != ' ')
{
switch (tolower(*lpsz))
{
case 'b':
g_contGlobalPreferences_WkSp.m_bFrameptr = TRUE;
g_contGlobalPreferences_WkSp.m_bRetAddr = TRUE;
g_contGlobalPreferences_WkSp.m_bDisplacement = TRUE;
g_contGlobalPreferences_WkSp.m_bStack = TRUE;
g_contGlobalPreferences_WkSp.m_bModule = TRUE;
bSpecial = TRUE;
bColumnTitles = TRUE;
break;
case 's':
g_contGlobalPreferences_WkSp.m_bSource = TRUE;
break;
case 'v':
g_contGlobalPreferences_WkSp.m_bRtf = TRUE;
break;
case 'n':
g_contGlobalPreferences_WkSp.m_bFrameNum = TRUE;
break;
case 't':
bColumnTitles = TRUE;
break;
case ' ':
break;
default:
goto nextparse;
}
++lpsz;
}
nextparse:
lpsz = CPSkipWhitespace(lpsz);
if (*lpsz == '=') {
lpsz++;
p = CPSzToken(&lpsz, NULL);
if (!p || !*p) {
CmdLogFmt( "Missing stack frame\r\n" );
goto done;
}
FrameAddr = CPGetNbr( p,
radix,
TRUE,
&CxfIp,
errmsg,
&err,
g_contWorkspace_WkSp.m_bMasmEval
);
if (err) {
CmdLogFmt( "Bad frame address\r\n" );
goto done;
}
p = CPSzToken(&lpsz, NULL);
if (!p || !*p) {
CmdLogFmt( "Missing stack address\r\n" );
goto done;
}
StackAddr = CPGetNbr( p,
radix,
TRUE,
&CxfIp,
errmsg,
&err,
g_contWorkspace_WkSp.m_bMasmEval
);
if (err) {
CmdLogFmt( "Bad stack address\r\n" );
goto done;
}
p = CPSzToken(&lpsz, NULL);
if (!p || !*p) {
CmdLogFmt( "Missing PC\r\n" );
goto done;
}
PCAddr = CPGetNbr( p,
radix,
TRUE,
&CxfIp,
errmsg,
&err,
g_contWorkspace_WkSp.m_bMasmEval
);
if (err) {
CmdLogFmt( "Bad PC address\r\n" );
goto done;
}
}
lpsz = CPSkipWhitespace(lpsz);
if (lpsz && *lpsz) {
if (*lpsz == 'l' || *lpsz == 'L') {
lpsz = CPSkipWhitespace(lpsz+1);
}
if (!*lpsz) {
err = 1;
} else {
k = CPGetInt(lpsz, &err, &cch);
}
if (err || k < 1) {
CmdLogVar(ERR_Bad_Count);
rVal = LOGERROR_QUIET;
goto done;
}
}
if (!DebuggeeActive()) {
CmdLogVar(ERR_Debuggee_Not_Alive);
rVal = LOGERROR_QUIET;
goto done;
}
GetCompleteStackTrace( FrameAddr, StackAddr, PCAddr, StackInfo, &dwFrames, FALSE, TRUE );
k = min( k, dwFrames );
for (i=0; i<k; i++)
{
if (i==0) {
if (bColumnTitles) {
TCHAR szFmt[200] = {0};
PTSTR pszFmt = szFmt;
PCTSTR pszFrmPtr = _T("FramePtr");
PCTSTR pszRetAdr = _T("RetAddr");
PCTSTR pszParam1 = _T("Param1");
PCTSTR pszParam2 = _T("Param2");
PCTSTR pszParam3 = _T("Param3");
int nPtrWidth = 0;
int nParamWidth = 0;
switch (StackInfo[i].StkFrame.AddrPC.Mode)
{
default:
case AddrModeFlat:
nPtrWidth = 16;
nParamWidth = 8;
break;
case AddrModeReal:
case AddrMode1616:
nPtrWidth = 9;
nParamWidth = 4;
break;
case AddrMode1632:
nPtrWidth = 13;
nParamWidth = 4;
break;
}
if (g_contGlobalPreferences_WkSp.m_bFrameNum){
_tcscpy(pszFmt, "# ");
pszFmt += (_tcslen(pszFmt) / sizeof(TCHAR));
}
if (bSpecial) {
// Display Params
_stprintf(pszFmt, "%-*s %-*s %-*s %-*s %-*s Function Name\r\n",
nPtrWidth, pszFrmPtr,
nPtrWidth, pszRetAdr,
nParamWidth, pszParam1,
nParamWidth, pszParam2,
nParamWidth, pszParam3);
} else {
_stprintf(pszFmt, "%-*s %-*s Function Name\r\n",
nPtrWidth, pszFrmPtr,
nPtrWidth, pszRetAdr);
}
CmdLogFmt( szFmt );
}
}
FormatStackFrameString( buf, sizeof(buf), &StackInfo[i], 0 );
CmdLogFmt( buf );
CmdLogFmt( "\r\n" );
}
done:
if (StackInfo) {
free( StackInfo );
}
LppdCur = LppdT;
LptdCur = LptdT;
return rVal;
}
INT
LookupFrameAddress(
LPSTACKINFO lpsi,
DWORD frames,
ADDR addr
)
/*++
Routine Description:
Locates an address in the callback stack area.
Arguments:
addr - An ADDR struct contining the address to find in the calls stack
Return Value:
Index of the located stack frame or -1 on error.
--*/
{
int i;
ADDR addrPC;
SYUnFixupAddr( &addr );
for (i=0; i<(INT)frames; i++) {
CreateAddress( &lpsi[i].StkFrame.AddrPC, &addrPC );
SYUnFixupAddr( &addrPC );
if ((GetAddrSeg(lpsi[i].ProcAddr) == GetAddrSeg(addr)) &&
((GetAddrOff(addr) >= GetAddrOff(lpsi[i].ProcAddr)) &&
(GetAddrOff(addr) < lpsi[i].StkFrame.AddrPC.Offset))) {
return i;
}
}
return -1;
}
PCXF
CLGetFuncCXF(
PADDR paddr,
PCXF pcxf
)
/*++
Routine Description:
This function is used to resolve a context operator by filling in the frame structure in the CXF passed in.
Because this function may be called while in the middle of an expression evaluation care must be taken to NEVER call the EE while in this function.
The EE is not re-entrant!
Arguments:
paddr - An ADDR struct contining the address of the evaluation
pcxf - Pointer to a CXF struture
Return Value:
Always return pcxf.
--*/
{
LPSTACKINFO StackInfo;
DWORD dwFrames = MAX_FRAMES;
INT frame;
ADDR addr;
Assert ( ADDR_IS_LI (*paddr));
addr = *paddr;
ZeroMemory( pcxf, sizeof ( CXF ) );
frame = sizeof(STACKINFO) * dwFrames;
StackInfo = (LPSTACKINFO) malloc( frame );
if (!StackInfo) {
goto exit;
}
ZeroMemory( StackInfo, frame );
GetCompleteStackTrace( 0, 0, 0, StackInfo, &dwFrames, FALSE, FALSE );
if (dwFrames == 0) {
goto exit;
}
frame = LookupFrameAddress( StackInfo, MAX_FRAMES, addr );
if (frame == -1) {
goto exit;
}
CreateAddress( &StackInfo[frame].StkFrame.AddrPC, &addr );
SHSetCxt( &addr, &pcxf->cxt );
pcxf->hFrame = StackInfo[frame].Cxf.hFrame;
pcxf->cxt.addr = addr;
exit:
if (StackInfo) {
free( StackInfo );
}
return pcxf;
}
void
FormatStackFrameString(
LPSTR lsz,
DWORD cb,
const STACKINFO * const si,
DWORD width
)
/*++
Routine Description:
This function formats a string that reresents a stack frame and places the data in the buffer pointed to by lsz.
The current options control the format of the data.
Arguments:
nView - view number for calls window
lsz - Pointer to a buffer that receives the formatted string.
cb - length of the lsz buffer.
si - Stack frame that is to be formatted.
width - If non-zero this value indicates that the source information
is to be right justified in the buffer.
--*/
{
LPSTR beg = lsz;
DWORD i;
ADDR addr;
CHAR SrcFname[MAX_PATH];
DWORD lineno;
CHAR szFname[_MAX_FNAME];
CHAR szExt[_MAX_EXT];
UINT processor;
PFPO_DATA pFpoData;
*lsz = '\0';
if (g_contGlobalPreferences_WkSp.m_bFrameNum) {
if (radix == 10) {
sprintf( lsz, "%02d ", si->FrameNum );
} else if (radix == 16) {
sprintf( lsz, "%02x ", si->FrameNum );
} else if (radix == 8) {
sprintf( lsz, "%02o ", si->FrameNum );
}
lsz += strlen( lsz );
}
switch( si->StkFrame.AddrReturn.Mode )
{
case AddrModeFlat:
if (g_contGlobalPreferences_WkSp.m_bFrameptr) {
sprintf( lsz, "%016I64x ", si->StkFrame.AddrFrame.Offset );
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bRetAddr) {
sprintf( lsz, "%016I64x ", si->StkFrame.AddrReturn.Offset );
lsz += strlen( lsz );
}
break;
case AddrMode1616:
case AddrModeReal:
if (g_contGlobalPreferences_WkSp.m_bFrameptr) {
sprintf( lsz, "%04x:%04x ",
si->StkFrame.AddrFrame.Segment,
(DWORD)si->StkFrame.AddrFrame.Offset
);
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bRetAddr) {
sprintf( lsz, "%04x:%04x ",
si->StkFrame.AddrReturn.Segment,
(DWORD)si->StkFrame.AddrReturn.Offset
);
lsz += strlen( lsz );
}
break;
case AddrMode1632:
if (g_contGlobalPreferences_WkSp.m_bFrameptr) {
sprintf( lsz, "%04x:%08x ",
si->StkFrame.AddrFrame.Segment,
(DWORD)si->StkFrame.AddrFrame.Offset
);
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bRetAddr) {
sprintf( lsz, "%04x:%08x ",
si->StkFrame.AddrReturn.Segment,
(DWORD)si->StkFrame.AddrReturn.Offset
);
lsz += strlen( lsz );
}
break;
}
if (g_contGlobalPreferences_WkSp.m_bRetAddr || g_contGlobalPreferences_WkSp.m_bFrameptr) {
strcat( lsz, " " );
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bStack) {
if (si->StkFrame.AddrReturn.Mode == AddrModeFlat) {
sprintf( lsz,
sizeof(si->StkFrame.Params[0] == 8)
? "%016I64x %016I64x %016I64x ":"%08x %08x %08x ",
si->StkFrame.Params[0],
si->StkFrame.Params[1],
si->StkFrame.Params[2]
);
} else {
sprintf( lsz,
"%04x %04x %04x ",
LOWORD(si->StkFrame.Params[0]),
HIWORD(si->StkFrame.Params[0]),
LOWORD(si->StkFrame.Params[1])
);
}
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bModule) {
if (si->Context[0]) {
strcat( lsz, si->Context );
lsz += strlen( lsz );
} else if (*si->Module) {
strcat( lsz, si->Module );
strcat( lsz, "!" );
lsz += strlen( lsz );
}
}
if (g_contGlobalPreferences_WkSp.m_bFuncName) {
if (si->ProcName[0] == '_') {
char *p;
strcat( lsz, &si->ProcName[1] );
p = (PSTR) strchr( (LPBYTE) lsz, '@');
if (p) {
*p = '\0';
}
lsz += strlen( lsz );
} else {
strcat( lsz, si->ProcName );
lsz += strlen( lsz );
}
}
if (g_contGlobalPreferences_WkSp.m_bDisplacement && si->Displacement) {
sprintf( lsz, "+0x%I64x", si->Displacement );
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bParams && si->Params[0]) {
sprintf( lsz, "(%s)", si->Params );
lsz += strlen( lsz );
}
if (g_contGlobalPreferences_WkSp.m_bRtf) {
OSDGetDebugMetric ( LppdCur->hpid, 0, mtrcProcessorType, &processor );
if (processor == mptix86) {
pFpoData = (PFPO_DATA) si->StkFrame.FuncTableEntry;
if (!pFpoData) {
sprintf(lsz, " (No FPO)");
} else {
switch (pFpoData->cbFrame)
{
case FRAME_NONFPO:
sprintf(lsz, " (EBP)");
break;
case FRAME_FPO:
if (pFpoData->fHasSEH) {
sprintf(lsz, " (FPO: [seh] ");
}
else if (pFpoData->fUseBP) {
sprintf(lsz, " (FPO: [ebp %08x] ", SAVE_EBP(si->StkFrame));
}
else {
sprintf(lsz, " (FPO: ");
}
lsz += strlen(lsz);
sprintf(lsz, "[%d,%d,%d])", pFpoData->cdwParams,
pFpoData->cdwLocals,
pFpoData->cbRegs);
break;
case FRAME_TRAP:
{
sprintf(lsz, " (FPO: [%d,%d] TrapFrame%s @ %08lx)",
pFpoData->cdwParams,
pFpoData->cdwLocals,
(TRAP_EDITED(si->StkFrame)) ? "" : "-EDITED",
SAVE_TRAP(si->StkFrame));
}
break;
case FRAME_TSS:
sprintf(lsz, " (FPO: TaskGate %lx:0)", TRAP_TSS(si->StkFrame));
break;
default:
sprintf(lsz, "(UKNOWN FPO TYPE)");
break;
}
}
lsz += strlen(lsz);
}
}
if (g_contGlobalPreferences_WkSp.m_bSource) {
ZeroMemory( &addr, sizeof(addr) );
addr.addr.off = (OFFSET)si->StkFrame.AddrPC.Offset;
addr.addr.seg = si->StkFrame.AddrPC.Segment;
addr.mode.fFlat = si->StkFrame.AddrPC.Mode == AddrModeFlat;
addr.mode.fOff32 = si->StkFrame.AddrPC.Mode == AddrMode1632;
addr.mode.fReal = si->StkFrame.AddrPC.Mode == AddrModeReal;
if (GetSourceFromAddress( &addr, SrcFname, sizeof(SrcFname), &lineno )) {
_splitpath( SrcFname, NULL, NULL, szFname, szExt );
if (width) {
//----------------
// this code right justifies the source info string
//----------------
// put the string in a safe place
sprintf( SrcFname, " [ %s%s @ %4lu ]", szFname, szExt, lineno );
if (width > (lsz-beg) + strlen(SrcFname)) {
// pad the string with spaces
for (i=0; i<width-(lsz-beg)+1; i++) {
*(lsz+i) = ' ';
}
lsz = beg + width - strlen(SrcFname);// re-position the pointer to the end
}
sprintf( lsz, "%s", SrcFname );// spew the string to it's new home
} else {
sprintf( lsz, " [ %s%s @ %lu ]", szFname, szExt, lineno );
}
lsz += strlen( lsz );
}
}
}
BOOL
GoUntilStackFrame(
LPSTACKINFO si
)
/*++
Routine Description:
This function sets a breakpoint at the address indicated in the requested stack frame and then continues the thread.
Arguments:
si - Stack frame that is to control the bp.
Return Value:
TRUE - Thread was continued to the requested address.
FALSE - Thread could not be continued or bp could not be set.
--*/
{
ADDR addr;
HBPT hbpt = NULL;
CHAR buf[256];
CXF cxf = CxfIp;
sprintf( buf, "0x%I64x", si->StkFrame.AddrPC.Offset );
if (BPParse(&hbpt, buf, NULL, NULL, LppdCur ? LppdCur->hpid: 0) != BPNOERROR) {
return FALSE;
}
if (BPBindHbpt( hbpt, &cxf ) == BPNOERROR) {
if (BPAddrFromHbpt( hbpt, &addr ) != BPNOERROR) {
return FALSE;
}
if (BPFreeHbpt( hbpt ) != BPNOERROR) {
return FALSE;
}
if (!GoUntil(&addr)) {
return FALSE;
}
UpdateDebuggerState(UPDATE_CONTEXT);
return TRUE;
}
BPFreeHbpt( hbpt );
return FALSE;
}
BOOL
GetCompleteStackTrace(
DWORD64 FramePointer,
DWORD64 StackPointer,
DWORD64 ProgramCounter,
LPSTACKINFO StackInfo,
LPDWORD lpdwFrames,
BOOL fQuick,
BOOL fFull
)
/*++
Routine Description:
This function calls OSDEBUG to get the individual stack frames.
The STACKINFO structure is filled in with the information returned from OSDEBUG.
Arguments:
FramePointer - If non-zero this is the beginning frame pointer.
StackPointer - If non-zero this is the beginning stack pointer .
ProgramCounter - If non-zero this is the beginning program counter.
StackInfo - Pointer to an array of STACKINFO structures.
lpdwFrames - Number of frames to get from OSDEBUG.
fQuick - If TRUE and the frame pointer is the same as the last
call to this function the only the first frame is updated.
fFull - If TRUE all fields in the frame are filled in
Return Value:
TRUE - Stack trace completed ok.
FALSE - Could not obtain a stack trace.
--*/
{
DWORD i;
STACKFRAME stkFrame;
XOSD xosd;
DWORD numFrames = *lpdwFrames;
DWORD dw;
HTID vhtid;
HIND hSavedRegs;
ADDR addr;
*lpdwFrames = 0;
if ((!LppdCur) || (!LptdCur)) {
return FALSE;
}
hSavedRegs = NULL;
if (FramePointer || StackPointer || ProgramCounter) {
OSDSaveRegs(LppdCur->hpid, LptdCur->htid, &hSavedRegs);
}
if (FramePointer) {
AddrInit(&addr,
NULL,
0,
FramePointer,
TRUE,
TRUE,
FALSE,
FALSE
);
OSDSetAddr(LppdCur->hpid, LptdCur->htid, adrBase, &addr);
}
if (StackPointer) {
AddrInit(&addr, NULL, 0, StackPointer, TRUE, TRUE, FALSE, FALSE);
OSDSetAddr(LppdCur->hpid, LptdCur->htid, adrStack, &addr);
}
if (ProgramCounter) {
AddrInit(&addr, NULL, 0, ProgramCounter, TRUE, TRUE, FALSE, FALSE);
OSDSetAddr(LppdCur->hpid, LptdCur->htid, adrPC, &addr);
}
ZeroMemory( &stkFrame, sizeof(stkFrame) );
vhtid = LptdCur->htid;
for (i=0; i<numFrames; i++)
{
xosd = OSDGetFrame(LppdCur->hpid, vhtid, 1, &vhtid);
if (xosd != xosdNone) {
break;
}
xosd = OSDSystemService (
LppdCur->hpid,
LptdCur->htid,
(SSVC) ssvcGetStackFrame,
&stkFrame,
sizeof(stkFrame),
&dw
);
if (xosd != xosdNone) {
break;
}
BuildStackInfo(&StackInfo[i],
&stkFrame,
i,
LppdCur->hpid,
vhtid,
fFull
);
if ( fQuick && i== 0 ) {
// If the first frame has the same frame and return
// addresses as the previously cached one, then we
// don't bother getting the rest of the stack trace since
// it has not changed.
if ( ADDREQ( stkFrame.AddrFrame, stkFrameSave.AddrFrame ) &&
ADDREQ( stkFrame.AddrReturn, stkFrameSave.AddrReturn ) &&
ADDREQ( stkFrame.AddrStack, stkFrameSave.AddrStack ) ) {
i = FrameCountSave;
break;
}
stkFrameSave = stkFrame;
} else if (i) {
// If the current frame is the same as the previous frame,
// we stop so we don't end up with a long list of bogus
// frames.
if ( ADDREQ( stkFrame.AddrPC, StackInfo[i-1].StkFrame.AddrPC ) &&
ADDREQ( stkFrame.AddrFrame, StackInfo[i-1].StkFrame.AddrFrame ) ) {
break;
}
}
}
*lpdwFrames = i;
if (fQuick) {
// Just in case cached frame count changes.
FrameCountSave = i;
}
if (hSavedRegs) {
OSDRestoreRegs(LppdCur->hpid, LptdCur->htid, hSavedRegs);
}
return TRUE;
}
LPSTR GetLastFrameFuncName(VOID)
/*++
Routine Description:
This function gets the symbol name of the last stack frame.
What this really accomplishes is getting the name of the function that was passed to CreateThread().
If the last symbol name is BaseThreadStart() then the previous frame's symbol name is used.
Arguments:
None.
Return Value:
Pointer to a string that contains the function name.
The caller is responsible for free()ing the memory.
--*/
{
LPSTR fname = NULL;
LPSTACKINFO StackInfo = NULL;
DWORD dwFrames = MAX_FRAMES;
DWORD i;
i = sizeof(STACKINFO) * dwFrames;
StackInfo = (LPSTACKINFO) malloc( i );
if (!StackInfo) {
goto exit;
}
ZeroMemory( StackInfo, i );
GetCompleteStackTrace( 0, 0, 0, StackInfo, &dwFrames, FALSE, TRUE );
if (dwFrames == 0) {
goto exit;
}
if (_stricmp(StackInfo[dwFrames-1].ProcName,"BaseThreadStart")==0 ||
_stricmp(StackInfo[dwFrames-1].ProcName,"_BaseThreadStart@8")==0) {
if (dwFrames > 1) {
fname = _strdup(StackInfo[dwFrames-2].ProcName);
goto exit;
}
}
fname = _strdup(StackInfo[dwFrames-1].ProcName);
exit:
if (StackInfo) {
free( StackInfo );
}
return fname;
}
BOOL IsValidFrameNumber(INT FrameNumber)
{
DWORD i;
// update the call stack
i = g_contGlobalPreferences_WkSp.m_dwMaxFrames;
if (GetCompleteStackTrace( 0, 0, 0, StackInfo, &i, TRUE, TRUE )) {
FrameCount = i;
}
// update the window if one exists
if (GetCallsHWND() && hwndList) {
FillStackFrameWindow( hwndList, FALSE );
}
if (FrameNumber >= 0 && FrameNumber <= (INT)FrameCount) {
return TRUE;
}
return FALSE;
}
// M00BUG -- this function should not re ally be needed -- but it is until
// KentF manages to fix what HFRAMEs really do.
HTID WalkToFrame(HPID hpid, HTID htid, int iCall)
{
int i;
HTID vhtid;
XOSD xosd;
if (!LppdCur || !LptdCur) {
return NULL;
}
vhtid = LptdCur->htid;
if (iCall > 0) {
xosd = OSDGetFrame(LppdCur->hpid, LptdCur->htid, iCall+1, &vhtid);
if (xosd != xosdNone) {
return NULL;
}
}
return vhtid;
}
PCXF ChangeFrame(int iCall)
{
PCXF cxf;
HTID vhtid;
if (!LppdCur || !LptdCur) {
return NULL;
} else if (iCall == 0) {
cxf = &CxfIp;
} else {
cxf = &StackInfo[iCall].Cxf;
vhtid = WalkToFrame(LppdCur->hpid, LptdCur->htid, iCall);
if (!vhtid) {
return NULL;
}
cxf->hFrame = (HFRAME) vhtid;
}
return cxf;
}
INT_PTR
CALLBACK
DlgProc_CallStack(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static DWORD HelpArray[]=
{
ID_CWOPT_FRAMEPTR, IDH_FP,
ID_CWOPT_FUNCNAME, IDH_FUNC,
ID_CWOPT_PARAMS, IDH_PARAM,
ID_CWOPT_MODULE, IDH_MODULE,
ID_CWOPT_STACK, IDH_4DWORDS,
ID_CWOPT_RETADDR, IDH_RETADDR,
ID_CWOPT_DISPLACEMENT, IDH_DISPLACE,
ID_CWOPT_SOURCE, IDH_SRC,
ID_CWOPT_RTF, IDH_RUNTIME,
ID_CWOPT_MAXFRAMES_LABEL, IDH_MAXFRAMES,
ID_CWOPT_MAXFRAMES, IDH_MAXFRAMES,
0, 0
};
switch (uMsg) {
case WM_INITDIALOG:
SendDlgItemMessage(hwndDlg, ID_CWOPT_MAXFRAMES, EM_SETLIMITTEXT, 3, 0);
CheckDlgButton( hwndDlg, ID_CWOPT_FRAMEPTR, g_contGlobalPreferences_WkSp.m_bFrameptr );
CheckDlgButton( hwndDlg, ID_CWOPT_RETADDR, g_contGlobalPreferences_WkSp.m_bRetAddr );
CheckDlgButton( hwndDlg, ID_CWOPT_FUNCNAME, g_contGlobalPreferences_WkSp.m_bFuncName );
CheckDlgButton( hwndDlg, ID_CWOPT_DISPLACEMENT, g_contGlobalPreferences_WkSp.m_bDisplacement );
CheckDlgButton( hwndDlg, ID_CWOPT_PARAMS, g_contGlobalPreferences_WkSp.m_bParams );
CheckDlgButton( hwndDlg, ID_CWOPT_STACK, g_contGlobalPreferences_WkSp.m_bStack );
CheckDlgButton( hwndDlg, ID_CWOPT_SOURCE, g_contGlobalPreferences_WkSp.m_bSource );
CheckDlgButton( hwndDlg, ID_CWOPT_MODULE, g_contGlobalPreferences_WkSp.m_bModule );
CheckDlgButton( hwndDlg, ID_CWOPT_RTF, g_contGlobalPreferences_WkSp.m_bRtf );
SetDlgItemInt ( hwndDlg, ID_CWOPT_MAXFRAMES, g_contGlobalPreferences_WkSp.m_dwMaxFrames, 500 );
return FALSE;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, "windbg.hlp", HELP_WM_HELP, (DWORD_PTR)(PVOID) HelpArray );
return TRUE;
case WM_CONTEXTMENU:
WinHelp ((HWND) wParam, "windbg.hlp", HELP_CONTEXTMENU, (DWORD_PTR)(PVOID) HelpArray );
return TRUE;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_APPLY:
{
BOOL bSuccess;
g_contGlobalPreferences_WkSp.m_bFrameptr = IsDlgButtonChecked( hwndDlg, ID_CWOPT_FRAMEPTR );
g_contGlobalPreferences_WkSp.m_bRetAddr = IsDlgButtonChecked( hwndDlg, ID_CWOPT_RETADDR );
g_contGlobalPreferences_WkSp.m_bFuncName = IsDlgButtonChecked( hwndDlg, ID_CWOPT_FUNCNAME );
g_contGlobalPreferences_WkSp.m_bDisplacement = IsDlgButtonChecked( hwndDlg, ID_CWOPT_DISPLACEMENT );
g_contGlobalPreferences_WkSp.m_bParams = IsDlgButtonChecked( hwndDlg, ID_CWOPT_PARAMS );
g_contGlobalPreferences_WkSp.m_bStack = IsDlgButtonChecked( hwndDlg, ID_CWOPT_STACK );
g_contGlobalPreferences_WkSp.m_bSource = IsDlgButtonChecked( hwndDlg, ID_CWOPT_SOURCE );
g_contGlobalPreferences_WkSp.m_bModule = IsDlgButtonChecked( hwndDlg, ID_CWOPT_MODULE );
g_contGlobalPreferences_WkSp.m_bRtf = IsDlgButtonChecked( hwndDlg, ID_CWOPT_RTF );
g_contGlobalPreferences_WkSp.m_dwMaxFrames = GetDlgItemInt( hwndDlg, ID_CWOPT_MAXFRAMES, &bSuccess, 500 );
UpdateDebuggerState( UPDATE_CALLS );
}
return TRUE;
}
break;
}
return FALSE;
}