TPL_PatternCollector.cpp 8.5 KB

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