File:  [OS/2 SDKs] / pmsdk / samples / spy / symbol.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:21 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
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);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.