Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

705 lines
18 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. sym.c
  5. Abstract:
  6. This function contains the 16-bit symbol support for VDMDBG
  7. Author:
  8. Bob Day (bobday) 29-Feb-1992 Grabbed standard header
  9. Revision History:
  10. Neil Sandlin (NeilSa) 15-Jan-1996 Merged with vdmexts
  11. Neil Sandlin (NeilSa) 01-Mar-1997 Moved it to VDMDBG,
  12. Rewrote it
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. #define PRINTF(x) TRUE
  17. #define MYOF_FLAGS (OF_READ | OF_SHARE_DENY_NONE)
  18. #define MAX_MODULE_LIST 200
  19. char ModuleList[MAX_MODULE_LIST][9];
  20. int ModuleListCount = 0;
  21. typedef struct _SYM_MAP {
  22. WORD map_ptr;
  23. WORD map_lsa;
  24. WORD pgm_ent;
  25. WORD abs_cnt;
  26. WORD abs_ptr;
  27. WORD seg_cnt;
  28. WORD seg_ptr;
  29. BYTE sym_nam_max;
  30. BYTE map_nam_len;
  31. char map_name[20];
  32. } SYM_MAP;
  33. typedef struct _SYM_SEG {
  34. WORD nxt_seg;
  35. WORD sym_cnt;
  36. WORD sym_ptr;
  37. WORD seg_lsa;
  38. WORD seg_in[4];
  39. WORD seg_lin;
  40. BYTE seg_ldd;
  41. char seg_cin;
  42. BYTE seg_nam_len;
  43. char seg_name[20];
  44. } SYM_SEG;
  45. typedef struct _SYM_ITEM {
  46. WORD sym_val;
  47. BYTE sym_nam_len;
  48. char sym_name[256];
  49. } SYM_ITEM;
  50. BOOL
  51. FindExport(
  52. LPSTR filename,
  53. WORD segment,
  54. WORD offset,
  55. LPSTR sym_text,
  56. BOOL next,
  57. LONG *dist
  58. )
  59. {
  60. int iFile;
  61. OFSTRUCT ofs;
  62. int rc;
  63. IMAGE_DOS_HEADER doshdr;
  64. IMAGE_OS2_HEADER winhdr;
  65. BYTE Table[65536];
  66. BYTE bBundles;
  67. BYTE bFlags;
  68. BYTE *ptr;
  69. WORD wIndex = 1;
  70. int i;
  71. int this_dist;
  72. int wIndexBest = -1;
  73. char myfilename[256];
  74. #pragma pack(1)
  75. typedef struct
  76. {
  77. BYTE bFlags;
  78. UNALIGNED WORD wSegOffset;
  79. } FENTRY, *PFENTRY;
  80. typedef struct
  81. {
  82. BYTE bFlags;
  83. UNALIGNED WORD wINT3F;
  84. BYTE bSegNumber;
  85. UNALIGNED WORD wSegOffset;
  86. } MENTRY, *PMENTRY;
  87. #pragma pack()
  88. strcpy(myfilename, filename);
  89. if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
  90. //PRINTF("VDMDBG: Error reading file %s\n", filename);
  91. strcpy(myfilename, filename);
  92. strcat(myfilename, ".exe");
  93. if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
  94. //PRINTF("VDMDBG: Error reading file %s\n", myfilename);
  95. strcpy(myfilename, filename);
  96. strcat(myfilename, ".dll");
  97. if (-1 == (iFile=OpenFile(myfilename, &ofs, MYOF_FLAGS))) {
  98. //PRINTF("VDMDBG: Error reading file %s\n", myfilename);
  99. PRINTF("VDMDBG: Error reading file\n");
  100. return FALSE;
  101. }
  102. }
  103. }
  104. rc = _lread(iFile, &doshdr, sizeof(doshdr));
  105. if (rc != sizeof(doshdr)) {
  106. PRINTF("VDMDBG: Error reading DOS header\n");
  107. goto Error;
  108. }
  109. if (doshdr.e_magic != IMAGE_DOS_SIGNATURE) {
  110. PRINTF("VDMDBG: Error - no DOS EXE signature");
  111. goto Error;
  112. }
  113. rc = _llseek(iFile, doshdr.e_lfanew, FILE_BEGIN);
  114. if (rc == -1) {
  115. PRINTF("VDMDBG: Error - could not seek - probably not Win3.1 exe\n");
  116. goto Error;
  117. }
  118. rc = _lread(iFile, &winhdr, sizeof(winhdr));
  119. if (rc != sizeof(winhdr)) {
  120. PRINTF("VDMDBG: Error - could not read WIN header - probably not Win3.1 exe\n");
  121. goto Error;
  122. }
  123. if (winhdr.ne_magic != IMAGE_OS2_SIGNATURE) {
  124. PRINTF("VDMDBG: Error - not WIN EXE signature\n");
  125. goto Error;
  126. }
  127. rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_enttab, FILE_BEGIN);
  128. if (rc == -1) {
  129. PRINTF("VDMDBG: Error - could not seek to entry table\n");
  130. goto Error;
  131. }
  132. rc = _lread(iFile, Table, winhdr.ne_cbenttab);
  133. if (rc != winhdr.ne_cbenttab) {
  134. PRINTF("VDMDBG: Error - could not read entry table\n");
  135. goto Error;
  136. }
  137. ptr = Table;
  138. while (TRUE) {
  139. bBundles = *ptr++;
  140. if (bBundles == 0)
  141. break;
  142. bFlags = *ptr++;
  143. switch (bFlags) {
  144. case 0: // Placeholders
  145. wIndex += bBundles;
  146. break;
  147. case 0xff: // movable segments
  148. for (i=0; i<(int)bBundles; ++i) {
  149. PMENTRY pe = (PMENTRY )ptr;
  150. if (pe->bSegNumber == segment) {
  151. this_dist = (!next) ? offset - pe->wSegOffset
  152. : pe->wSegOffset - offset;
  153. if ( this_dist >= 0 && (this_dist < *dist || *dist == -1) ) {
  154. // mark this as the best match so far
  155. *dist = this_dist;
  156. wIndexBest = wIndex;
  157. }
  158. }
  159. ptr += sizeof(MENTRY);
  160. wIndex++;
  161. }
  162. break;
  163. default: // fixed segments
  164. if ((int)bFlags != segment) {
  165. ptr += (int)bBundles * sizeof(FENTRY);
  166. wIndex += (int)bBundles;
  167. } else {
  168. for (i=0; i<(int)bBundles; ++i) {
  169. PFENTRY pe = (PFENTRY)ptr;
  170. this_dist = (!next) ? offset - pe->wSegOffset
  171. : pe->wSegOffset - offset;
  172. if ( this_dist >= 0 && (this_dist < *dist || *dist == -1) ) {
  173. // mark this as the best match so far
  174. *dist = this_dist;
  175. wIndexBest = wIndex;
  176. }
  177. ptr += sizeof(FENTRY);
  178. wIndex++;
  179. }
  180. }
  181. break;
  182. }
  183. }
  184. if (wIndexBest == -1) {
  185. // no match found - error out
  186. Error:
  187. _lclose(iFile);
  188. return FALSE;
  189. }
  190. // Success: match found
  191. // wIndexBest = ordinal of the function
  192. // segment:offset = address to look up
  193. // *dist = distance from segment:offset to the symbol
  194. // filename = name of .exe/.dll
  195. // Look for the ordinal in the resident name table
  196. rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_restab, FILE_BEGIN);
  197. if (rc == -1) {
  198. PRINTF("VDMDBG: Error - unable to seek to residentname table\n");
  199. goto Error;
  200. }
  201. rc = _lread(iFile, Table, winhdr.ne_modtab-winhdr.ne_restab);
  202. if (rc != winhdr.ne_modtab-winhdr.ne_restab) {
  203. PRINTF("VDMDBG: Error - unable to read entire resident name table\n");
  204. goto Error;
  205. }
  206. ptr = Table;
  207. while (*ptr) {
  208. if ( *(UNALIGNED USHORT *)(ptr+1+*ptr) == (USHORT)wIndexBest) {
  209. // found the matching name
  210. *(ptr+1+*ptr) = '\0'; // null-terminate the function name
  211. strcpy(sym_text, ptr+1);
  212. goto Finished;
  213. }
  214. ptr += *ptr + 3;
  215. }
  216. // Look for the ordinal in the non-resident name table
  217. rc = _llseek(iFile, doshdr.e_lfanew+winhdr.ne_nrestab, FILE_BEGIN);
  218. if (rc == -1) {
  219. PRINTF("VDMDBG: Error - unable to seek to non-residentname table\n");
  220. goto Error;
  221. }
  222. rc = _lread(iFile, Table, winhdr.ne_cbnrestab);
  223. if (rc != winhdr.ne_cbnrestab) {
  224. PRINTF("VDMDBG: Error - unable to read entire non-resident name table\n");
  225. goto Error;
  226. }
  227. ptr = Table;
  228. while (*ptr) {
  229. if ( *(UNALIGNED USHORT *)(ptr+1+*ptr) == (USHORT)wIndexBest) {
  230. // found the matching name
  231. *(ptr+1+*ptr) = '\0'; // null-terminate the function name
  232. strcpy(sym_text, ptr+1);
  233. goto Finished;
  234. }
  235. ptr += *ptr + 3;
  236. }
  237. // fall into error path - no match found
  238. goto Error;
  239. Finished:
  240. _lclose(iFile);
  241. return TRUE;
  242. }
  243. BOOL
  244. ExtractSymbol(
  245. int iFile,
  246. DWORD ulSegPos,
  247. DWORD ulSymPos,
  248. WORD csym,
  249. WORD seglsa,
  250. WORD segment,
  251. DWORD offset,
  252. BOOL next,
  253. LPSTR sym_text,
  254. PLONG pdist
  255. )
  256. {
  257. WORD uLastSymdefPos=0;
  258. /* ulWrap allows for wrapping around with more than 64K of symbols */
  259. DWORD ulWrap=0;
  260. LONG SymOffset;
  261. LONG this_dist;
  262. BOOL fResult = FALSE;
  263. char name_text[256];
  264. for (; csym--; ulSymPos+=sizeof(WORD))
  265. {
  266. WORD uSymdefPos;
  267. SYM_ITEM sym;
  268. if (_llseek(iFile, ulSymPos, FILE_BEGIN) == -1)
  269. return FALSE;
  270. if (_lread(iFile, (LPSTR)&uSymdefPos, sizeof(uSymdefPos)) != sizeof(uSymdefPos))
  271. return FALSE;
  272. if (uSymdefPos < uLastSymdefPos)
  273. ulWrap += 0x10000L;
  274. _llseek(iFile, ulSegPos + uSymdefPos + ulWrap, FILE_BEGIN);
  275. _lread(iFile, (LPSTR)&sym, sizeof(sym));
  276. if (segment == 0) {
  277. SymOffset = (LONG)seglsa*16 + sym.sym_val;
  278. } else {
  279. SymOffset = (LONG)sym.sym_val;
  280. }
  281. // Depending on whether the caller wants the closest symbol
  282. // from below or above, compute the distance from the current
  283. // symbol to the target offset.
  284. switch( next ) {
  285. case FALSE:
  286. this_dist = offset - SymOffset;
  287. break;
  288. case TRUE:
  289. this_dist = SymOffset - offset;
  290. break;
  291. }
  292. //
  293. // Since we don't really know if the current symbol is actually
  294. // the nearest symbol, just remember it if it qualifies. Keep
  295. // the best distance so far in 'dist'.
  296. //
  297. if ((this_dist >= 0) && ((this_dist < *pdist) || (*pdist == -1))) {
  298. *pdist = this_dist;
  299. strncpy(name_text, sym.sym_name, sym.sym_nam_len);
  300. name_text[sym.sym_nam_len] = 0;
  301. fResult = TRUE;
  302. }
  303. uLastSymdefPos = uSymdefPos;
  304. }
  305. if (fResult) {
  306. //
  307. // The scan of the symbols in this segment produced a winner.
  308. // Copy the name and displacement back up to the caller.
  309. //
  310. strcpy(sym_text, name_text);
  311. }
  312. return fResult;
  313. }
  314. BOOL
  315. WalkSegmentsForSymbol(
  316. int iFile,
  317. SYM_MAP *pMap,
  318. ULONG ulMapPos,
  319. WORD segment,
  320. DWORD offset,
  321. BOOL next,
  322. LPSTR sym_text,
  323. PDWORD pDisplacement
  324. )
  325. {
  326. DWORD ulSegPos;
  327. LONG dist = -1;
  328. BOOL fResult = FALSE;
  329. WORD this_seg;
  330. #if 0
  331. /* first, walk absolute segment */
  332. if (fAbsolute && map.abs_cnt != 0) {
  333. /* the thing with seg_ptr below is to allow for an absolute
  334. * segment with more than 64K of symbols: if the segment
  335. * pointer of the next symbol is more than 64K away, then
  336. * add 64K to the beginning of the table of symbol pointers.
  337. */
  338. if (ExtractSymbol(iFile,
  339. ulMapPos,
  340. ulMapPos + pMap->abs_ptr + (pMap->seg_ptr&0xF000)*0x10L,
  341. pMap->abs_cnt,
  342. 0,
  343. segment,
  344. offset,
  345. next,
  346. sym_text,
  347. pDisplacement)) {
  348. return TRUE;
  349. }
  350. }
  351. #endif
  352. /* now walk other segments */
  353. ulSegPos = (DWORD)pMap->seg_ptr * 16;
  354. for (this_seg = 0; this_seg < pMap->seg_cnt; this_seg++) {
  355. SYM_SEG seg;
  356. if (_llseek(iFile, ulSegPos, FILE_BEGIN) == -1)
  357. return FALSE;
  358. if (_lread(iFile, (LPSTR)&seg, sizeof(seg)) != sizeof(seg))
  359. return FALSE;
  360. if ((segment == 0) || (segment == this_seg+1)) {
  361. if (ExtractSymbol(iFile,
  362. ulSegPos,
  363. ulSegPos + seg.sym_ptr,
  364. seg.sym_cnt,
  365. seg.seg_lsa,
  366. segment,
  367. offset,
  368. next,
  369. sym_text,
  370. &dist)) {
  371. fResult = TRUE;
  372. if (segment != 0) {
  373. // only looking in one segment
  374. break;
  375. }
  376. }
  377. }
  378. ulSegPos = (DWORD)seg.nxt_seg * 16;
  379. }
  380. if (fResult) {
  381. *pDisplacement = dist;
  382. }
  383. return fResult;
  384. }
  385. BOOL
  386. WINAPI
  387. VDMGetSymbol(
  388. LPSTR fn,
  389. WORD segment,
  390. DWORD offset,
  391. BOOL bProtectMode,
  392. BOOL next,
  393. LPSTR sym_text,
  394. PDWORD pDisplacement
  395. )
  396. {
  397. int iFile;
  398. char filename[256];
  399. OFSTRUCT ofs;
  400. SYM_MAP map;
  401. SYM_SEG seg;
  402. SYM_ITEM item;
  403. ULONG ulMapPos = 0;
  404. strcpy(filename, fn);
  405. strcat(filename,".sym");
  406. iFile = OpenFile( filename, &ofs, MYOF_FLAGS );
  407. if ( iFile == -1 ) {
  408. // Open the .EXE/.DLL file and see if the address corresponds
  409. // to an exported function.
  410. return(FindExport(fn,segment,(WORD)offset,sym_text,next,pDisplacement));
  411. }
  412. do {
  413. if (_llseek( iFile, ulMapPos, FILE_BEGIN) == -1) {
  414. PRINTF("VDMDBG: GetSymbol failed to seek to map\n");
  415. break;
  416. }
  417. if (_lread( iFile, (LPSTR)&map, sizeof(map)) != sizeof(map)) {
  418. PRINTF("VDMDBG: GetSymbol failed to read map\n");
  419. break;
  420. }
  421. if (WalkSegmentsForSymbol(iFile, &map, ulMapPos,
  422. segment, offset, next,
  423. sym_text, pDisplacement)) {
  424. _lclose( iFile );
  425. return TRUE;
  426. }
  427. } while(ulMapPos);
  428. _lclose( iFile );
  429. return FALSE;
  430. }
  431. BOOL
  432. ExtractValue(
  433. int iFile,
  434. DWORD ulSegPos,
  435. DWORD ulSymPos,
  436. WORD csym,
  437. LPSTR szSymbol,
  438. PWORD pValue
  439. )
  440. {
  441. WORD uLastSymdefPos=0;
  442. /* ulWrap allows for wrapping around with more than 64K of symbols */
  443. DWORD ulWrap=0;
  444. LONG SymOffset;
  445. char name_text[256];
  446. for (; csym--; ulSymPos+=sizeof(WORD))
  447. {
  448. WORD uSymdefPos;
  449. SYM_ITEM sym;
  450. if (_llseek(iFile, ulSymPos, FILE_BEGIN) == -1)
  451. return FALSE;
  452. if (_lread(iFile, (LPSTR)&uSymdefPos, sizeof(uSymdefPos)) != sizeof(uSymdefPos))
  453. return FALSE;
  454. if (uSymdefPos < uLastSymdefPos)
  455. ulWrap += 0x10000L;
  456. _llseek(iFile, ulSegPos + uSymdefPos + ulWrap, FILE_BEGIN);
  457. _lread(iFile, (LPSTR)&sym, sizeof(sym));
  458. strncpy(name_text, sym.sym_name, sym.sym_nam_len);
  459. name_text[sym.sym_nam_len] = 0;
  460. if (_stricmp(szSymbol, name_text) == 0) {
  461. *pValue = sym.sym_val;
  462. return TRUE;
  463. }
  464. uLastSymdefPos = uSymdefPos;
  465. }
  466. return FALSE;
  467. }
  468. BOOL
  469. WalkSegmentsForValue(
  470. int iFile,
  471. SYM_MAP *pMap,
  472. ULONG ulMapPos,
  473. LPSTR szSymbol,
  474. PWORD pSegmentBase,
  475. PWORD pSegmentNumber,
  476. PWORD pValue
  477. )
  478. {
  479. DWORD ulSegPos;
  480. WORD this_seg;
  481. #if 0
  482. /* first, walk absolute segment */
  483. if (fAbsolute && pMap->abs_cnt != 0) {
  484. /* the thing with seg_ptr below is to allow for an absolute
  485. * segment with more than 64K of symbols: if the segment
  486. * pointer of the next symbol is more than 64K away, then
  487. * add 64K to the beginning of the table of symbol pointers.
  488. */
  489. if (ExtractValue(iFile,
  490. ulMapPos,
  491. ulMapPos + pMap->abs_ptr + (pMap->seg_ptr&0xF000)*0x10L,
  492. pMap->abs_cnt,
  493. szSymbol,
  494. pValue)) {
  495. return TRUE;
  496. }
  497. }
  498. #endif
  499. /* now walk other segments */
  500. ulSegPos = (DWORD)pMap->seg_ptr * 16;
  501. for (this_seg = 0; this_seg < pMap->seg_cnt; this_seg++) {
  502. SYM_SEG seg;
  503. if (_llseek(iFile, ulSegPos, FILE_BEGIN) == -1)
  504. return FALSE;
  505. if (_lread(iFile, (LPSTR)&seg, sizeof(seg)) != sizeof(seg))
  506. return FALSE;
  507. if (ExtractValue(iFile,
  508. ulSegPos,
  509. ulSegPos + seg.sym_ptr,
  510. seg.sym_cnt,
  511. szSymbol,
  512. pValue)) {
  513. *pSegmentBase = seg.seg_lsa;
  514. *pSegmentNumber = this_seg+1;
  515. return TRUE;
  516. }
  517. ulSegPos = (DWORD)seg.nxt_seg * 16;
  518. }
  519. return FALSE;
  520. }
  521. BOOL
  522. WalkMapForValue(
  523. LPSTR fn,
  524. LPSTR szSymbol,
  525. PWORD pSelector,
  526. PDWORD pOffset,
  527. PWORD pType
  528. )
  529. {
  530. int iFile;
  531. char filename[256];
  532. OFSTRUCT ofs;
  533. SYM_MAP map;
  534. SYM_SEG seg;
  535. SYM_ITEM item;
  536. ULONG ulMapPos = 0;
  537. WORD SegmentNumber;
  538. WORD SegmentBase;
  539. WORD Value;
  540. strcpy(filename, fn);
  541. strcat(filename,".sym");
  542. iFile = OpenFile( filename, &ofs, MYOF_FLAGS );
  543. if ( iFile == -1 ) {
  544. return FALSE;
  545. }
  546. do {
  547. if (_llseek( iFile, ulMapPos, FILE_BEGIN) == -1) {
  548. PRINTF("VDMDBG: failed to seek to map\n");
  549. break;
  550. }
  551. if (_lread( iFile, (LPSTR)&map, sizeof(map)) != sizeof(map)) {
  552. PRINTF("VDMDBG: failed to read map\n");
  553. break;
  554. }
  555. if (WalkSegmentsForValue(iFile, &map, ulMapPos,
  556. szSymbol, &SegmentBase, &SegmentNumber, &Value)) {
  557. VDM_SEGINFO si;
  558. if (GetInfoBySegmentNumber(fn, SegmentNumber, &si)) {
  559. *pSelector = si.Selector;
  560. if (!si.Type) {
  561. *pType = VDMADDR_V86;
  562. if (!si.SegNumber) {
  563. // This is a "combined" map of all the segments,
  564. // so we need to calculate the offset
  565. *pOffset = (DWORD)SegmentBase*16 + Value;
  566. } else {
  567. // This is a "split" v86 map
  568. *pOffset = (DWORD) Value;
  569. }
  570. } else {
  571. *pType = VDMADDR_PM16;
  572. *pOffset = (DWORD)Value;
  573. }
  574. _lclose( iFile );
  575. return TRUE;
  576. }
  577. }
  578. } while(ulMapPos);
  579. _lclose( iFile );
  580. return FALSE;
  581. }
  582. BOOL
  583. WINAPI
  584. VDMGetAddrExpression(
  585. LPSTR szModule,
  586. LPSTR szSymbol,
  587. PWORD pSelector,
  588. PDWORD pOffset,
  589. PWORD pType
  590. )
  591. {
  592. int iFile;
  593. char filename[256];
  594. OFSTRUCT ofs;
  595. SYM_MAP map;
  596. SYM_SEG seg;
  597. SYM_ITEM item;
  598. ULONG ulMapPos = 0;
  599. if (szModule) {
  600. return(WalkMapForValue(szModule, szSymbol, pSelector, pOffset, pType));
  601. }
  602. return (EnumerateModulesForValue(VDMGetAddrExpression,
  603. szSymbol,
  604. pSelector,
  605. pOffset,
  606. pType));
  607. }