|
|
1.1 root 1: /***************************************************************************\
2:
3: Module Name: SYMBOL.C
4:
5: This module contains the code for displaying symbols for a specified address.
6:
7: \***************************************************************************/
8:
9: #define INCL_DOSPROCESS
10: #define INCL_GPILCIDS
11: #define INCL_WINDIALOGS
12: #define INCL_WINFRAMEMGR
13: #define INCL_WINHEAP /* needed for spy.h */
14: #define INCL_WININPUT
15: #define INCL_WINLISTBOXES
16: #define INCL_WINMENUS
17: #define INCL_WINMESSAGEMGR
18: #define INCL_WINPOINTERS /* needed for spy.h */
19: #define INCL_WINWINDOWMGR
20: #include <os2.h>
21: #include <stdio.h>
22: #include <string.h>
23: #include "spy.h"
24: #include <spyhook.h>
25: #include "symbol.h"
26:
27: WHOISINFO whoIs;
28: MAPDEF mapdef;
29: MAPEND mapend;
30: SEGDEF segdef;
31: SYMDEF symdef;
32:
33: extern VOID lstrcat(PSZ, PSZ);
34: extern void OutputString(char [], SHORT); /* Output string to output devices */
35: extern BOOL FValidPointer (CHAR FAR *pVoid, SHORT cbStruct);
36: extern BOOL FGuessValidPointer (CHAR FAR *pVoid, SHORT cbStruct);
37:
38:
39: extern HWND hwndSpyFrame;
40: extern HAB hab;
41:
42: /* Function prototypes */
43: HWND HwndFrameFromPID(PID);
44: VOID GetSymbolInformation(PID, char far *, char *);
45: VOID NEAR ProcessLNOkButton(HWND);
46: MRESULT NEAR FormatLNDialog(HWND, PSWP, PRECTL);
47: VOID NEAR EndLNDialog(HWND);
48: MRESULT CALLBACK ListNearDlgProc(HWND, USHORT, MPARAM, MPARAM);
49:
50:
51: /***************************************************************************\
52: * hwnd HwndFrameFromPID(pid)
53: *
54: * This function attempts to locate a frame window that was
55: * created by the specified PID. It returns NULL if none are found.
56: \***************************************************************************/
57: HWND HwndFrameFromPID(pid)
58: PID pid;
59: {
60: HENUM henum;
61: HWND hwnd;
62: PID pidWindow;
63: TID tidWindow;
64: char szClassName[50]; /* Class name of window */
65: CLASSINFO classinfo; /* Information about class */
66:
67: henum = WinBeginEnumWindows(HWND_DESKTOP);
68: if (henum == NULL)
69: return (NULL);
70:
71: while ((hwnd = WinGetNextWindow(henum)) != NULL) {
72: WinQueryWindowProcess(hwnd, &pidWindow, &tidWindow);
73: WinLockWindow(hwnd, FALSE);
74: if (pid == pidWindow) {
75: /* See if a frame window */
76: WinQueryClassName(hwnd, sizeof(szClassName),
77: (PSZ)szClassName);
78: if (WinQueryClassInfo(hab, (PSZ)szClassName, &classinfo) &&
79: (classinfo.flClassStyle & CS_FRAME))
80: break; /* We have our frame */
81: }
82: }
83:
84: WinEndEnumWindows(henum);
85: return (hwnd);
86: }
87:
88:
89:
90: /***************************************************************************\
91: * int IdentifyCodeSegment(lpSegInfo, pid, selector)
92: *
93: * Identifies the code selector for the specified process.
94: * NOTE: The process is currently ignored, but later will somehow
95: * return information in the context of the specified process ID.
96: \***************************************************************************/
97: int
98: pascal near IdentifyCodeSegment( pSegInfo, pid, selector )
99: PSEGINFO pSegInfo;
100: PID pid;
101: USHORT selector;
102: {
103: char far *lp;
104: char *np;
105: int n;
106: BYTE c;
107: USHORT segnum;
108: USHORT seg_ptr;
109: USHORT uTemp;
110: int rc;
111: PIDINFO pidinfo;
112: HWND hwndPIDFrame;
113:
114: /* If new selector matches the current one, then nothing to do */
115: if ((pSegInfo->pid == pid) && (pSegInfo->selector == selector))
116: return 0;
117:
118: /*
119: * Try to identify the code selector. We will first try in the context
120: * of our process. If this fails, or if we find that the segment is
121: * associated with our program and it is not our PID, we will attempt
122: * to get the symbol in the specified PID context, with the help of
123: * our hooks.
124: */
125: DosGetPID(&pidinfo);
126: rc = IdentifyCodeSelector( selector, (PWHOISINFO)&whoIs );
127: if ((pid != pidinfo.pid) && (rc == 0)) {
128: /*
129: * User asked for a different context, and symbol was found.
130: * If the symbol was in our .exe we will ignore what we found,
131: * and try again.
132: */
133: /* First get past the module name */
134: np = whoIs.names;
135: while (*np++)
136: ;
137: /* Now go through the pathname */
138: while (*np) {
139: if (*np++ == '.') {
140: if (strcmp(np,"EXE") == 0) {
141: rc = 1; /* It is in our exe, so set errr condition */
142: break; /* no need to go on */
143: }
144: }
145: }
146: }
147:
148: if (rc) {
149: /*
150: * We need to try in other PID context
151: */
152: if ((pid == pidinfo.pid) ||
153: ((hwndPIDFrame = HwndFrameFromPID(pid)) == NULL))
154: return (rc); /* segment not found or no way to find segment */
155:
156: /* Lets use the hook */
157: SpySetLNSymbolPID(pid, selector);
158:
159: /* HACK: Send message to frame known to send another message */
160: WinSendMsg(hwndPIDFrame, WM_QUERYTASKFOCUS, 0L, 0L);
161:
162: if (SpyGetLNSymbolSelector(&whoIs) != 0)
163: return (1); /* Still did not find the symbol */
164:
165: }
166:
167:
168: /* It is a valid code selector, make it the new current selector */
169: pSegInfo->selector = selector;
170: pSegInfo->pid = pid;
171:
172: /* Is the new selector in the same module? */
173: if (pSegInfo->lpSegName && pSegInfo->whoIs.mte == whoIs.mte)
174: pSegInfo->whoIs.segNum = whoIs.segNum; /* Yes, just copy seg# */
175: else {
176:
177: /* New module, get segment #, mte handle, module name and pathstring */
178: pSegInfo->whoIs = whoIs;
179:
180: /* Generate separate pointers to module name and pathstring */
181: lp = &pSegInfo->whoIs.names[0];
182: pSegInfo->lpModName = lp;
183: while (*lp++)
184: ;
185: pSegInfo->lpPathName = lp;
186:
187: /* Change pathstring extension to be .SYM */
188: while (*lp)
189: if (*lp++ == '.') {
190: *lp++ = 'S';
191: *lp++ = 'Y';
192: *lp++ = 'M';
193: }
194: lp++;
195:
196: /*
197: * No current segment name or symbol name, so make them point to
198: * null string
199: */
200: *lp = 0;
201: pSegInfo->lpSegName = lp;
202: pSegInfo->lpSymName = 0L;
203:
204: /* Close any currently open .SYM file and then open the new .SYM file */
205: if (pSegInfo->symfh != -1)
206: pSegInfo->symfh = DosClose((HFILE)pSegInfo->symfh );
207:
208: if (DosOpen(pSegInfo->lpPathName, (PHFILE)&pSegInfo->symfh,
209: (PUSHORT)&uTemp,
210: 0L, 0, 1, 0x00c0, 0L) == 0) {
211:
212: /* Read in .SYM file header and save segment count and pointer */
213:
214: DebugFileRead( pSegInfo->symfh, (PSZ)&mapdef, sizeof( mapdef ) );
215: pSegInfo->segcnt = mapdef.seg_cnt;
216: pSegInfo->segptr = mapdef.seg_ptr;
217:
218: /* Read version of MAPSYM that produced this file.
219: If not a version 4 file then ignore the file */
220:
221: DebugFileSeek( pSegInfo->symfh, (long)-sizeof( mapend ), 2 );
222: DebugFileRead( pSegInfo->symfh, (PSZ)&mapend, sizeof( mapend ) );
223: if (mapend.ver != 4)
224: pSegInfo->symfh = DosClose( (HFILE)pSegInfo->symfh );
225: }
226: }
227:
228: /* Point to segment name buffer and make it a null string for now */
229:
230: lp = pSegInfo->lpSegName;
231: *lp = 0;
232:
233: /* If we have an open .SYM file, search for segment definition record */
234:
235: if (pSegInfo->symfh != -1 && pSegInfo->whoIs.segNum < pSegInfo->segcnt) {
236:
237: /* Start with first segment definition and read segNum definitions */
238:
239: seg_ptr = pSegInfo->segptr;
240: n = pSegInfo->whoIs.segNum;
241: while (n--) {
242: DebugFileSeek( pSegInfo->symfh, (long)seg_ptr, 4 );
243: DebugFileRead( pSegInfo->symfh, (PSZ)&segdef, sizeof( segdef ) );
244: seg_ptr = (USHORT)segdef.nxt_seg;
245: }
246:
247: /* Now read in the segment name string associated with this segment
248: and make it a null terminated string */
249:
250: DebugFileRead( pSegInfo->symfh, (PSZ)(lp),
251: (int)((BYTE)segdef.nam_len) );
252: lp += segdef.nam_len;
253: *lp++ = 0;
254:
255: /* Remember the count of symbols for this segment */
256:
257: pSegInfo->symcnt = segdef.sym_cnt;
258:
259:
260: /* Remember the file offset of the symbols for this segment, which is
261: immediately after the segment definition record and name we just read */
262:
263: pSegInfo->symFPos = DebugFileSeek( pSegInfo->symfh, 0L, 1 );
264: }
265: else {
266: /* If no .SYM file or segment number too big, then make the segnemt name
267: be the hex representation of its number */
268:
269: pSegInfo->symcnt = 0;
270:
271: segnum = pSegInfo->whoIs.segNum;
272: n = 4;
273: lp += n;
274: while (n--) {
275: c = (char)(segnum & (USHORT)0xF);
276: segnum >>= 4;
277: if (c > 9)
278: c += 'A' - 10;
279: else
280: c += '0';
281: *--lp = c;
282: *lp++ = 0;
283: }
284:
285: /* Null terminate the segment name string */
286:
287: lp += 4;
288: *lp++ = 0;
289: }
290:
291: /* Initialize the symbol name pointer to point to a null string, immediately
292: after the segment name string just created above. */
293:
294: pSegInfo->lpSymName = lp;
295: *lp = 0;
296:
297: return 0;
298: }
299:
300:
301: USHORT
302: pascal near FindSymbol( pSegInfo, offset )
303: PSEGINFO pSegInfo;
304: USHORT offset;
305: {
306: USHORT i;
307: long symPos;
308: char far *lp;
309:
310: /* If no .SYM file then return failure */
311:
312: if (pSegInfo->symfh == -1)
313: return 0xFFFF;
314:
315: /* No symbol found yet, so make it a null string */
316:
317: lp = pSegInfo->lpSymName;
318: *lp = 0;
319:
320: /* Now do a linear search of the symbol definitions for this segment, looking
321: for the closest match. The definitions are stored in sorted order */
322:
323: symPos = DebugFileSeek( pSegInfo->symfh, (long)pSegInfo->symFPos, 0 );
324: i = (USHORT)pSegInfo->symcnt;
325: while (i--) {
326: DebugFileRead( pSegInfo->symfh, (PSZ)&symdef, sizeof( symdef ) );
327:
328: /* If this is not our symbol then just remember its offset */
329:
330: if ((USHORT)symdef.sym_val <= offset) {
331: symPos = DebugFileSeek( pSegInfo->symfh, 0L, 1 ) -
332: sizeof( symdef );
333:
334: /* If exact match, exit this loop */
335:
336: if ((USHORT)symdef.sym_val == offset)
337: break;
338: }
339: else
340: /* If we went past then exit this loop */
341:
342: break;
343:
344: /* Still looking, so seek past this symbols name string to next symbol
345: definition */
346:
347: DebugFileSeek( pSegInfo->symfh, (long)symdef.nam_len, 1 );
348: }
349:
350: /* Seek to found symdebol definition and read it in, along with the name */
351:
352: DebugFileSeek( pSegInfo->symfh, (long)symPos, 0 );
353: DebugFileRead( pSegInfo->symfh, (PSZ)&symdef,
354: sizeof( symdef ) );
355: DebugFileRead( pSegInfo->symfh, (PSZ)lp,
356: (int)((BYTE)symdef.nam_len) );
357:
358: /* Make the name a null terminated string */
359:
360: lp += symdef.nam_len;
361: *lp++ = 0;
362:
363: /* Return the distance of the passed offset from the value of the symbol */
364:
365: return offset - symdef.sym_val;
366: }
367:
368:
369:
370: /*************************************************************************
371: *
372: * GetSymbolInformation(pid, pvoidInfo, pszInfo)
373: *
374: * Purpose: To get information about the supplied address
375: */
376: VOID GetSymbolInformation(pid, pvoidInfo, pszInfo)
377: PID pid;
378: char far *pvoidInfo;
379: char *pszInfo;
380: {
381: SEGINFO seginfo;
382: char szTemp[256];
383: USHORT uOffsetFromSym;
384:
385:
386: /*
387: * First try to find the segment in the segment table.
388: */
389: if (IdentifyCodeSegment(&seginfo, pid, SELECTOROF(pvoidInfo)) != 0) {
390:
391: /*
392: * It failed to find the segment, ie it was invalid, so
393: * Simply return INVALID to caller
394: */
395: sprintf(pszInfo,"PID:%d %04x:%04x - INVALID", (SHORT)pid,
396: SELECTOROF(pvoidInfo), OFFSETOF(pvoidInfo));
397: return;
398: }
399:
400:
401: sprintf(pszInfo,"PID:%d %04x:%04x - %Fs ! ", (SHORT)pid,
402: SELECTOROF(pvoidInfo), OFFSETOF(pvoidInfo),
403: seginfo.lpModName);
404:
405: if (seginfo.symfh == -1) {
406: sprintf(szTemp,"%04x", seginfo.whoIs.segNum);
407: strcat(pszInfo, szTemp);
408: } else {
409: lstrcat((PSZ)pszInfo, seginfo.lpSegName);
410: }
411:
412: uOffsetFromSym = FindSymbol(&seginfo, OFFSETOF(pvoidInfo));
413: if (uOffsetFromSym != 0xffff) {
414: strcat(pszInfo, ":");
415:
416: lstrcat((PSZ)pszInfo, seginfo.lpSymName);
417: if (uOffsetFromSym != 0) {
418: sprintf(szTemp, "+%x", uOffsetFromSym);
419: strcat(pszInfo, szTemp);
420: }
421: }
422: }
423:
424:
425: /***************************************************************************\
426: * VOID NEAR ProcessLNOkButton(hwndDlg)
427: *
428: * Process the Ok Button for the List Near Dlg proc
429: \***************************************************************************/
430: VOID NEAR ProcessLNOkButton(hwndDlg)
431: HWND hwndDlg;
432: {
433: char szTemp[100];
434: char far *pVoid;
435: PID pid;
436: SHORT item;
437:
438: /*
439: * For now try using sscanf to convert the string into a
440: * pointer.
441: */
442: WinQueryDlgItemShort(hwndDlg, DID_PID, &pid, FALSE);
443: WinQueryDlgItemText(hwndDlg, DID_ADDR, sizeof(szTemp), szTemp);
444: if ((strchr(szTemp,':') != NULL) && (sscanf(szTemp,"%p", &pVoid)) > 0) {
445: /* It translated, so try to get info about pointer */
446: GetSymbolInformation(pid, pVoid, szTemp);
447:
448: /* For now simply output to output areas */
449: item = (SHORT)WinSendDlgItemMsg(hwndDlg, DID_SYMLIST,
450: LM_INSERTITEM, (MPARAM)LIT_END, (MPARAM)(PSZ)szTemp);
451:
452: WinSendDlgItemMsg(hwndDlg, DID_SYMLIST, LM_SETTOPINDEX,
453: (MPARAM)item, 0L);
454: }
455:
456: /*
457: * Now clear the text out of the ADDR field, and set the focus
458: * back to the window
459: */
460: WinSetDlgItemText(hwndDlg, DID_ADDR, "");
461: WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, DID_ADDR));
462: }
463:
464: /***************************************************************************\
465: * MRESULT NEAR FormatLNDialog(hwndDlg, paswp, prectl)
466: *
467: * Process the WM_SIZE message in the List Near Dialog
468: \***************************************************************************/
469: MRESULT NEAR FormatLNDialog(hwndDlg, paswp, prclClientX)
470: HWND hwndDlg;
471: PSWP paswp;
472: PRECTL prclClientX;
473: {
474: USHORT cy;
475: USHORT cswp;
476: HPS hps;
477: SHORT dy;
478: register HWND hwndT;
479: FONTMETRICS fm;
480: PSWP pswpT;
481: RECTL rclClient;
482: SWP swpOk;
483: SHORT y;
484:
485: /*
486: * First let the default frame processing set up the position of
487: * all of the standard controls. Then we will position the list box
488: * and the two entry fields to fill in the remainder of the space.
489: */
490:
491: #define PSWPLN(x) (paswp + cswp + x - DID_SYMLIST)
492:
493:
494: cswp = (USHORT)WinDefDlgProc(hwndDlg, WM_FORMATFRAME, (MPARAM)paswp,
495: (MPARAM)(PRECTL)&rclClient);
496: if (prclClientX != NULL)
497: *prclClientX = rclClient; /* Give caller info */
498:
499:
500: /*
501: * Now Add our controls to the SWP list - Verify that the first one
502: * exists. If not, we probably are initializing the dialog, so
503: * Simply return what the default Dlg Proc returned.
504: */
505: hwndT = WinWindowFromID(hwndDlg, DID_OK);
506: if (hwndT == NULL)
507: return (cswp);
508:
509: /*
510: * We need to get a PS, such that we can find out the size of the
511: * font, to adjust our edit fields such that they wont keep moving
512: * in.
513: */
514: hps = WinGetPS(hwndDlg);
515: GpiQueryFontMetrics(hps, (LONG)sizeof(fm), &fm);
516: WinReleasePS(hps);
517:
518: WinQueryWindowPos(hwndT, &swpOk);
519:
520: pswpT=PSWPLN(DID_SYMLIST);
521: WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_SYMLIST), pswpT);
522: dy = pswpT->y - (swpOk.y + swpOk.cy);
523: pswpT->fs = SWP_SIZE;
524: pswpT->cx = (SHORT)rclClient.xRight - (SHORT)rclClient.xLeft - pswpT->x;
525:
526: /* First position the top line, just below titlebar */
527: pswpT=PSWPLN(DID_PIDLABEL);
528: WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_PIDLABEL), pswpT);
529: pswpT->fs = SWP_MOVE;
530: cy = pswpT->cy;
531: y = pswpT->y = (SHORT)rclClient.yTop - (SHORT)rclClient.yBottom -
532: cy - dy;
533:
534: pswpT=PSWPLN(DID_PID);
535: WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_PID), pswpT);
536: pswpT->fs = SWP_MOVE;
537: pswpT->x += (SHORT)fm.lAveCharWidth / 2; /* Take care of margin */
538: pswpT->y = y;
539:
540: /* Since Edit control is bigger Setup Start Y for the next row */
541: y += (cy - pswpT->cy);
542:
543:
544: /* Now position Addr line below PID line */
545: pswpT=PSWPLN(DID_ADDRLABEL);
546: WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_ADDRLABEL), pswpT);
547: pswpT->fs = SWP_MOVE;
548: y = (pswpT->y = y - pswpT->cy - dy);
549:
550: pswpT=PSWPLN(DID_ADDR);
551: WinQueryWindowPos(hwndT = WinWindowFromID(hwndDlg, DID_ADDR), pswpT);
552: pswpT->fs = SWP_MOVE;
553: pswpT->x += (SHORT)fm.lAveCharWidth / 2; /* Take care of margin */
554: pswpT->y = y;
555:
556: /* Now set size of listbox */
557: y += (cy - pswpT->cy);
558:
559: pswpT=PSWPLN(DID_SYMLIST);
560: pswpT->cy = y - dy - pswpT->y;
561:
562:
563: /*
564: * Return the count of swps
565: */
566: return ((MRESULT)(cswp + (DID_PID-DID_SYMLIST+1)));
567: }
568:
569:
570:
571:
572: /***************************************************************************\
573: * VOID NEAR EndLNDialog(hwndDlg)
574: *
575: * End processing for the List Near Dialog
576: \***************************************************************************/
577: VOID NEAR EndLNDialog(hwndDlg)
578: HWND hwndDlg;
579: {
580: /* First Dismiss the dialog and destroy the windows */
581: WinDismissDlg(hwndDlg, 0);
582: WinDestroyWindow(hwndDlg);
583:
584: /* And re-enable the menu item */
585: WinSendMsg(WinWindowFromID(hwndSpyFrame, FID_MENU),
586: MM_SETITEMATTR, MPFROM2SHORT(CMD_LISTNEAR, TRUE),
587: MPFROM2SHORT(MIA_DISABLED, 0));
588:
589: }
590:
591:
592:
593: /***************************************************************************\
594: * MRESULT CALLBACK ListNearDlgProc(hwnd, msg, mp1, mp2)
595: *
596: * Will locate the symbol near the specified address.
597: \***************************************************************************/
598: MRESULT CALLBACK ListNearDlgProc(hwnd, msg, mp1, mp2)
599: HWND hwnd;
600: USHORT msg;
601: MPARAM mp1;
602: MPARAM mp2;
603: {
604: PIDINFO pidinfo;
605:
606: switch (msg) {
607:
608: case WM_INITDLG:
609: /* Initialize the dialog items */
610: WinSetDlgItemText(hwnd, DID_ADDR, "");
611: DosGetPID(&pidinfo);
612: WinSetDlgItemShort(hwnd, DID_PID, (USHORT)pidinfo.pid, FALSE);
613: break;
614:
615: case WM_SYSCOMMAND:
616: if (SHORT1FROMMP(mp1) == SC_CLOSE) {
617: /* End processing the dialog */
618: EndLNDialog(hwnd);
619: break;
620: } else
621: return(WinDefDlgProc(hwnd, msg, mp1, mp2));
622:
623:
624: case WM_COMMAND:
625: switch (SHORT1FROMMP(mp1)) {
626: case DID_OK:
627:
628: /*
629: * Process The Ok Button, by caling ProcessLNOkButton, which
630: * will add the information to the listbox in our dialog.
631: */
632: ProcessLNOkButton(hwnd);
633: break;
634:
635: case DID_CANCEL:
636: /* End processing the dialog */
637: EndLNDialog(hwnd);
638: break;
639: }
640:
641: break;
642:
643: /*
644: * We want to add our controls into the formating of the frame, so
645: * we need to add some room onto the SWP list
646: */
647: case WM_QUERYFRAMECTLCOUNT:
648: return((MRESULT)((SHORT)WinDefDlgProc(hwnd, msg, mp1, mp2) +
649: (SHORT)(DID_PID-DID_SYMLIST+1)));
650: break;
651:
652: /*
653: * Call FormatLNDialog, to format the dialog
654: */
655: case WM_FORMATFRAME:
656: return (FormatLNDialog(hwnd, (PSWP)mp1, (PRECTL)mp2));
657:
658: default:
659: return(WinDefDlgProc(hwnd, msg, mp1, mp2));
660: }
661:
662: return (0L);
663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.