Browse Source

Update the dcc tools code

Artur K 9 years ago
parent
commit
842687726f

+ 1 - 1
CMakeLists.txt

@@ -27,7 +27,7 @@ enable_testing()
 ENDIF()
 
 
-llvm_map_components_to_libnames(REQ_LLVM_LIBRARIES jit native mc support tablegen)
+llvm_map_components_to_libnames(REQ_LLVM_LIBRARIES native mc support tablegen)
 INCLUDE_DIRECTORIES(
     3rd_party/libdisasm
     include

+ 77 - 0
common/PatternCollector.h

@@ -1,5 +1,82 @@
 #ifndef PATTERNCOLLECTOR
 #define PATTERNCOLLECTOR
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <vector>
 
+#define	SYMLEN	16			/* Number of chars in the symbol name, incl null */
+#define PATLEN	23			/* Number of bytes in the pattern part */
+
+struct HASHENTRY
+{
+    char name[SYMLEN];		/* The symbol name */
+    uint8_t pat [PATLEN];		/* The pattern */
+    uint16_t offset;			/* Offset (needed temporarily) */
+};
+
+struct PatternCollector {
+    uint8_t buf[100], bufSave[7];	/* Temp buffer for reading the file */
+    uint16_t readShort(FILE *f)
+    {
+        uint8_t b1, b2;
+
+        if (fread(&b1, 1, 1, f) != 1)
+        {
+            printf("Could not read\n");
+            exit(11);
+        }
+        if (fread(&b2, 1, 1, f) != 1)
+        {
+            printf("Could not read\n");
+            exit(11);
+        }
+        return (b2 << 8) + b1;
+    }
+
+    void grab(FILE *f,int n)
+    {
+        if (fread(buf, 1, n, f) != (size_t)n)
+        {
+            printf("Could not read\n");
+            exit(11);
+        }
+    }
+
+    uint8_t readByte(FILE *f)
+    {
+        uint8_t b;
+
+        if (fread(&b, 1, 1, f) != 1)
+        {
+            printf("Could not read\n");
+            exit(11);
+        }
+        return b;
+    }
+
+    uint16_t readWord(FILE *fl)
+    {
+        uint8_t b1, b2;
+
+        b1 = readByte(fl);
+        b2 = readByte(fl);
+
+        return b1 + (b2 << 8);
+    }
+
+    /* Called by map(). Return the i+1th key in *pKeys */
+    uint8_t *getKey(int i)
+    {
+        return keys[i].pat;
+    }
+    /* Display key i */
+    void dispKey(int i)
+    {
+        printf("%s", keys[i].name);
+    }
+    std::vector<HASHENTRY> keys; /* array of keys */
+    virtual int readSyms(FILE *f)=0;
+};
 #endif // PATTERNCOLLECTOR
 

+ 1 - 0
src/DccFrontend.cpp

@@ -211,6 +211,7 @@ struct ComLoader : public DosLoader {
         return false;
     }
     bool load(PROG &prog,QFile &fp) {
+        fp.seek(0);
         /* COM file
          * In this case the load module size is just the file length
          */

+ 2 - 2
src/chklib.cpp

@@ -15,7 +15,7 @@
 #include <stdlib.h>
 #include <memory.h>
 #include <string.h>
-
+PerfectHash g_pattern_hasher;
 #define  NIL   -1                   /* Used like NULL, but 0 is valid */
 
 /* Hash table structure */
@@ -331,7 +331,7 @@ void SetupLibCheck(void)
 
     /* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */
     /* Set the parameters for the hash table */
-    g_pattern_hasher.init(
+    g_pattern_hasher.setHashParams(
                     numKeys,                /* The number of symbols */
                     PatLen,                 /* The length of the pattern to be hashed */
                     256,                    /* The character set of the pattern (0-FF) */

+ 38 - 38
src/dcc.cpp

@@ -65,7 +65,7 @@ bool TVisitor(raw_ostream &OS, RecordKeeper &Records)
     //        rec = Records.getDef("CCR");
     //        if(rec)
     //            rec->dump();
-    for(auto val : Records.getDefs())
+    for(const auto &val : Records.getDefs())
     {
         //std::cout<< "Def "<<val.first<<"\n";
     }
@@ -73,43 +73,43 @@ bool TVisitor(raw_ostream &OS, RecordKeeper &Records)
 }
 int testTblGen(int argc, char **argv)
 {
-    using namespace llvm;
-    sys::PrintStackTraceOnErrorSignal();
-    PrettyStackTraceProgram(argc,argv);
-    cl::ParseCommandLineOptions(argc,argv);
-    return llvm::TableGenMain(argv[0],TVisitor);
-    InitializeNativeTarget();
-    Triple TheTriple;
-    std::string  def = sys::getDefaultTargetTriple();
-    std::string MCPU="i386";
-    std::string MARCH="x86";
-    InitializeAllTargetInfos();
-    InitializeAllTargetMCs();
-    InitializeAllAsmPrinters();
-    InitializeAllAsmParsers();
-    InitializeAllDisassemblers();
-    std::string TargetTriple("i386-pc-linux-gnu");
-    TheTriple = Triple(Triple::normalize(TargetTriple));
-    MCOperand op=llvm::MCOperand::CreateImm(11);
-    MCAsmInfo info;
-    raw_os_ostream wrap(std::cerr);
-    op.print(wrap,&info);
-    wrap.flush();
-    std::cerr<<"\n";
-    std::string lookuperr;
-    TargetRegistry::printRegisteredTargetsForVersion();
-    const Target *t = TargetRegistry::lookupTarget(MARCH,TheTriple,lookuperr);
-    TargetOptions opts;
-    std::string Features;
-    opts.PrintMachineCode=1;
-    TargetMachine *tm = t->createTargetMachine(TheTriple.getTriple(),MCPU,Features,opts);
-    std::cerr<<tm->getInstrInfo()->getName(97)<<"\n";
-    const MCInstrDesc &ds(tm->getInstrInfo()->get(97));
-    const MCOperandInfo *op1=ds.OpInfo;
-    uint16_t impl_def = ds.getImplicitDefs()[0];
-    std::cerr<<lookuperr<<"\n";
-
-    exit(0);
+//    using namespace llvm;
+//    sys::PrintStackTraceOnErrorSignal();
+//    PrettyStackTraceProgram(argc,argv);
+//    cl::ParseCommandLineOptions(argc,argv);
+//    return llvm::TableGenMain(argv[0],TVisitor);
+//    InitializeNativeTarget();
+//    Triple TheTriple;
+//    std::string  def = sys::getDefaultTargetTriple();
+//    std::string MCPU="i386";
+//    std::string MARCH="x86";
+//    InitializeAllTargetInfos();
+//    InitializeAllTargetMCs();
+//    InitializeAllAsmPrinters();
+//    InitializeAllAsmParsers();
+//    InitializeAllDisassemblers();
+//    std::string TargetTriple("i386-pc-linux-gnu");
+//    TheTriple = Triple(Triple::normalize(TargetTriple));
+//    MCOperand op=llvm::MCOperand::CreateImm(11);
+//    MCAsmInfo info;
+//    raw_os_ostream wrap(std::cerr);
+//    op.print(wrap,&info);
+//    wrap.flush();
+//    std::cerr<<"\n";
+//    std::string lookuperr;
+//    TargetRegistry::printRegisteredTargetsForVersion();
+//    const Target *t = TargetRegistry::lookupTarget(MARCH,TheTriple,lookuperr);
+//    TargetOptions opts;
+//    std::string Features;
+//    opts.PrintMachineCode=1;
+//    TargetMachine *tm = t->createTargetMachine(TheTriple.getTriple(),MCPU,Features,opts);
+//    std::cerr<<tm->getInstrInfo()->getName(97)<<"\n";
+//    const MCInstrDesc &ds(tm->getInstrInfo()->get(97));
+//    const MCOperandInfo *op1=ds.OpInfo;
+//    uint16_t impl_def = ds.getImplicitDefs()[0];
+//    std::cerr<<lookuperr<<"\n";
+
+//    exit(0);
 
 }
 void setupOptions(QCoreApplication &app) {

+ 231 - 1
tools/makedsig/LIB_PatternCollector.cpp

@@ -1,7 +1,237 @@
 #include "LIB_PatternCollector.h"
+#include <cstring>
+#include <cstring>
+/** \note there is an untested assumption that the *first* segment definition
+    with class CODE will be the one containing all useful functions in the
+    LEDATA records. Functions such as _exit() have more than one segment
+    declared with class CODE (MSC8 libraries) */
 
-LIB_PatternCollector::LIB_PatternCollector()
+extern void fixWildCards(uint8_t pat[]);
+void readNN(int n, FILE *fl)
 {
+    if (fseek(fl, (long)n, SEEK_CUR) != 0)
+    {
+        printf("Could not seek file\n");
+        exit(2);
+    }
+}
+
+void LIB_PatternCollector::readString(FILE *fl)
+{
+    uint8_t len;
 
+    len = readByte(fl);
+    if (fread(buf, 1, len, fl) != len)
+    {
+        printf("Could not read string len %d\n", len);
+        exit(2);
+    }
+    buf[len] = '\0';
+    offset += len;
 }
 
+int LIB_PatternCollector::readSyms(FILE *fl)
+{
+    int i;
+    int count = 0;
+    int	firstSym = 0;			/* First symbol this module */
+    uint8_t b, c, type;
+    uint16_t w, len;
+
+    codeLNAMES = NONE;			/* Invalidate indexes for code segment */
+    codeSEGDEF = NONE;			/* Else won't be assigned */
+
+    offset = 0;                 /* For diagnostics, really */
+
+    if ((leData = (uint8_t *)malloc(0xFF80)) == 0)
+    {
+        printf("Could not malloc 64k bytes for LEDATA\n");
+        exit(10);
+    }
+
+    while (!feof(fl))
+    {
+        type = readByte(fl);
+        len = readWord(fl);
+        /* Note: uncommenting the following generates a *lot* of output */
+        /*printf("Offset %05lX: type %02X len %d\n", offset-3, type, len);//*/
+        switch (type)
+        {
+
+        case 0x96:				/* LNAMES */
+            while (len > 1)
+            {
+                readString(fl);
+                ++lnum;
+                if (strcmp((char *)buf, "CODE") == 0)
+                {
+                    /* This is the class name we're looking for */
+                    codeLNAMES= lnum;
+                }
+                len -= strlen((char *)buf)+1;
+            }
+            b = readByte(fl);		/* Checksum */
+            break;
+
+        case 0x98:				/* Segment definition */
+            b = readByte(fl);		/* Segment attributes */
+            if ((b & 0xE0) == 0)
+            {
+                /* Alignment field is zero. Frame and offset follow */
+                readWord(fl);
+                readByte(fl);
+            }
+
+            w = readWord(fl);		/* Segment length */
+
+            b = readByte(fl);		/* Segment name index */
+            ++segnum;
+
+            b = readByte(fl);		/* Class name index */
+            if ((b == codeLNAMES) && (codeSEGDEF == NONE))
+            {
+                /* This is the segment defining the code class */
+                codeSEGDEF = segnum;
+            }
+
+            b = readByte(fl);		/* Overlay index */
+            b = readByte(fl);		/* Checksum */
+            break;
+
+        case 0x90:				/* PUBDEF: public symbols */
+            b = readByte(fl);		/* Base group */
+            c = readByte(fl);		/* Base segment */
+            len -= 2;
+            if (c == 0)
+            {
+                w = readWord(fl);
+                len -= 2;
+            }
+            while (len > 1)
+            {
+                readString(fl);
+                w = readWord(fl);		/* Offset */
+                b = readByte(fl);		/* Type index */
+                if (c == codeSEGDEF)
+                {
+                    char *p;
+                    HASHENTRY entry;
+                    p = (char *)buf;
+                    if (buf[0] == '_')	/* Leading underscore? */
+                    {
+                        p++; 			/* Yes, remove it*/
+                    }
+                    i = std::min(size_t(SYMLEN-1), strlen(p));
+                    memcpy(entry.name, p, i);
+                    entry.name[i] = '\0';
+                    entry.offset = w;
+                    /*printf("%04X: %s is sym #%d\n", w, keys[count].name, count);//*/
+                    keys.push_back(entry);
+                    count++;
+                }
+                len -= strlen((char *)buf) + 1 + 2 + 1;
+            }
+            b = readByte(fl);		/* Checksum */
+            break;
+
+
+        case 0xA0:				/* LEDATA */
+        {
+            b = readByte(fl);		/* Segment index */
+            w = readWord(fl);		/* Offset */
+            len -= 3;
+            /*printf("LEDATA seg %d off %02X len %Xh, looking for %d\n", b, w, len-1, codeSEGDEF);//*/
+
+            if (b != codeSEGDEF)
+            {
+                readNN(len,fl);	/* Skip the data */
+                break;			/* Next record */
+            }
+
+
+            if (fread(&leData[w], 1, len-1, fl) != len-1)
+            {
+                printf("Could not read LEDATA length %d\n", len-1);
+                exit(2);
+            }
+            offset += len-1;
+            maxLeData = std::max<uint16_t>(maxLeData, w+len-1);
+
+            readByte(fl);				/* Checksum */
+            break;
+        }
+
+        default:
+            readNN(len,fl);			/* Just skip the lot */
+
+            if (type == 0x8A)	/* Mod end */
+            {
+                /* Now find all the patterns for public code symbols that
+                        we have found */
+                for (i=firstSym; i < count; i++)
+                {
+                    uint16_t off = keys[i].offset;
+                    if (off == (uint16_t)-1)
+                    {
+                        continue;			/* Ignore if already done */
+                    }
+                    if (keys[i].offset > maxLeData)
+                    {
+                        printf(
+                                    "Warning: no LEDATA for symbol #%d %s "
+                                    "(offset %04X, max %04X)\n",
+                                    i, keys[i].name, off, maxLeData);
+                        /* To make things consistant, we set the pattern for
+                                    this symbol to nulls */
+                        memset(&keys[i].pat, 0, PATLEN);
+                        continue;
+                    }
+                    /* Copy to temp buffer so don't overrun later patterns.
+                                (e.g. when chopping a short pattern).
+                                Beware of short patterns! */
+                    if (off+PATLEN <= maxLeData)
+                    {
+                        /* Available pattern is >= PATLEN */
+                        memcpy(buf, &leData[off], PATLEN);
+                    }
+                    else
+                    {
+                        /* Short! Only copy what is available (and malloced!) */
+                        memcpy(buf, &leData[off], maxLeData-off);
+                        /* Set rest to zeroes */
+                        memset(&buf[maxLeData-off], 0, PATLEN-(maxLeData-off));
+                    }
+                    fixWildCards((uint8_t *)buf);
+                    /* Save into the hash entry. */
+                    memcpy(keys[i].pat, buf, PATLEN);
+                    keys[i].offset = (uint16_t)-1;	// Flag it as done
+                    //printf("Saved pattern for %s\n", keys[i].name);
+                }
+
+
+                while (readByte(fl) == 0);
+                readNN(-1,fl);			/* Unget the last byte (= type) */
+                lnum = 0;			/* Reset index into lnames */
+                segnum = 0;			/* Reset index into snames */
+                firstSym = count;	/* Remember index of first sym this mod */
+                codeLNAMES = NONE;	/* Invalidate indexes for code segment */
+                codeSEGDEF = NONE;
+                memset(leData, 0, maxLeData);	/* Clear out old junk */
+                maxLeData = 0;		/* No data read this module */
+            }
+
+            else if (type == 0xF1)
+            {
+                /* Library end record */
+                return count;
+            }
+
+        }
+    }
+
+
+    free(leData);
+    keys.clear();
+
+    return count;
+}

+ 20 - 6
tools/makedsig/LIB_PatternCollector.h

@@ -1,11 +1,25 @@
-#ifndef LIB_PATTERNCOLLECTOR_H
-#define LIB_PATTERNCOLLECTOR_H
+#pragma once
 
+#include "PatternCollector.h"
 
-class LIB_PatternCollector
+struct LIB_PatternCollector : public PatternCollector
 {
+protected:
+    unsigned long offset;
+    uint8_t lnum = 0;				/* Count of LNAMES  so far */
+    uint8_t segnum = 0;			/* Count of SEGDEFs so far */
+    uint8_t codeLNAMES;			/* Index of the LNAMES for "CODE" class */
+    uint8_t codeSEGDEF;			/* Index of the first SEGDEF that has class CODE */
+    #define NONE 0xFF			/* Improbable segment index */
+    uint8_t *leData;            /* Pointer to 64K of alloc'd data. Some .lib files
+                                   have the symbols (PUBDEFs) *after* the data
+                                   (LEDATA), so you need to keep the data here */
+    uint16_t maxLeData;			/* How much data we have in there */
+    /* read a length then string to buf[]; make it an asciiz string */
+    void readString( FILE *fl);
+
 public:
-    LIB_PatternCollector();
-};
+    /* Read the .lib file, and put the keys into the array *keys[]. Returns the count */
+    int readSyms(FILE *fl);
 
-#endif // LIB_PATTERNCOLLECTOR_H
+};

+ 299 - 0
tools/makedsig/TPL_PatternCollector.cpp

@@ -1 +1,300 @@
+#include "TPL_PatternCollector.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) || (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) && ((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;
+}

+ 33 - 0
tools/makedsig/TPL_PatternCollector.h

@@ -1,5 +1,38 @@
 #ifndef TPL_PATTERNCOLLECTOR_H
 #define TPL_PATTERNCOLLECTOR_H
+#include "PatternCollector.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <vector>
+
+struct TPL_PatternCollector : public PatternCollector {
+protected:
+    uint16_t cmap, pmap, csegBase, unitBase;
+    uint16_t offStCseg, skipPmap;
+    int count = 0;
+    int	cAllocSym = 0;
+    int unitNum = 0;
+    char version, charProc, charFunc;
+    uint16_t csegoffs[100];
+    uint16_t csegIdx;
+    std::vector<long int> positionStack;
+
+    void enterSym(FILE *f,const char *name, uint16_t pmapOffset);
+    void allocSym(int count);
+    void readCmapOffsets(FILE *f);
+    void enterSystemUnit(FILE *f);
+    void readString(FILE *f);
+    void unknown(FILE *f,unsigned j, unsigned k);
+    void nextUnit(FILE *f);
+    void setVersionSpecifics(void);
+    void savePos(FILE *f);
+    void restorePos(FILE *f);
+    void enterUnitProcs(FILE *f);
+public:
+    /* Read the .tpl file, and put the keys into the array *keys[]. Returns the count */
+    int readSyms(FILE *f);
+};
 
 #endif // TPL_PATTERNCOLLECTOR_H