|
|
Microsoft OS/2 SDK PM 02-24-1989
/***************************************************************************\
Module Name: SYMBOL.C
This module contains the code for displaying symbols for a specified address.
\***************************************************************************/
#define INCL_DOSPROCESS
#define INCL_GPILCIDS
#define INCL_WINDIALOGS
#define INCL_WINFRAMEMGR
#define INCL_WINHEAP /* needed for spy.h */
#define INCL_WININPUT
#define INCL_WINLISTBOXES
#define INCL_WINMENUS
#define INCL_WINMESSAGEMGR
#define INCL_WINPOINTERS /* needed for spy.h */
#define INCL_WINWINDOWMGR
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include "spy.h"
#include <spyhook.h>
#include "symbol.h"
WHOISINFO whoIs;
MAPDEF mapdef;
MAPEND mapend;
SEGDEF segdef;
SYMDEF symdef;
extern VOID lstrcat(PSZ, PSZ);
extern void OutputString(char [], SHORT); /* Output string to output devices */
extern BOOL FValidPointer (CHAR FAR *pVoid, SHORT cbStruct);
extern BOOL FGuessValidPointer (CHAR FAR *pVoid, SHORT cbStruct);
extern HWND hwndSpyFrame;
extern HAB hab;
/* Function prototypes */
HWND HwndFrameFromPID(PID);
VOID GetSymbolInformation(PID, char far *, char *);
VOID NEAR ProcessLNOkButton(HWND);
MRESULT NEAR FormatLNDialog(HWND, PSWP, PRECTL);
VOID NEAR EndLNDialog(HWND);
MRESULT CALLBACK ListNearDlgProc(HWND, USHORT, MPARAM, MPARAM);
/***************************************************************************\
* hwnd HwndFrameFromPID(pid)
*
* This function attempts to locate a frame window that was
* created by the specified PID. It returns NULL if none are found.
\***************************************************************************/
HWND HwndFrameFromPID(pid)
PID pid;
{
HENUM henum;
HWND hwnd;
PID pidWindow;
TID tidWindow;
char szClassName[50]; /* Class name of window */
CLASSINFO classinfo; /* Information about class */
henum = WinBeginEnumWindows(HWND_DESKTOP);
if (henum == NULL)
return (NULL);
while ((hwnd = WinGetNextWindow(henum)) != NULL) {
WinQueryWindowProcess(hwnd, &pidWindow, &tidWindow);
WinLockWindow(hwnd, FALSE);
if (pid == pidWindow) {
/* See if a frame window */
WinQueryClassName(hwnd, sizeof(szClassName),
(PSZ)szClassName);
if (WinQueryClassInfo(hab, (PSZ)szClassName, &classinfo) &&
(classinfo.flClassStyle & CS_FRAME))
break; /* We have our frame */
}
}
WinEndEnumWindows(henum);
return (hwnd);
}
/***************************************************************************\
* int IdentifyCodeSegment(lpSegInfo, pid, selector)
*
* Identifies the code selector for the specified process.
* NOTE: The process is currently ignored, but later will somehow
* return information in the context of the specified process ID.
\***************************************************************************/
int
pascal near IdentifyCodeSegment( pSegInfo, pid, selector )
PSEGINFO pSegInfo;
PID pid;
USHORT selector;
{
char far *lp;
char *np;
int n;
BYTE c;
USHORT segnum;
USHORT seg_ptr;
USHORT uTemp;
int rc;
PIDINFO pidinfo;
HWND hwndPIDFrame;
/* If new selector matches the current one, then nothing to do */
if ((pSegInfo->pid == pid) && (pSegInfo->selector == selector))
return 0;
/*
* Try to identify the code selector. We will first try in the context
* of our process. If this fails, or if we find that the segment is
* associated with our program and it is not our PID, we will attempt
* to get the symbol in the specified PID context, with the help of
* our hooks.
*/
DosGetPID(&pidinfo);
rc = IdentifyCodeSelector( selector, (PWHOISINFO)&whoIs );
if ((pid != pidinfo.pid) && (rc == 0)) {
/*
* User asked for a different context, and symbol was found.
* If the symbol was in our .exe we will ignore what we found,
* and try again.
*/
/* First get past the module name */
np = whoIs.names;
while (*np++)
;
/* Now go through the pathname */
while (*np) {
if (*np++ == '.') {
if (strcmp(np,"EXE") == 0) {
rc = 1; /* It is in our exe, so set errr condition */
break; /* no need to go on */
}
}
}
}
if (rc) {
/*
* We need to try in other PID context
*/
if ((pid == pidinfo.pid) ||
((hwndPIDFrame = HwndFrameFromPID(pid)) == NULL))
return (rc); /* segment not found or no way to find segment */
/* Lets use the hook */
SpySetLNSymbolPID(pid, selector);
/* HACK: Send message to frame known to send another message */
WinSendMsg(hwndPIDFrame, WM_QUERYTASKFOCUS, 0L, 0L);
if (SpyGetLNSymbolSelector(&whoIs) != 0)
return (1); /* Still did not find the symbol */
}
/* It is a valid code selector, make it the new current selector */
pSegInfo->selector = selector;
pSegInfo->pid = pid;
/* Is the new selector in the same module? */
if (pSegInfo->lpSegName && pSegInfo->whoIs.mte == whoIs.mte)
pSegInfo->whoIs.segNum = whoIs.segNum; /* Yes, just copy seg# */
else {
/* New module, get segment #, mte handle, module name and pathstring */
pSegInfo->whoIs = whoIs;
/* Generate separate pointers to module name and pathstring */
lp = &pSegInfo->whoIs.names[0];
pSegInfo->lpModName = lp;
while (*lp++)
;
pSegInfo->lpPathName = lp;
/* Change pathstring extension to be .SYM */
while (*lp)
if (*lp++ == '.') {
*lp++ = 'S';
*lp++ = 'Y';
*lp++ = 'M';
}
lp++;
/*
* No current segment name or symbol name, so make them point to
* null string
*/
*lp = 0;
pSegInfo->lpSegName = lp;
pSegInfo->lpSymName = 0L;
/* Close any currently open .SYM file and then open the new .SYM file */
if (pSegInfo->symfh != -1)
pSegInfo->symfh = DosClose((HFILE)pSegInfo->symfh );
if (DosOpen(pSegInfo->lpPathName, (PHFILE)&pSegInfo->symfh,
(PUSHORT)&uTemp,
0L, 0, 1, 0x00c0, 0L) == 0) {
/* Read in .SYM file header and save segment count and pointer */
DebugFileRead( pSegInfo->symfh, (PSZ)&mapdef, sizeof( mapdef ) );
pSegInfo->segcnt = mapdef.seg_cnt;
pSegInfo->segptr = mapdef.seg_ptr;
/* Read version of MAPSYM that produced this file.
If not a version 4 file then ignore the file */
DebugFileSeek( pSegInfo->symfh, (long)-sizeof( mapend ), 2 );
DebugFileRead( pSegInfo->symfh, (PSZ)&mapend, sizeof( mapend ) );
if (mapend.ver != 4)
pSegInfo->symfh = DosClose( (HFILE)pSegInfo->symfh );
}
}
/* Point to segment name buffer and make it a null string for now */
lp = pSegInfo->lpSegName;
*lp = 0;
/* If we have an open .SYM file, search for segment definition record */
if (pSegInfo->symfh != -1 && pSegInfo->whoIs.segNum < pSegInfo->segcnt) {
/* Start with first segment definition and read segNum definitions */
seg_ptr = pSegInfo->segptr;
n = pSegInfo->whoIs.segNum;
while (n--) {
DebugFileSeek( pSegInfo->symfh, (long)seg_ptr, 4 );
DebugFileRead( pSegInfo->symfh, (PSZ)&segdef, sizeof( segdef ) );
seg_ptr = (USHORT)segdef.nxt_seg;
}
/* Now read in the segment name string associated with this segment
and make it a null terminated string */
DebugFileRead( pSegInfo->symfh, (PSZ)(lp),
(int)((BYTE)segdef.nam_len) );
lp += segdef.nam_len;
*lp++ = 0;
/* Remember the count of symbols for this segment */
pSegInfo->symcnt = segdef.sym_cnt;
/* Remember the file offset of the symbols for this segment, which is
immediately after the segment definition record and name we just read */
pSegInfo->symFPos = DebugFileSeek( pSegInfo->symfh, 0L, 1 );
}
else {
/* If no .SYM file or segment number too big, then make the segnemt name
be the hex representation of its number */
pSegInfo->symcnt = 0;
segnum = pSegInfo->whoIs.segNum;
n = 4;
lp += n;
while (n--) {
c = (char)(segnum & (USHORT)0xF);
segnum >>= 4;
if (c > 9)
c += 'A' - 10;
else
c += '0';
*--lp = c;
*lp++ = 0;
}
/* Null terminate the segment name string */
lp += 4;
*lp++ = 0;
}
/* Initialize the symbol name pointer to point to a null string, immediately
after the segment name string just created above. */
pSegInfo->lpSymName = lp;
*lp = 0;
return 0;
}
USHORT
pascal near FindSymbol( pSegInfo, offset )
PSEGINFO pSegInfo;
USHORT offset;
{
USHORT i;
long symPos;
char far *lp;
/* If no .SYM file then return failure */
if (pSegInfo->symfh == -1)
return 0xFFFF;
/* No symbol found yet, so make it a null string */
lp = pSegInfo->lpSymName;
*lp = 0;
/* Now do a linear search of the symbol definitions for this segment, looking
for the closest match. The definitions are stored in sorted order */
symPos = DebugFileSeek( pSegInfo->symfh, (long)pSegInfo->symFPos, 0 );
i = (USHORT)pSegInfo->symcnt;
while (i--) {
DebugFileRead( pSegInfo->symfh, (PSZ)&symdef, sizeof( symdef ) );
/* If this is not our symbol then just remember its offset */
if ((USHORT)symdef.sym_val <= offset) {
symPos = DebugFileSeek( pSegInfo->symfh, 0L, 1 ) -
sizeof( symdef );
/* If exact match, exit this loop */
if ((USHORT)symdef.sym_val == offset)
break;
}
else
/* If we went past then exit this loop */
break;
/* Still looking, so seek past this symbols name string to next symbol
definition */
DebugFileSeek( pSegInfo->symfh, (long)symdef.nam_len, 1 );
}
/* Seek to found symdebol definition and read it in, along with the name */
DebugFileSeek( pSegInfo->symfh, (long)symPos, 0 );
DebugFileRead( pSegInfo->symfh, (PSZ)&symdef,
sizeof( symdef ) );
DebugFileRead( pSegInfo->symfh, (PSZ)lp,
(int)((BYTE)symdef.nam_len) );
/* Make the name a null terminated string */
lp += symdef.nam_len;
*lp++ = 0;
/* Return the distance of the passed offset from the value of the symbol */
return offset - symdef.sym_val;
}
/*************************************************************************
*
* GetSymbolInformation(pid, pvoidInfo, pszInfo)
*
* Purpose: To get information about the supplied address
*/
VOID GetSymbolInformation(pid, pvoidInfo, pszInfo)
PID pid;
char far *pvoidInfo;
char *pszInfo;
{
SEGINFO seginfo;
char szTemp[256];
USHORT uOffsetFromSym;
/*
* First try to find the segment in the segment table.
*/
if (IdentifyCodeSegment(&seginfo, pid, SELECTOROF(pvoidInfo)) != 0) {
/*
* It failed to find the segment, ie it was invalid, so
* Simply return INVALID to caller
*/
sprintf(pszInfo,"PID:%d %04x:%04x - INVALID", (SHORT)pid,
SELECTOROF(pvoidInfo), OFFSETOF(pvoidInfo));
return;
}
sprintf(pszInfo,"PID:%d %04x:%04x - %Fs ! ", (SHORT)pid,
SELECTOROF(pvoidInfo), OFFSETOF(pvoidInfo),
seginfo.lpModName);
if (seginfo.symfh == -1) {
sprintf(szTemp,"%04x", seginfo.whoIs.segNum);
strcat(pszInfo, szTemp);
} else {
lstrcat((PSZ)pszInfo, seginfo.lpSegName);
}
uOffsetFromSym = FindSymbol(&seginfo, OFFSETOF(pvoidInfo));
if (uOffsetFromSym != 0xffff) {
strcat(pszInfo, ":");
lstrcat((PSZ)pszInfo, seginfo.lpSymName);
if (uOffsetFromSym != 0) {
sprintf(szTemp, "+%x", uOffsetFromSym);
strcat(pszInfo, szTemp);
}
}
}
/***************************************************************************\
* VOID NEAR ProcessLNOkButton(hwndDlg)
*
* Process the Ok Button for the List Near Dlg proc
\***************************************************************************/
VOID NEAR ProcessLNOkButton(hwndDlg)
HWND hwndDlg;
{
char szTemp[100];
char far *pVoid;
PID pid;
SHORT item;
/*
* For now try using sscanf to convert the string into a
* pointer.
*/
WinQueryDlgItemShort(hwndDlg, DID_PID, &pid, FALSE);
WinQueryDlgItemText(hwndDlg, DID_ADDR, sizeof(szTemp), szTemp);
if ((strchr(szTemp,':') != NULL) && (sscanf(szTemp,"%p", &pVoid)) > 0) {
/* It translated, so try to get info about pointer */
GetSymbolInformation(pid, pVoid, szTemp);
/* For now simply output to output areas */
item = (SHORT)WinSendDlgItemMsg(hwndDlg, DID_SYMLIST,
LM_INSERTITEM, (MPARAM)LIT_END, (MPARAM)(PSZ)szTemp);
WinSendDlgItemMsg(hwndDlg, DID_SYMLIST, LM_SETTOPINDEX,
(MPARAM)item, 0L);
}
/*
* Now clear the text out of the ADDR field, and set the focus
* back to the window
*/
WinSetDlgItemText(hwndDlg, DID_ADDR, "");
WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, DID_ADDR));
}
/***************************************************************************\
* MRESULT NEAR FormatLNDialog(hwndDlg, paswp, prectl)
*
* Process the WM_SIZE message in the List Near Dialog
\***************************************************************************/
MRESULT NEAR FormatLNDialog(hwndDlg, paswp, prclClientX)
HWND hwndDlg;
PSWP paswp;
PRECTL prclClientX;
{
USHORT cy;
USHORT cswp;
HPS hps;
SHORT dy;
register HWND hwndT;
FONTMETRICS fm;
PSWP pswpT;
RECTL rclClient;
SWP swpOk;
SHORT y;
/*
* First let the default frame processing set up the position of
* all of the standard controls. Then we will position the list box
* and the two entry fields to fill in the remainder of the space.
*/
#define PSWPLN(x) (paswp + cswp + x - DID_SYMLIST)
cswp = (USHORT)WinDefDlgProc(hwndDlg, WM_FORMATFRAME, (MPARAM)paswp,
(MPARAM)(PRECTL)&rclClient);
if (prclClientX != NULL)
*prclClientX = rclClient; /* Give caller info */
/*
* Now Add our controls to the SWP list - Verify that the first one
* exists. If not, we probably are initializing the dialog, so
* Simply return what the default Dlg Proc returned.
*/
hwndT = WinWindowFromID(hwndDlg, DID_OK);
if (hwndT == NULL)
return (cswp);
/*
* We need to get a PS, such that we can find out the size of the
* font, to adjust our edit fields such that they wont keep moving
* in.
*/
hps = WinGetPS(hwndDlg);
GpiQueryFontMetrics(hps, (LONG)sizeof(fm), &fm);
WinReleasePS(hps);
WinQueryWindowPos(hwndT, &swpOk);
pswpT=PSWPLN(DID_SYMLIST);
WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_SYMLIST), pswpT);
dy = pswpT->y - (swpOk.y + swpOk.cy);
pswpT->fs = SWP_SIZE;
pswpT->cx = (SHORT)rclClient.xRight - (SHORT)rclClient.xLeft - pswpT->x;
/* First position the top line, just below titlebar */
pswpT=PSWPLN(DID_PIDLABEL);
WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_PIDLABEL), pswpT);
pswpT->fs = SWP_MOVE;
cy = pswpT->cy;
y = pswpT->y = (SHORT)rclClient.yTop - (SHORT)rclClient.yBottom -
cy - dy;
pswpT=PSWPLN(DID_PID);
WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_PID), pswpT);
pswpT->fs = SWP_MOVE;
pswpT->x += (SHORT)fm.lAveCharWidth / 2; /* Take care of margin */
pswpT->y = y;
/* Since Edit control is bigger Setup Start Y for the next row */
y += (cy - pswpT->cy);
/* Now position Addr line below PID line */
pswpT=PSWPLN(DID_ADDRLABEL);
WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_ADDRLABEL), pswpT);
pswpT->fs = SWP_MOVE;
y = (pswpT->y = y - pswpT->cy - dy);
pswpT=PSWPLN(DID_ADDR);
WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_ADDR), pswpT);
pswpT->fs = SWP_MOVE;
pswpT->x += (SHORT)fm.lAveCharWidth / 2; /* Take care of margin */
pswpT->y = y;
/* Now set size of listbox */
y += (cy - pswpT->cy);
pswpT=PSWPLN(DID_SYMLIST);
pswpT->cy = y - dy - pswpT->y;
/*
* Return the count of swps
*/
return ((MRESULT)(cswp + (DID_PID-DID_SYMLIST+1)));
}
/***************************************************************************\
* VOID NEAR EndLNDialog(hwndDlg)
*
* End processing for the List Near Dialog
\***************************************************************************/
VOID NEAR EndLNDialog(hwndDlg)
HWND hwndDlg;
{
/* First Dismiss the dialog and destroy the windows */
WinDismissDlg(hwndDlg, 0);
WinDestroyWindow(hwndDlg);
/* And re-enable the menu item */
WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
MM_SETITEMATTR, MPFROM2SHORT(CMD_LISTNEAR, TRUE),
MPFROM2SHORT(MIA_DISABLED, 0));
}
/***************************************************************************\
* MRESULT CALLBACK ListNearDlgProc(hwnd, msg, mp1, mp2)
*
* Will locate the symbol near the specified address.
\***************************************************************************/
MRESULT CALLBACK ListNearDlgProc(hwnd, msg, mp1, mp2)
HWND hwnd;
USHORT msg;
MPARAM mp1;
MPARAM mp2;
{
PIDINFO pidinfo;
switch (msg) {
case WM_INITDLG:
/* Initialize the dialog items */
WinSetDlgItemText(hwnd, DID_ADDR, "");
DosGetPID(&pidinfo);
WinSetDlgItemShort(hwnd, DID_PID, (USHORT)pidinfo.pid, FALSE);
break;
case WM_SYSCOMMAND:
if (SHORT1FROMMP(mp1) == SC_CLOSE) {
/* End processing the dialog */
EndLNDialog(hwnd);
break;
} else
return(WinDefDlgProc(hwnd, msg, mp1, mp2));
case WM_COMMAND:
switch (SHORT1FROMMP(mp1)) {
case DID_OK:
/*
* Process The Ok Button, by caling ProcessLNOkButton, which
* will add the information to the listbox in our dialog.
*/
ProcessLNOkButton(hwnd);
break;
case DID_CANCEL:
/* End processing the dialog */
EndLNDialog(hwnd);
break;
}
break;
/*
* We want to add our controls into the formating of the frame, so
* we need to add some room onto the SWP list
*/
case WM_QUERYFRAMECTLCOUNT:
return((MRESULT)((SHORT)WinDefDlgProc(hwnd, msg, mp1, mp2) +
(SHORT)(DID_PID-DID_SYMLIST+1)));
break;
/*
* Call FormatLNDialog, to format the dialog
*/
case WM_FORMATFRAME:
return (FormatLNDialog(hwnd, (PSWP)mp1, (PRECTL)mp2));
default:
return(WinDefDlgProc(hwnd, msg, mp1, mp2));
}
return (0L);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.