Update the dcc tools code

This commit is contained in:
Artur K 2015-04-28 14:59:00 +02:00
parent c5c9196561
commit 842687726f
9 changed files with 703 additions and 49 deletions

View File

@ -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

View File

@ -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

View File

@ -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
*/

View File

@ -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) */

View File

@ -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";
// 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);
// exit(0);
}
void setupOptions(QCoreApplication &app) {

View File

@ -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;
}

View File

@ -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
{
public:
LIB_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);
#endif // LIB_PATTERNCOLLECTOR_H
public:
/* Read the .lib file, and put the keys into the array *keys[]. Returns the count */
int readSyms(FILE *fl);
};

View File

@ -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;
}

View File

@ -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