123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- #include "TPL_PatternCollector.h"
- #include "msvc_fixes.h"
- #include <cstring>
- /** \note Fundamental problem: there seems to be no information linking the names
- in the system unit ("V" category) with their routines, except trial and
- error. I have entered a few. There is no guarantee that the same pmap
- offset will map to the same routine in all versions of turbo.tpl. They
- seem to match so far in version 4 and 5.0 */
- #define roundUp(w) ((w + 0x0F) & 0xFFF0)
- extern void fixWildCards(uint8_t pat[]);
- void TPL_PatternCollector::enterSym(FILE *f, const char *name, uint16_t pmapOffset)
- {
- uint16_t pm, cm, codeOffset, pcode;
- uint16_t j;
- /* Enter a symbol with given name */
- allocSym(count);
- strcpy(keys[count].name, name);
- pm = pmap + pmapOffset; /* Pointer to the 4 byte pmap structure */
- fseek(f, unitBase+pm, SEEK_SET);/* Go there */
- cm = readShort(f); /* CSeg map offset */
- codeOffset = readShort(f); /* How far into the code segment is our rtn */
- j = cm / 8; /* Index into the cmap array */
- pcode = csegBase+csegoffs[j]+codeOffset;
- fseek(f, unitBase+pcode, SEEK_SET); /* Go there */
- grab(f,PATLEN); /* Grab the pattern to buf[] */
- fixWildCards(buf); /* Fix the wild cards */
- memcpy(keys[count].pat, buf, PATLEN); /* Copy to the key array */
- count++; /* Done one more */
- }
- void TPL_PatternCollector::allocSym(int count)
- {
- keys.resize(count);
- }
- void TPL_PatternCollector::readCmapOffsets(FILE *f)
- {
- uint16_t cumsize, csize;
- uint16_t i;
- /* Read the cmap table to find the start address of each segment */
- fseek(f, unitBase+cmap, SEEK_SET);
- cumsize = 0;
- csegIdx = 0;
- for (i=cmap; i < pmap; i+=8)
- {
- readShort(f); /* Always 0 */
- csize = readShort(f);
- if (csize == 0xFFFF) continue; /* Ignore the first one... unit init */
- csegoffs[csegIdx++] = cumsize;
- cumsize += csize;
- grab(f,4);
- }
- }
- void TPL_PatternCollector::enterSystemUnit(FILE *f)
- {
- /* The system unit is special. The association between keywords and
- pmap entries is not stored in the .tpl file (as far as I can tell).
- So we hope that they are constant pmap entries.
- */
- fseek(f, 0x0C, SEEK_SET);
- cmap = readShort(f);
- pmap = readShort(f);
- fseek(f, offStCseg, SEEK_SET);
- csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
- printf("CMAP table at %04X\n", cmap);
- printf("PMAP table at %04X\n", pmap);
- printf("Code seg base %04X\n", csegBase);
- readCmapOffsets(f);
- enterSym(f,"INITIALISE", 0x04);
- enterSym(f,"UNKNOWN008", 0x08);
- enterSym(f,"EXIT", 0x0C);
- enterSym(f,"BlockMove", 0x10);
- unknown(f,0x14, 0xC8);
- enterSym(f,"PostIO", 0xC8);
- enterSym(f,"UNKNOWN0CC", 0xCC);
- enterSym(f,"STACKCHK", 0xD0);
- enterSym(f,"UNKNOWN0D4", 0xD4);
- enterSym(f,"WriteString", 0xD8);
- enterSym(f,"WriteInt", 0xDC);
- enterSym(f,"UNKNOWN0E0", 0xE0);
- enterSym(f,"UNKNOWN0E4", 0xE4);
- enterSym(f,"CRLF", 0xE8);
- enterSym(f,"UNKNOWN0EC", 0xEC);
- enterSym(f,"UNKNOWN0F0", 0xF0);
- enterSym(f,"UNKNOWN0F4", 0xF4);
- enterSym(f,"ReadEOL", 0xF8);
- enterSym(f,"Read", 0xFC);
- enterSym(f,"UNKNOWN100", 0x100);
- enterSym(f,"UNKNOWN104", 0x104);
- enterSym(f,"PostWrite", 0x108);
- enterSym(f,"UNKNOWN10C", 0x10C);
- enterSym(f,"Randomize", 0x110);
- unknown(f,0x114, 0x174);
- enterSym(f,"Random", 0x174);
- unknown(f,0x178, 0x1B8);
- enterSym(f,"FloatAdd", 0x1B8); /* A guess! */
- enterSym(f,"FloatSub", 0x1BC); /* disicx - dxbxax -> dxbxax*/
- enterSym(f,"FloatMult", 0x1C0); /* disicx * dxbxax -> dxbxax*/
- enterSym(f,"FloatDivide", 0x1C4); /* disicx / dxbxax -> dxbxax*/
- enterSym(f,"UNKNOWN1C8", 0x1C8);
- enterSym(f,"DoubleToFloat",0x1CC); /* dxax to dxbxax */
- enterSym(f,"UNKNOWN1D0", 0x1D0);
- enterSym(f,"WriteFloat", 0x1DC);
- unknown(f,0x1E0, 0x200);
- }
- void TPL_PatternCollector::readString(FILE *f)
- {
- uint8_t len;
- len = readByte(f);
- grab(f,len);
- buf[len] = '\0';
- }
- void TPL_PatternCollector::unknown(FILE *f, unsigned j, unsigned k)
- {
- /* Mark calls j to k (not inclusive) as unknown */
- unsigned i;
- for (i=j; i < k; i+= 4)
- {
- sprintf((char *)buf, "UNKNOWN%03X", i);
- enterSym(f,(char *)buf, i);
- }
- }
- void TPL_PatternCollector::nextUnit(FILE *f)
- {
- /* Find the start of the next unit */
- uint16_t dsegBase, sizeSyms, sizeOther1, sizeOther2;
- fseek(f, unitBase+offStCseg, SEEK_SET);
- dsegBase = roundUp(readShort(f));
- sizeSyms = roundUp(readShort(f));
- sizeOther1 = roundUp(readShort(f));
- sizeOther2 = roundUp(readShort(f));
- unitBase += dsegBase + sizeSyms + sizeOther1 + sizeOther2;
- fseek(f, unitBase, SEEK_SET);
- if (fread(buf, 1, 4, f) == 4)
- {
- buf[4]='\0';
- printf("Start of unit: found %s\n", buf);
- }
- }
- void TPL_PatternCollector::setVersionSpecifics()
- {
- version = buf[3]; /* The x of TPUx */
- switch (version)
- {
- case '0': /* Version 4.0 */
- offStCseg = 0x14; /* Offset to the LL giving the Cseg start */
- charProc = 'T'; /* Indicates a proc in the dictionary */
- charFunc = 'U'; /* Indicates a function in the dictionary */
- skipPmap = 6; /* Bytes to skip after Func to get pmap offset */
- break;
- case '5': /* Version 5.0 */
- offStCseg = 0x18; /* Offset to the LL giving the Cseg start */
- charProc = 'T'; /* Indicates a proc in the dictionary */
- charFunc = 'U'; /* Indicates a function in the dictionary */
- skipPmap = 1; /* Bytes to skip after Func to get pmap offset */
- break;
- default:
- printf("Unknown version %c!\n", version);
- exit(1);
- }
- }
- void TPL_PatternCollector::savePos(FILE *f)
- {
- if (positionStack.size() >= 20)
- {
- printf("Overflowed filePosn array\n");
- exit(1);
- }
- positionStack.push_back(ftell(f));
- }
- void TPL_PatternCollector::restorePos(FILE *f)
- {
- if (positionStack.empty() == 0)
- {
- printf("Underflowed filePosn array\n");
- exit(1);
- }
- fseek(f, positionStack.back(), SEEK_SET);
- positionStack.pop_back();
- }
- void TPL_PatternCollector::enterUnitProcs(FILE *f)
- {
- uint16_t i, LL;
- uint16_t hash, hsize, dhdr, pmapOff;
- char cat;
- char name[40];
- fseek(f, unitBase+0x0C, SEEK_SET);
- cmap = readShort(f);
- pmap = readShort(f);
- fseek(f, unitBase+offStCseg, SEEK_SET);
- csegBase = roundUp(readShort(f)); /* Round up to next 16 bdry */
- printf("CMAP table at %04X\n", cmap);
- printf("PMAP table at %04X\n", pmap);
- printf("Code seg base %04X\n", csegBase);
- readCmapOffsets(f);
- fseek(f, unitBase+pmap, SEEK_SET); /* Go to first pmap entry */
- if (readShort(f) != 0xFFFF) /* FFFF means none */
- {
- sprintf(name, "UNIT_INIT_%d", ++unitNum);
- enterSym(f,name, 0); /* This is the unit init code */
- }
- fseek(f, unitBase+0x0A, SEEK_SET);
- hash = readShort(f);
- //printf("Hash table at %04X\n", hash);
- fseek(f, unitBase+hash, SEEK_SET);
- hsize = readShort(f);
- //printf("Hash table size %04X\n", hsize);
- for (i=0; i <= hsize; i+= 2)
- {
- dhdr = readShort(f);
- if (dhdr)
- {
- savePos(f);
- fseek(f, unitBase+dhdr, SEEK_SET);
- do
- {
- LL = readShort(f);
- readString(f);
- strcpy(name, (char *)buf);
- cat = readByte(f);
- if ((cat == charProc) or (cat == charFunc))
- {
- grab(f,skipPmap); /* Skip to the pmap */
- pmapOff = readShort(f); /* pmap offset */
- printf("pmap offset for %13s: %04X\n", name, pmapOff);
- enterSym(f,name, pmapOff);
- }
- //printf("%13s %c ", name, cat);
- if (LL)
- {
- //printf("LL seek to %04X\n", LL);
- fseek(f, unitBase+LL, SEEK_SET);
- }
- } while (LL);
- restorePos(f);
- }
- }
- }
- int TPL_PatternCollector::readSyms(FILE *f)
- {
- grab(f,4);
- if ((strncmp((char *)buf, "TPU0", 4) != 0) and ((strncmp((char *)buf, "TPU5", 4) != 0)))
- {
- printf("Not a Turbo Pascal version 4 or 5 library file\n");
- fclose(f);
- exit(1);
- }
- setVersionSpecifics();
- enterSystemUnit(f);
- unitBase = 0;
- do
- {
- nextUnit(f);
- if (feof(f)) break;
- enterUnitProcs(f);
- } while (1);
- return count;
- }
|