TPL_PatternCollector.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include "TPL_PatternCollector.h"
  2. #include "msvc_fixes.h"
  3. #include <cstring>
  4. /** \note Fundamental problem: there seems to be no information linking the names
  5. in the system unit ("V" category) with their routines, except trial and
  6. error. I have entered a few. There is no guarantee that the same pmap
  7. offset will map to the same routine in all versions of turbo.tpl. They
  8. seem to match so far in version 4 and 5.0 */
  9. #define roundUp(w) ((w + 0x0F) & 0xFFF0)
  10. extern void fixWildCards(uint8_t pat[]);
  11. void TPL_PatternCollector::enterSym(FILE *f, const char *name, uint16_t pmapOffset)
  12. {
  13. uint16_t pm, cm, codeOffset, pcode;
  14. uint16_t j;
  15. /* Enter a symbol with given name */
  16. allocSym(count);
  17. strcpy(keys[count].name, name);
  18. pm = pmap + pmapOffset; /* Pointer to the 4 byte pmap structure */
  19. fseek(f, unitBase+pm, SEEK_SET);/* Go there */
  20. cm = readShort(f); /* CSeg map offset */
  21. codeOffset = readShort(f); /* How far into the code segment is our rtn */
  22. j = cm / 8; /* Index into the cmap array */
  23. pcode = csegBase+csegoffs[j]+codeOffset;
  24. fseek(f, unitBase+pcode, SEEK_SET); /* Go there */
  25. grab(f,PATLEN); /* Grab the pattern to buf[] */
  26. fixWildCards(buf); /* Fix the wild cards */
  27. memcpy(keys[count].pat, buf, PATLEN); /* Copy to the key array */
  28. count++; /* Done one more */
  29. }
  30. void TPL_PatternCollector::allocSym(int count)
  31. {
  32. keys.resize(count);
  33. }
  34. void TPL_PatternCollector::readCmapOffsets(FILE *f)
  35. {
  36. uint16_t cumsize, csize;
  37. uint16_t i;
  38. /* Read the cmap table to find the start address of each segment */
  39. fseek(f, unitBase+cmap, SEEK_SET);
  40. cumsize = 0;
  41. csegIdx = 0;
  42. for (i=cmap; i < pmap; i+=8)
  43. {
  44. readShort(f); /* Always 0 */
  45. csize = readShort(f);
  46. if (csize == 0xFFFF) continue; /* Ignore the first one... unit init */
  47. csegoffs[csegIdx++] = cumsize;
  48. cumsize += csize;
  49. grab(f,4);
  50. }
  51. }
  52. void TPL_PatternCollector::enterSystemUnit(FILE *f)
  53. {
  54. /* The system unit is special. The association between keywords and
  55. pmap entries is not stored in the .tpl file (as far as I can tell).
  56. So we hope that they are constant pmap entries.
  57. */
  58. fseek(f, 0x0C, SEEK_SET);
  59. cmap = readShort(f);
  60. pmap = readShort(f);
  61. fseek(f, offStCseg, SEEK_SET);
  62. csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
  63. printf("CMAP table at %04X\n", cmap);
  64. printf("PMAP table at %04X\n", pmap);
  65. printf("Code seg base %04X\n", csegBase);
  66. readCmapOffsets(f);
  67. enterSym(f,"INITIALISE", 0x04);
  68. enterSym(f,"UNKNOWN008", 0x08);
  69. enterSym(f,"EXIT", 0x0C);
  70. enterSym(f,"BlockMove", 0x10);
  71. unknown(f,0x14, 0xC8);
  72. enterSym(f,"PostIO", 0xC8);
  73. enterSym(f,"UNKNOWN0CC", 0xCC);
  74. enterSym(f,"STACKCHK", 0xD0);
  75. enterSym(f,"UNKNOWN0D4", 0xD4);
  76. enterSym(f,"WriteString", 0xD8);
  77. enterSym(f,"WriteInt", 0xDC);
  78. enterSym(f,"UNKNOWN0E0", 0xE0);
  79. enterSym(f,"UNKNOWN0E4", 0xE4);
  80. enterSym(f,"CRLF", 0xE8);
  81. enterSym(f,"UNKNOWN0EC", 0xEC);
  82. enterSym(f,"UNKNOWN0F0", 0xF0);
  83. enterSym(f,"UNKNOWN0F4", 0xF4);
  84. enterSym(f,"ReadEOL", 0xF8);
  85. enterSym(f,"Read", 0xFC);
  86. enterSym(f,"UNKNOWN100", 0x100);
  87. enterSym(f,"UNKNOWN104", 0x104);
  88. enterSym(f,"PostWrite", 0x108);
  89. enterSym(f,"UNKNOWN10C", 0x10C);
  90. enterSym(f,"Randomize", 0x110);
  91. unknown(f,0x114, 0x174);
  92. enterSym(f,"Random", 0x174);
  93. unknown(f,0x178, 0x1B8);
  94. enterSym(f,"FloatAdd", 0x1B8); /* A guess! */
  95. enterSym(f,"FloatSub", 0x1BC); /* disicx - dxbxax -> dxbxax*/
  96. enterSym(f,"FloatMult", 0x1C0); /* disicx * dxbxax -> dxbxax*/
  97. enterSym(f,"FloatDivide", 0x1C4); /* disicx / dxbxax -> dxbxax*/
  98. enterSym(f,"UNKNOWN1C8", 0x1C8);
  99. enterSym(f,"DoubleToFloat",0x1CC); /* dxax to dxbxax */
  100. enterSym(f,"UNKNOWN1D0", 0x1D0);
  101. enterSym(f,"WriteFloat", 0x1DC);
  102. unknown(f,0x1E0, 0x200);
  103. }
  104. void TPL_PatternCollector::readString(FILE *f)
  105. {
  106. uint8_t len;
  107. len = readByte(f);
  108. grab(f,len);
  109. buf[len] = '\0';
  110. }
  111. void TPL_PatternCollector::unknown(FILE *f, unsigned j, unsigned k)
  112. {
  113. /* Mark calls j to k (not inclusive) as unknown */
  114. unsigned i;
  115. for (i=j; i < k; i+= 4)
  116. {
  117. sprintf((char *)buf, "UNKNOWN%03X", i);
  118. enterSym(f,(char *)buf, i);
  119. }
  120. }
  121. void TPL_PatternCollector::nextUnit(FILE *f)
  122. {
  123. /* Find the start of the next unit */
  124. uint16_t dsegBase, sizeSyms, sizeOther1, sizeOther2;
  125. fseek(f, unitBase+offStCseg, SEEK_SET);
  126. dsegBase = roundUp(readShort(f));
  127. sizeSyms = roundUp(readShort(f));
  128. sizeOther1 = roundUp(readShort(f));
  129. sizeOther2 = roundUp(readShort(f));
  130. unitBase += dsegBase + sizeSyms + sizeOther1 + sizeOther2;
  131. fseek(f, unitBase, SEEK_SET);
  132. if (fread(buf, 1, 4, f) == 4)
  133. {
  134. buf[4]='\0';
  135. printf("Start of unit: found %s\n", buf);
  136. }
  137. }
  138. void TPL_PatternCollector::setVersionSpecifics()
  139. {
  140. version = buf[3]; /* The x of TPUx */
  141. switch (version)
  142. {
  143. case '0': /* Version 4.0 */
  144. offStCseg = 0x14; /* Offset to the LL giving the Cseg start */
  145. charProc = 'T'; /* Indicates a proc in the dictionary */
  146. charFunc = 'U'; /* Indicates a function in the dictionary */
  147. skipPmap = 6; /* Bytes to skip after Func to get pmap offset */
  148. break;
  149. case '5': /* Version 5.0 */
  150. offStCseg = 0x18; /* Offset to the LL giving the Cseg start */
  151. charProc = 'T'; /* Indicates a proc in the dictionary */
  152. charFunc = 'U'; /* Indicates a function in the dictionary */
  153. skipPmap = 1; /* Bytes to skip after Func to get pmap offset */
  154. break;
  155. default:
  156. printf("Unknown version %c!\n", version);
  157. exit(1);
  158. }
  159. }
  160. void TPL_PatternCollector::savePos(FILE *f)
  161. {
  162. if (positionStack.size() >= 20)
  163. {
  164. printf("Overflowed filePosn array\n");
  165. exit(1);
  166. }
  167. positionStack.push_back(ftell(f));
  168. }
  169. void TPL_PatternCollector::restorePos(FILE *f)
  170. {
  171. if (positionStack.empty() == 0)
  172. {
  173. printf("Underflowed filePosn array\n");
  174. exit(1);
  175. }
  176. fseek(f, positionStack.back(), SEEK_SET);
  177. positionStack.pop_back();
  178. }
  179. void TPL_PatternCollector::enterUnitProcs(FILE *f)
  180. {
  181. uint16_t i, LL;
  182. uint16_t hash, hsize, dhdr, pmapOff;
  183. char cat;
  184. char name[40];
  185. fseek(f, unitBase+0x0C, SEEK_SET);
  186. cmap = readShort(f);
  187. pmap = readShort(f);
  188. fseek(f, unitBase+offStCseg, SEEK_SET);
  189. csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
  190. printf("CMAP table at %04X\n", cmap);
  191. printf("PMAP table at %04X\n", pmap);
  192. printf("Code seg base %04X\n", csegBase);
  193. readCmapOffsets(f);
  194. fseek(f, unitBase+pmap, SEEK_SET); /* Go to first pmap entry */
  195. if (readShort(f) != 0xFFFF) /* FFFF means none */
  196. {
  197. sprintf(name, "UNIT_INIT_%d", ++unitNum);
  198. enterSym(f,name, 0); /* This is the unit init code */
  199. }
  200. fseek(f, unitBase+0x0A, SEEK_SET);
  201. hash = readShort(f);
  202. //printf("Hash table at %04X\n", hash);
  203. fseek(f, unitBase+hash, SEEK_SET);
  204. hsize = readShort(f);
  205. //printf("Hash table size %04X\n", hsize);
  206. for (i=0; i <= hsize; i+= 2)
  207. {
  208. dhdr = readShort(f);
  209. if (dhdr)
  210. {
  211. savePos(f);
  212. fseek(f, unitBase+dhdr, SEEK_SET);
  213. do
  214. {
  215. LL = readShort(f);
  216. readString(f);
  217. strcpy(name, (char *)buf);
  218. cat = readByte(f);
  219. if ((cat == charProc) or (cat == charFunc))
  220. {
  221. grab(f,skipPmap); /* Skip to the pmap */
  222. pmapOff = readShort(f); /* pmap offset */
  223. printf("pmap offset for %13s: %04X\n", name, pmapOff);
  224. enterSym(f,name, pmapOff);
  225. }
  226. //printf("%13s %c ", name, cat);
  227. if (LL)
  228. {
  229. //printf("LL seek to %04X\n", LL);
  230. fseek(f, unitBase+LL, SEEK_SET);
  231. }
  232. } while (LL);
  233. restorePos(f);
  234. }
  235. }
  236. }
  237. int TPL_PatternCollector::readSyms(FILE *f)
  238. {
  239. grab(f,4);
  240. if ((strncmp((char *)buf, "TPU0", 4) != 0) and ((strncmp((char *)buf, "TPU5", 4) != 0)))
  241. {
  242. printf("Not a Turbo Pascal version 4 or 5 library file\n");
  243. fclose(f);
  244. exit(1);
  245. }
  246. setVersionSpecifics();
  247. enterSystemUnit(f);
  248. unitBase = 0;
  249. do
  250. {
  251. nextUnit(f);
  252. if (feof(f)) break;
  253. enterUnitProcs(f);
  254. } while (1);
  255. return count;
  256. }