Add original dcc tools to repository
* makedsig has been integrated with makedstp, it should handle both LIB and TPL files * other tools have not been modified
This commit is contained in:
parent
d8c66e7791
commit
a697ad05c0
@ -26,16 +26,23 @@ enable_testing()
|
||||
FIND_PACKAGE(GMock)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(3rd_party)
|
||||
|
||||
llvm_map_components_to_libraries(REQ_LLVM_LIBRARIES jit native mc support tablegen)
|
||||
llvm_map_components_to_libnames(REQ_LLVM_LIBRARIES jit native mc support tablegen)
|
||||
INCLUDE_DIRECTORIES(
|
||||
3rd_party/libdisasm
|
||||
include
|
||||
include/idioms
|
||||
common
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${LLVM_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
||||
ADD_SUBDIRECTORY(3rd_party)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
|
||||
set(dcc_LIB_SOURCES
|
||||
src/CallConvention.cpp
|
||||
src/ast.cpp
|
||||
@ -67,7 +74,6 @@ set(dcc_LIB_SOURCES
|
||||
src/locident.cpp
|
||||
src/liveness_set.cpp
|
||||
src/parser.cpp
|
||||
src/perfhlib.cpp
|
||||
src/procs.cpp
|
||||
src/project.cpp
|
||||
src/Procedure.cpp
|
||||
@ -106,7 +112,6 @@ set(dcc_HEADERS
|
||||
include/idioms/xor_idioms.h
|
||||
include/locident.h
|
||||
include/CallConvention.h
|
||||
include/perfhlib.h
|
||||
include/project.h
|
||||
include/scanner.h
|
||||
include/state.h
|
||||
@ -118,6 +123,7 @@ set(dcc_HEADERS
|
||||
include/dcc_interface.h
|
||||
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Source FILES ${dcc_SOURCES})
|
||||
SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
|
||||
|
||||
@ -127,11 +133,10 @@ qt5_use_modules(dcc_lib Core)
|
||||
|
||||
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_HEADERS})
|
||||
ADD_DEPENDENCIES(dcc_original dcc_lib)
|
||||
TARGET_LINK_LIBRARIES(dcc_original dcc_lib disasm_s ${REQ_LLVM_LIBRARIES} ncurses LLVMSupport)
|
||||
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} ncurses LLVMSupport)
|
||||
qt5_use_modules(dcc_original Core)
|
||||
#ADD_SUBDIRECTORY(gui)
|
||||
if(dcc_build_tests)
|
||||
ADD_SUBDIRECTORY(src)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
7
common/CMakeLists.txt
Normal file
7
common/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
set(SRC
|
||||
perfhlib.cpp
|
||||
perfhlib.h
|
||||
PatternCollector.h
|
||||
|
||||
)
|
||||
add_library(dcc_hash STATIC ${SRC})
|
||||
5
common/PatternCollector.h
Normal file
5
common/PatternCollector.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef PATTERNCOLLECTOR
|
||||
#define PATTERNCOLLECTOR
|
||||
|
||||
#endif // PATTERNCOLLECTOR
|
||||
|
||||
440
common/perfhlib.cpp
Normal file
440
common/perfhlib.cpp
Normal file
@ -0,0 +1,440 @@
|
||||
/*
|
||||
*$Log: perfhlib.c,v $
|
||||
* Revision 1.5 93/09/29 14:45:02 emmerik
|
||||
* Oops, didn't do the casts last check in
|
||||
*
|
||||
* Revision 1.4 93/09/29 14:41:45 emmerik
|
||||
* Added casts to mod instructions to keep the SVR4 compiler happy
|
||||
*
|
||||
*
|
||||
* Perfect hashing function library. Contains functions to generate perfect
|
||||
* hashing functions
|
||||
*/
|
||||
#include "perfhlib.h"
|
||||
#include "PatternCollector.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cassert>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
/* Private data structures */
|
||||
|
||||
//static int NumEntry; /* Number of entries in the hash table (# keys) */
|
||||
//static int EntryLen; /* Size (bytes) of each entry (size of keys) */
|
||||
//static int SetSize; /* Size of the char set */
|
||||
//static char SetMin; /* First char in the set */
|
||||
//static int NumVert; /* c times NumEntry */
|
||||
|
||||
//static uint16_t *T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
static uint16_t *T1, *T2; /* Pointers to T1[i], T2[i] */
|
||||
|
||||
static int *graphNode; /* The array of edges */
|
||||
static int *graphNext; /* Linked list of edges */
|
||||
static int *graphFirst;/* First edge at a vertex */
|
||||
|
||||
|
||||
static int numEdges; /* An edge counter */
|
||||
static bool *visited; /* Array of bools: whether visited */
|
||||
static bool *deleted; /* Array of bools: whether deleted */
|
||||
|
||||
/* Private prototypes */
|
||||
static void initGraph(void);
|
||||
static void addToGraph(int e, int v1, int v2);
|
||||
static bool isCycle(void);
|
||||
static void duplicateKeys(int v1, int v2);
|
||||
|
||||
void PerfectHash::setHashParams(int _NumEntry, int _EntryLen, int _SetSize, char _SetMin,
|
||||
int _NumVert)
|
||||
{
|
||||
/* These parameters are stored in statics so as to obviate the need for
|
||||
passing all these (or defererencing pointers) for every call to hash()
|
||||
*/
|
||||
|
||||
NumEntry = _NumEntry;
|
||||
EntryLen = _EntryLen;
|
||||
SetSize = _SetSize;
|
||||
SetMin = _SetMin;
|
||||
NumVert = _NumVert;
|
||||
|
||||
/* Allocate the variable sized tables etc */
|
||||
if ((T1base = (uint16_t *)malloc(EntryLen * SetSize * sizeof(uint16_t))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
if ((T2base = (uint16_t *)malloc(EntryLen * SetSize * sizeof(uint16_t))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
|
||||
if ((graphNode = (int *)malloc((NumEntry*2 + 1) * sizeof(int))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
if ((graphNext = (int *)malloc((NumEntry*2 + 1) * sizeof(int))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
if ((graphFirst = (int *)malloc((NumVert + 1) * sizeof(int))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
|
||||
if ((g = (short *)malloc((NumVert+1) * sizeof(short))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
if ((visited = (bool *)malloc((NumVert+1) * sizeof(bool))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
if ((deleted = (bool *)malloc((NumEntry+1) * sizeof(bool))) == 0)
|
||||
{
|
||||
goto BadAlloc;
|
||||
}
|
||||
return;
|
||||
|
||||
BadAlloc:
|
||||
printf("Could not allocate memory\n");
|
||||
hashCleanup();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void PerfectHash::hashCleanup(void)
|
||||
{
|
||||
/* Free the storage for variable sized tables etc */
|
||||
if (T1base) free(T1base);
|
||||
if (T2base) free(T2base);
|
||||
if (graphNode) free(graphNode);
|
||||
if (graphNext) free(graphNext);
|
||||
if (graphFirst) free(graphFirst);
|
||||
if (g) free(g);
|
||||
if (visited) free(visited);
|
||||
if (deleted) free(deleted);
|
||||
}
|
||||
|
||||
void PerfectHash::map(PatternCollector *collector)
|
||||
{
|
||||
m_collector = collector;
|
||||
assert(nullptr!=collector);
|
||||
int i, j, c;
|
||||
uint16_t f1, f2;
|
||||
bool cycle;
|
||||
uint8_t *keys;
|
||||
|
||||
c = 0;
|
||||
|
||||
do
|
||||
{
|
||||
initGraph();
|
||||
cycle = false;
|
||||
|
||||
/* Randomly generate T1 and T2 */
|
||||
for (i=0; i < SetSize*EntryLen; i++)
|
||||
{
|
||||
T1base[i] = rand() % NumVert;
|
||||
T2base[i] = rand() % NumVert;
|
||||
}
|
||||
|
||||
for (i=0; i < NumEntry; i++)
|
||||
{
|
||||
f1 = 0; f2 = 0;
|
||||
keys = m_collector->getKey(i);
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T1 = T1base + j * SetSize;
|
||||
T2 = T2base + j * SetSize;
|
||||
f1 += T1[keys[j] - SetMin];
|
||||
f2 += T2[keys[j] - SetMin];
|
||||
}
|
||||
f1 %= (uint16_t)NumVert;
|
||||
f2 %= (uint16_t)NumVert;
|
||||
if (f1 == f2)
|
||||
{
|
||||
/* A self loop. Reject! */
|
||||
printf("Self loop on vertex %d!\n", f1);
|
||||
cycle = true;
|
||||
break;
|
||||
}
|
||||
addToGraph(numEdges++, f1, f2);
|
||||
}
|
||||
if (cycle || (cycle = isCycle())) /* OK - is there a cycle? */
|
||||
{
|
||||
printf("Iteration %d\n", ++c);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (/* there is a cycle */ 1);
|
||||
|
||||
}
|
||||
|
||||
/* Initialise the graph */
|
||||
void PerfectHash::initGraph()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1; i <= NumVert; i++)
|
||||
{
|
||||
graphFirst[i] = 0;
|
||||
}
|
||||
|
||||
for (i= -NumEntry; i <= NumEntry; i++)
|
||||
{
|
||||
/* No need to init graphNode[] as they will all be filled by successive
|
||||
calls to addToGraph() */
|
||||
graphNext[NumEntry+i] = 0;
|
||||
}
|
||||
|
||||
numEdges = 0;
|
||||
}
|
||||
|
||||
/* Add an edge e between vertices v1 and v2 */
|
||||
/* e, v1, v2 are 0 based */
|
||||
void PerfectHash::addToGraph(int e, int v1, int v2)
|
||||
{
|
||||
e++; v1++; v2++; /* So much more convenient */
|
||||
|
||||
graphNode[NumEntry+e] = v2; /* Insert the edge information */
|
||||
graphNode[NumEntry-e] = v1;
|
||||
|
||||
graphNext[NumEntry+e] = graphFirst[v1]; /* Insert v1 to list of alphas */
|
||||
graphFirst[v1]= e;
|
||||
graphNext[NumEntry-e] = graphFirst[v2]; /* Insert v2 to list of omegas */
|
||||
graphFirst[v2]= -e;
|
||||
|
||||
}
|
||||
|
||||
bool PerfectHash::DFS(int parentE, int v)
|
||||
{
|
||||
int e, w;
|
||||
|
||||
/* Depth first search of the graph, starting at vertex v, looking for
|
||||
cycles. parent and v are origin 1. Note parent is an EDGE,
|
||||
not a vertex */
|
||||
|
||||
visited[v] = true;
|
||||
|
||||
/* For each e incident with v .. */
|
||||
for (e = graphFirst[v]; e; e = graphNext[NumEntry+e])
|
||||
{
|
||||
uint8_t *key1;
|
||||
|
||||
if (deleted[abs(e)])
|
||||
{
|
||||
/* A deleted key. Just ignore it */
|
||||
continue;
|
||||
}
|
||||
key1 = m_collector->getKey(abs(e)-1);
|
||||
w = graphNode[NumEntry+e];
|
||||
if (visited[w])
|
||||
{
|
||||
/* Did we just come through this edge? If so, ignore it. */
|
||||
if (abs(e) != abs(parentE))
|
||||
{
|
||||
/* There is a cycle in the graph. There is some subtle code here
|
||||
to work around the distinct possibility that there may be
|
||||
duplicate keys. Duplicate keys will always cause unit
|
||||
cycles, since f1 and f2 (used to select v and w) will be the
|
||||
same for both. The edges (representing an index into the
|
||||
array of keys) are distinct, but the key values are not.
|
||||
The logic is as follows: for the candidate edge e, check to
|
||||
see if it terminates in the parent vertex. If so, we test
|
||||
the keys associated with e and the parent, and if they are
|
||||
the same, we can safely ignore e for the purposes of cycle
|
||||
detection, since edge e adds nothing to the cycle. Cycles
|
||||
involving v, w, and e0 will still be found. The parent
|
||||
edge was not similarly eliminated because at the time when
|
||||
it was a candidate, v was not yet visited.
|
||||
We still have to remove the key from further consideration,
|
||||
since each edge is visited twice, but with a different
|
||||
parent edge each time.
|
||||
*/
|
||||
/* We save some stack space by calculating the parent vertex
|
||||
for these relatively few cases where it is needed */
|
||||
int parentV = graphNode[NumEntry-parentE];
|
||||
|
||||
if (w == parentV)
|
||||
{
|
||||
uint8_t *key2;
|
||||
|
||||
key2=m_collector->getKey(abs(parentE)-1);
|
||||
if (memcmp(key1, key2, EntryLen) == 0)
|
||||
{
|
||||
printf("Duplicate keys with edges %d and %d (",
|
||||
e, parentE);
|
||||
m_collector->dispKey(abs(e)-1);
|
||||
printf(" & ");
|
||||
m_collector->dispKey(abs(parentE)-1);
|
||||
printf(")\n");
|
||||
deleted[abs(e)] = true; /* Wipe the key */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A genuine (unit) cycle. */
|
||||
printf("There is a unit cycle involving vertex %d and edge %d\n", v, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have reached a previously visited vertex not the
|
||||
parent. Therefore, we have uncovered a genuine cycle */
|
||||
printf("There is a cycle involving vertex %d and edge %d\n", v, e);
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Not yet seen. Traverse it */
|
||||
{
|
||||
if (DFS(e, w))
|
||||
{
|
||||
/* Cycle found deeper down. Exit */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PerfectHash::isCycle(void)
|
||||
{
|
||||
int v, e;
|
||||
|
||||
for (v=1; v <= NumVert; v++)
|
||||
{
|
||||
visited[v] = false;
|
||||
}
|
||||
for (e=1; e <= NumEntry; e++)
|
||||
{
|
||||
deleted[e] = false;
|
||||
}
|
||||
for (v=1; v <= NumVert; v++)
|
||||
{
|
||||
if (!visited[v])
|
||||
{
|
||||
if (DFS(-32767, v))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PerfectHash::traverse(int u)
|
||||
{
|
||||
int w, e;
|
||||
|
||||
visited[u] = true;
|
||||
/* Find w, the neighbours of u, by searching the edges e associated with u */
|
||||
e = graphFirst[1+u];
|
||||
while (e)
|
||||
{
|
||||
w = graphNode[NumEntry+e]-1;
|
||||
if (!visited[w])
|
||||
{
|
||||
g[w] = (abs(e)-1 - g[u]) % NumEntry;
|
||||
if (g[w] < 0) g[w] += NumEntry; /* Keep these positive */
|
||||
traverse(w);
|
||||
}
|
||||
e = graphNext[NumEntry+e];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PerfectHash::assign(void)
|
||||
{
|
||||
int v;
|
||||
|
||||
|
||||
for (v=0; v < NumVert; v++)
|
||||
{
|
||||
g[v] = 0; /* g is sparse; leave the gaps 0 */
|
||||
visited[v] = false;
|
||||
}
|
||||
|
||||
for (v=0; v < NumVert; v++)
|
||||
{
|
||||
if (!visited[v])
|
||||
{
|
||||
g[v] = 0;
|
||||
traverse(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PerfectHash::hash(uint8_t *string)
|
||||
{
|
||||
uint16_t u, v;
|
||||
int j;
|
||||
|
||||
u = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T1 = T1base + j * SetSize;
|
||||
u += T1[string[j] - SetMin];
|
||||
}
|
||||
u %= NumVert;
|
||||
|
||||
v = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T2 = T2base + j * SetSize;
|
||||
v += T2[string[j] - SetMin];
|
||||
}
|
||||
v %= NumVert;
|
||||
|
||||
return (g[u] + g[v]) % NumEntry;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void dispRecord(int i);
|
||||
|
||||
void
|
||||
duplicateKeys(int v1, int v2)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t *keys;
|
||||
int u, v;
|
||||
|
||||
v1--; v2--; /* These guys are origin 1 */
|
||||
|
||||
printf("Duplicate keys:\n");
|
||||
|
||||
for (i=0; i < NumEntry; i++)
|
||||
{
|
||||
getKey(i, &keys);
|
||||
u = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T1 = T1base + j * SetSize;
|
||||
u += T1[keys[j] - SetMin];
|
||||
}
|
||||
u %= NumVert;
|
||||
if ((u != v1) && (u != v2)) continue;
|
||||
|
||||
v = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T2 = T2base + j * SetSize;
|
||||
v += T2[keys[j] - SetMin];
|
||||
}
|
||||
v %= NumVert;
|
||||
|
||||
if ((v == v2) || (v == v1))
|
||||
{
|
||||
printf("Entry #%d key: ", i+1);
|
||||
for (j=0; j < EntryLen; j++) printf("%02X ", keys[j]);
|
||||
printf("\n");
|
||||
dispRecord(i+1);
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
37
common/perfhlib.h
Normal file
37
common/perfhlib.h
Normal file
@ -0,0 +1,37 @@
|
||||
#include <stdint.h>
|
||||
/** Perfect hashing function library. Contains functions to generate perfect
|
||||
hashing functions */
|
||||
struct PatternCollector;
|
||||
struct PerfectHash {
|
||||
uint16_t *T1base;
|
||||
uint16_t *T2base; /* Pointers to start of T1, T2 */
|
||||
short *g; /* g[] */
|
||||
|
||||
int NumEntry; /* Number of entries in the hash table (# keys) */
|
||||
int EntryLen; /* Size (bytes) of each entry (size of keys) */
|
||||
int SetSize; /* Size of the char set */
|
||||
char SetMin; /* First char in the set */
|
||||
int NumVert; /* c times NumEntry */
|
||||
/** Set the parameters for the hash table */
|
||||
void setHashParams(int _numEntry, int _entryLen, int _setSize, char _setMin, int _numVert);
|
||||
|
||||
public:
|
||||
void map(PatternCollector * collector); /* Part 1 of creating the tables */
|
||||
void hashCleanup(); /* Frees memory allocated by setHashParams() */
|
||||
void assign(); /* Part 2 of creating the tables */
|
||||
int hash(uint8_t *string); /* Hash the string to an int 0 .. NUMENTRY-1 */
|
||||
const uint16_t *readT1(void) const { return T1base; }
|
||||
const uint16_t *readT2(void) const { return T2base; }
|
||||
const uint16_t *readG(void) const { return (uint16_t *)g; }
|
||||
uint16_t *readT1(void){ return T1base; }
|
||||
uint16_t *readT2(void){ return T2base; }
|
||||
uint16_t *readG(void) { return (uint16_t *)g; }
|
||||
private:
|
||||
void initGraph();
|
||||
void addToGraph(int e, int v1, int v2);
|
||||
bool isCycle();
|
||||
bool DFS(int parentE, int v);
|
||||
void traverse(int u);
|
||||
PatternCollector *m_collector; /* used to retrieve the keys */
|
||||
|
||||
};
|
||||
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
/* Perfect hashing function library. Contains functions to generate perfect
|
||||
hashing functions
|
||||
* (C) Mike van Emmerik
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
/* Prototypes */
|
||||
void hashCleanup(void); /* Frees memory allocated by hashParams() */
|
||||
void map(void); /* Part 1 of creating the tables */
|
||||
|
||||
/* The application must provide these functions: */
|
||||
void getKey(int i, uint8_t **pKeys);/* Set *keys to point to the i+1th key */
|
||||
void dispKey(int i); /* Display the key */
|
||||
class PatternHasher
|
||||
{
|
||||
uint16_t *T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
int NumEntry; /* Number of entries in the hash table (# keys) */
|
||||
int EntryLen; /* Size (bytes) of each entry (size of keys) */
|
||||
int SetSize; /* Size of the char set */
|
||||
char SetMin; /* First char in the set */
|
||||
int NumVert; /* c times NumEntry */
|
||||
int *graphNode; /* The array of edges */
|
||||
int *graphNext; /* Linked list of edges */
|
||||
int *graphFirst;/* First edge at a vertex */
|
||||
public:
|
||||
uint16_t *readT1(void); /* Returns a pointer to the T1 table */
|
||||
uint16_t *readT2(void); /* Returns a pointer to the T2 table */
|
||||
uint16_t *readG(void); /* Returns a pointer to the g table */
|
||||
void init(int _NumEntry, int _EntryLen, int _SetSize, char _SetMin,int _NumVert); /* Set the parameters for the hash table */
|
||||
void cleanup();
|
||||
int hash(unsigned char *string); //!< Hash the string to an int 0 .. NUMENTRY-1
|
||||
};
|
||||
extern PatternHasher g_pattern_hasher;
|
||||
/* Macro reads a LH uint16_t from the image regardless of host convention */
|
||||
#ifndef LH
|
||||
#define LH(p) ((int)((uint8_t *)(p))[0] + ((int)((uint8_t *)(p))[1] << 8))
|
||||
#endif
|
||||
@ -1,12 +1,14 @@
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
#include <cstdio>
|
||||
#include "dcc.h"
|
||||
#include "DccFrontend.h"
|
||||
#include "project.h"
|
||||
#include "disassem.h"
|
||||
#include "CallGraph.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
class Loader
|
||||
{
|
||||
@ -158,7 +160,7 @@ bool DccFrontend::FrontEnd ()
|
||||
|
||||
if (option.asm1)
|
||||
{
|
||||
std::cout << "dcc: writing assembler file "<<asm1_name.toStdString()<<'\n';
|
||||
qWarning() << "dcc: writing assembler file "<<asm1_name<<'\n';
|
||||
}
|
||||
|
||||
/* Search through code looking for impure references and flag them */
|
||||
|
||||
101
src/perfhlib.cpp
101
src/perfhlib.cpp
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Perfect hashing function library. Contains functions to generate perfect
|
||||
* hashing functions
|
||||
* (C) Mike van Emmerik
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "perfhlib.h"
|
||||
|
||||
/* Private data structures */
|
||||
|
||||
static uint16_t *T1, *T2; /* Pointers to T1[i], T2[i] */
|
||||
static short *g; /* g[] */
|
||||
|
||||
//static int numEdges; /* An edge counter */
|
||||
//static bool *visited; /* Array of bools: whether visited */
|
||||
|
||||
/* Private prototypes */
|
||||
//static void initGraph(void);
|
||||
//static void addToGraph(int e, int v1, int v2);
|
||||
//static bool isCycle(void);
|
||||
//static void duplicateKeys(int v1, int v2);
|
||||
PatternHasher g_pattern_hasher;
|
||||
|
||||
void PatternHasher::init(int _NumEntry, int _EntryLen, int _SetSize, char _SetMin, int _NumVert)
|
||||
{
|
||||
/* These parameters are stored in statics so as to obviate the need for
|
||||
passing all these (or defererencing pointers) for every call to hash()
|
||||
*/
|
||||
|
||||
NumEntry = _NumEntry;
|
||||
EntryLen = _EntryLen;
|
||||
SetSize = _SetSize;
|
||||
SetMin = _SetMin;
|
||||
NumVert = _NumVert;
|
||||
|
||||
/* Allocate the variable sized tables etc */
|
||||
T1base = new uint16_t [EntryLen * SetSize];
|
||||
T2base = new uint16_t [EntryLen * SetSize];
|
||||
graphNode = new int [NumEntry*2 + 1];
|
||||
graphNext = new int [NumEntry*2 + 1];
|
||||
graphFirst = new int [NumVert + 1];
|
||||
g = new short [NumVert + 1];
|
||||
// visited = new bool [NumVert + 1];
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void PatternHasher::cleanup(void)
|
||||
{
|
||||
/* Free the storage for variable sized tables etc */
|
||||
delete [] T1base;
|
||||
delete [] T2base;
|
||||
delete [] graphNode;
|
||||
delete [] graphNext;
|
||||
delete [] graphFirst;
|
||||
delete [] g;
|
||||
// delete [] visited;
|
||||
}
|
||||
|
||||
int PatternHasher::hash(uint8_t *string)
|
||||
{
|
||||
uint16_t u, v;
|
||||
int j;
|
||||
|
||||
u = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T1 = T1base + j * SetSize;
|
||||
u += T1[string[j] - SetMin];
|
||||
}
|
||||
u %= NumVert;
|
||||
|
||||
v = 0;
|
||||
for (j=0; j < EntryLen; j++)
|
||||
{
|
||||
T2 = T2base + j * SetSize;
|
||||
v += T2[string[j] - SetMin];
|
||||
}
|
||||
v %= NumVert;
|
||||
|
||||
return (g[u] + g[v]) % NumEntry;
|
||||
}
|
||||
|
||||
uint16_t * PatternHasher::readT1(void)
|
||||
{
|
||||
return T1base;
|
||||
}
|
||||
|
||||
uint16_t *PatternHasher::readT2(void)
|
||||
{
|
||||
return T2base;
|
||||
}
|
||||
|
||||
uint16_t * PatternHasher::readG(void)
|
||||
{
|
||||
return (uint16_t *)g;
|
||||
}
|
||||
|
||||
1
tools/CMakeLists.txt
Normal file
1
tools/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(makedsig)
|
||||
248
tools/dispsrch/dispsig.cpp
Normal file
248
tools/dispsrch/dispsig.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/* Quick program to copy a named signature to a small file */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "perfhlib.h"
|
||||
|
||||
/* statics */
|
||||
byte buf[100];
|
||||
int numKeys; /* Number of hash table entries (keys) */
|
||||
int numVert; /* Number of vertices in the graph (also size of g[]) */
|
||||
int PatLen; /* Size of the keys (pattern length) */
|
||||
int SymLen; /* Max size of the symbols, including null */
|
||||
FILE *f; /* File being read */
|
||||
FILE *f2; /* File being written */
|
||||
|
||||
static word *T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
static word *g; /* g[] */
|
||||
|
||||
/* prototypes */
|
||||
void grab(int n);
|
||||
word readFileShort(void);
|
||||
void cleanup(void);
|
||||
|
||||
|
||||
#define SYMLEN 16
|
||||
#define PATLEN 23
|
||||
|
||||
/* Hash table structure */
|
||||
typedef struct HT_tag
|
||||
{
|
||||
char htSym[SYMLEN];
|
||||
byte htPat[PATLEN];
|
||||
} HT;
|
||||
|
||||
HT ht; /* One hash table entry */
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
word w, len;
|
||||
int i;
|
||||
|
||||
if (argc <= 3)
|
||||
{
|
||||
printf("Usage: dispsig <SigFilename> <FunctionName> <BinFileName>\n");
|
||||
printf("Example: dispsig dccm8s.sig printf printf.bin\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((f = fopen(argv[1], "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot open %s\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if ((f2 = fopen(argv[3], "wb")) == NULL)
|
||||
{
|
||||
printf("Cannot write to %s\n", argv[3]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
/* Read the parameters */
|
||||
grab(4);
|
||||
if (memcmp("dccs", buf, 4) != 0)
|
||||
{
|
||||
printf("Not a dccs file!\n");
|
||||
exit(3);
|
||||
}
|
||||
numKeys = readFileShort();
|
||||
numVert = readFileShort();
|
||||
PatLen = readFileShort();
|
||||
SymLen = readFileShort();
|
||||
|
||||
/* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */
|
||||
hashParams( /* Set the parameters for the hash table */
|
||||
numKeys, /* The number of symbols */
|
||||
PatLen, /* The length of the pattern to be hashed */
|
||||
256, /* The character set of the pattern (0-FF) */
|
||||
0, /* Minimum pattern character value */
|
||||
numVert); /* Specifies C, the sparseness of the graph.
|
||||
See Czech, Havas and Majewski for details
|
||||
*/
|
||||
|
||||
T1base = readT1();
|
||||
T2base = readT2();
|
||||
g = readG();
|
||||
|
||||
/* Read T1 and T2 tables */
|
||||
grab(2);
|
||||
if (memcmp("T1", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T1'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = PatLen * 256 * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T1: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T1base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T1\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
grab(2);
|
||||
if (memcmp("T2", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T2'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T2: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T2base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
/* Now read the function g[] */
|
||||
grab(2);
|
||||
if (memcmp("gg", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'gg'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = numVert * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of g[]: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(g, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
|
||||
/* This is now the hash table */
|
||||
grab(2);
|
||||
if (memcmp("ht", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'ht'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != numKeys * (SymLen + PatLen + sizeof(word)))
|
||||
{
|
||||
printf("Problem with size of hash table: file %d, calc %d\n", w, len);
|
||||
exit(6);
|
||||
}
|
||||
|
||||
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
if (fread(&ht, 1, SymLen + PatLen, f) != (size_t)(SymLen + PatLen))
|
||||
{
|
||||
printf("Could not read pattern %d from %s\n", i, argv[1]);
|
||||
exit(7);
|
||||
}
|
||||
if (stricmp(ht.htSym, argv[2]) == 0)
|
||||
{
|
||||
/* Found it! */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
fclose(f);
|
||||
if (i == numKeys)
|
||||
{
|
||||
printf("Function %s not found!\n", argv[2]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
printf("Function %s index %d\n", ht.htSym, i);
|
||||
for (i=0; i < PatLen; i++)
|
||||
{
|
||||
printf("%02X ", ht.htPat[i]);
|
||||
}
|
||||
|
||||
fwrite(ht.htPat, 1, PatLen, f2);
|
||||
fclose(f2);
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
/* Free the storage for variable sized tables etc */
|
||||
if (T1base) free(T1base);
|
||||
if (T2base) free(T2base);
|
||||
if (g) free(g);
|
||||
}
|
||||
|
||||
void grab(int n)
|
||||
{
|
||||
if (fread(buf, 1, n, f) != (size_t)n)
|
||||
{
|
||||
printf("Could not read\n");
|
||||
exit(11);
|
||||
}
|
||||
}
|
||||
|
||||
word
|
||||
readFileShort(void)
|
||||
{
|
||||
byte 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;
|
||||
}
|
||||
|
||||
/* Following two functions not needed unless creating tables */
|
||||
|
||||
void getKey(int i, byte **keys)
|
||||
{
|
||||
}
|
||||
|
||||
/* Display key i */
|
||||
void
|
||||
dispKey(int i)
|
||||
{
|
||||
}
|
||||
|
||||
11
tools/dispsrch/dispsig.mak
Normal file
11
tools/dispsrch/dispsig.mak
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS = -Zi -c -AL -W3 -D__MSDOS__
|
||||
|
||||
dispsig.exe: dispsig.obj perfhlib.obj
|
||||
link /CO dispsig perfhlib;
|
||||
|
||||
dispsig.obj: dispsig.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
perfhlib.obj: perfhlib.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
221
tools/dispsrch/dispsrch.txt
Normal file
221
tools/dispsrch/dispsrch.txt
Normal file
@ -0,0 +1,221 @@
|
||||
DISPSIG and SRCHSIG
|
||||
===================
|
||||
|
||||
1 What are DispSig and SrchSig?
|
||||
|
||||
2 How do I use DispSig?
|
||||
|
||||
3 How do I use SrchSig?
|
||||
|
||||
4 What can I do with the binary pattern file from DispSig?
|
||||
|
||||
5 How can I create a binary pattern file for SrchSig?
|
||||
|
||||
|
||||
|
||||
1 What are DispSig and SrchSig?
|
||||
-------------------------------
|
||||
|
||||
SrchSig is a program to display the name of a function, given a
|
||||
signature (pattern).
|
||||
DispSig is a program to display a signature, given a function name.
|
||||
Dispsig also writes the signature to a binary file, so you can
|
||||
disassemble it, or use it in Srchsig to see if some other signature
|
||||
file has the same pattern.
|
||||
|
||||
|
||||
2 How do I use DispSig?
|
||||
-----------------------
|
||||
Just type
|
||||
DispSig <SignatureFileName> <FunctionName> <BinaryFileName>
|
||||
|
||||
For example:
|
||||
|
||||
dispsig dccb2s.sig strcmp strcmp.bin
|
||||
Function index 58
|
||||
55 8B EC 56 57 8C D8 8E C0 FC 33 C0 8B D8 8B 7E 06 8B F7 32 C0 B9 F4
|
||||
|
||||
This tells us that the function was the 59th function in the
|
||||
signature file (and that the signature above will hash to 58
|
||||
(decimal)). We can see that it is a standard C function, since it
|
||||
starts with "55 8B EC", which is the standard C function prologue.
|
||||
The rest of it is a bit hard to follow, but fortunately we have also
|
||||
written the pattern to a binary file, strcmp.bin. See section 4 on
|
||||
how to disassemble this pattern.
|
||||
|
||||
If I type
|
||||
|
||||
dispsig dcct4p.sig writeln wl.bin
|
||||
|
||||
I get
|
||||
Function writeln not found!
|
||||
|
||||
In fact, there is no one function that performs the writeln function;
|
||||
there are functions like WriteString, WriteInt, CrLf (Carriage
|
||||
return, linefeed), and so on. Dispsig is case insensitive, so:
|
||||
|
||||
dispsig dcct4p.sig writestring wl.bin
|
||||
produces
|
||||
|
||||
Function WriteString index 53
|
||||
55 8B EC C4 7E 0C E8 F4 F4 75 25 C5 76 08 8B 4E 06 FC AC F4 F4 2B C8
|
||||
|
||||
|
||||
3 How do I use SrchSig?
|
||||
-----------------------
|
||||
Just type
|
||||
|
||||
srchsig <SignatureFileName> <BinaryFileName>
|
||||
|
||||
dispsig dcct4p.sig writeln wl.bin
|
||||
where BinaryFileName contains a pattern. See section 5 for how to
|
||||
create one of these. For now, we can use the pattern file from the
|
||||
first example:
|
||||
|
||||
srchsig dccb2s.sig strcmp.bin
|
||||
|
||||
Pattern:
|
||||
55 8B EC 56 57 8C D8 8E C0 FC 33 C0 8B D8 8B 7E 06 8B F7 32 C0 B9 F4
|
||||
Pattern hashed to 58 (0x3A), symbol strcmp
|
||||
Pattern matched
|
||||
|
||||
Note that the pattern reported above need not be exactly the same as
|
||||
the one we provided in <BinaryFileName>. The pattern displayed is the
|
||||
wildcarded and chopped version of the pattern provided; it will have
|
||||
F4s (wildcards) and possibly zeroes at the end; see the file
|
||||
makedstp.txt for a simple explanation of wildcarding and chopping.
|
||||
|
||||
If we type
|
||||
|
||||
srchsig dccb2s.sig ws.bin
|
||||
|
||||
we get
|
||||
|
||||
Pattern:
|
||||
55 8B EC C4 7E 0C E8 F4 F4 75 25 C5 76 08 8B 4E 06 FC AC F4 F4 2B C8
|
||||
Pattern hashed to 0 (0x0), symbol _IOERROR
|
||||
Pattern mismatch: found following pattern
|
||||
55 8B EC 56 8B 76 04 0B F6 7C 14 83 FE 58 76 03 BE F4 F4 89 36 F4 F4
|
||||
300
|
||||
|
||||
The pattern often hashes to zero when the pattern is unknown, due to
|
||||
the sparse nature of the tables used in the hash function. The first
|
||||
pattern in dccb2s.sig happens to be _IOERROR, and its pattern is
|
||||
completely different, apart from the first three bytes. The "300" at
|
||||
the end is actually a running count of signatures searched linearly,
|
||||
in case there is a problem with the hash function.
|
||||
|
||||
|
||||
|
||||
4 What can I do with the binary pattern file from DispSig?
|
||||
----------------------------------------------------------
|
||||
|
||||
You can feed it into SrchSig; this might make sense if you wanted to
|
||||
know if, e.g. the signature for printf was the same for version 2 as
|
||||
it is for version 3. In this case, you would use DispSig on the
|
||||
version 2 signature file, and SrchSig on the version 3 file.
|
||||
|
||||
You can also disassemble it, using debug (it comes with MS-DOS). For
|
||||
example
|
||||
debug strcmp.bin
|
||||
-u100 l 17
|
||||
|
||||
1754:0100 55 PUSH BP
|
||||
1754:0101 8BEC MOV BP,SP
|
||||
1754:0103 56 PUSH SI
|
||||
1754:0104 57 PUSH DI
|
||||
1754:0105 8CD8 MOV AX,DS
|
||||
1754:0107 8EC0 MOV ES,AX
|
||||
1754:0109 FC CLD
|
||||
1754:010A 33C0 XOR AX,AX
|
||||
1754:010C 8BD8 MOV BX,AX
|
||||
1754:010E 8B7E06 MOV DI,[BP+06]
|
||||
1754:0111 8BF7 MOV SI,DI
|
||||
1754:0113 32C0 XOR AL,AL
|
||||
1754:0115 B9F42B MOV CX,2BF4
|
||||
-q
|
||||
|
||||
Note that the "2B" at the end is actually past the end of the
|
||||
signature. (Signatures are 23 bytes (17 in hex) long, so only
|
||||
addresses 100-116 are valid). Remember that most 16 bit operands will
|
||||
be "wildcarded", so don't believe the resultant addresses.
|
||||
|
||||
|
||||
5 How can I create a binary pattern file for SrchSig?
|
||||
-----------------------------------------------------
|
||||
|
||||
Again, you can use debug. Suppose you have found an interesing piece
|
||||
of code at address 05BE (this example comes from a hello world
|
||||
program):
|
||||
|
||||
-u 5be
|
||||
15FF:05BE 55 PUSH BP
|
||||
15FF:05BF 8BEC MOV BP,SP
|
||||
15FF:05C1 83EC08 SUB SP,+08
|
||||
15FF:05C4 57 PUSH DI
|
||||
15FF:05C5 56 PUSH SI
|
||||
15FF:05C6 BE1E01 MOV SI,011E
|
||||
15FF:05C9 8D4606 LEA AX,[BP+06]
|
||||
15FF:05CC 8946FC MOV [BP-04],AX
|
||||
15FF:05CF 56 PUSH SI
|
||||
15FF:05D0 E8E901 CALL 07BC
|
||||
15FF:05D3 83C402 ADD SP,+02
|
||||
15FF:05D6 8BF8 MOV DI,AX
|
||||
15FF:05D8 8D4606 LEA AX,[BP+06]
|
||||
15FF:05DB 50 PUSH AX
|
||||
15FF:05DC FF7604 PUSH [BP+04]
|
||||
-mcs:5be l 17 cs:100
|
||||
-u100 l 17
|
||||
15FF:0100 55 PUSH BP
|
||||
15FF:0101 8BEC MOV BP,SP
|
||||
15FF:0103 83EC08 SUB SP,+08
|
||||
15FF:0106 57 PUSH DI
|
||||
15FF:0107 56 PUSH SI
|
||||
15FF:0108 BE1E01 MOV SI,011E
|
||||
15FF:010B 8D4606 LEA AX,[BP+06]
|
||||
15FF:010E 8946FC MOV [BP-04],AX
|
||||
15FF:0111 56 PUSH SI
|
||||
15FF:0112 E8E901 CALL 02FE
|
||||
15FF:0115 83C41F ADD SP,+1F
|
||||
-nfoo.bin
|
||||
-rcx
|
||||
CS 268A
|
||||
:17
|
||||
-w
|
||||
Writing 0017 bytes
|
||||
-q
|
||||
c>dir foo.bin
|
||||
foo.bin 23 3-25-94 12:04
|
||||
c>
|
||||
|
||||
The binary file has to be exactly 23 bytes long; that's why we
|
||||
changed cx to the value 17 (hex 17 = decimal 23). If you are studying
|
||||
a large file (> 64K) remember to set bx to 0 as well. The m (block
|
||||
move) command moves the code of interest to cs:100, which is where
|
||||
debug will write the file from. The "rcx" changes the length of the
|
||||
save, and the "nfoo.bin" sets the name of the file to be saved. Now
|
||||
we can feed this into srchsig:
|
||||
|
||||
srchsig dccb2s.sig foo.bin
|
||||
Pattern:
|
||||
55 8B EC 83 EC 08 57 56 BE F4 F4 8D 46 06 89 46 FC 56 E8 F4 F4 83 C4
|
||||
Pattern hashed to 278 (0x116), symbol sleep
|
||||
Pattern mismatch: found following pattern
|
||||
55 8B EC 83 EC 04 56 57 8D 46 FC 50 E8 F4 F4 59 80 7E FE 5A 76 05 BF
|
||||
300
|
||||
|
||||
Hmmm. Not a Borland C version 2 small model signature. Perhaps its a
|
||||
Microsoft Version 5 signature:
|
||||
|
||||
Pattern:
|
||||
55 8B EC 83 EC 08 57 56 BE F4 F4 8D 46 06 89 46 FC 56 E8 F4 F4 83 C4
|
||||
Pattern hashed to 31 (0x1F), symbol printf
|
||||
Pattern matched
|
||||
|
||||
Yes, it was good old printf. Of course, no need for you to guess, DCC
|
||||
will figure out the vendor, version number, and model for you.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
287
tools/dispsrch/srchsig.cpp
Normal file
287
tools/dispsrch/srchsig.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
/* Quick program to see if a pattern is in a sig file. Pattern is supplied
|
||||
in a small .bin or .com style file */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "perfhlib.h"
|
||||
|
||||
/* statics */
|
||||
byte buf[100];
|
||||
int numKeys; /* Number of hash table entries (keys) */
|
||||
int numVert; /* Number of vertices in the graph (also size of g[]) */
|
||||
int PatLen; /* Size of the keys (pattern length) */
|
||||
int SymLen; /* Max size of the symbols, including null */
|
||||
FILE *f; /* Sig file being read */
|
||||
FILE *fpat; /* Pattern file being read */
|
||||
|
||||
static word *T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
static word *g; /* g[] */
|
||||
|
||||
#define SYMLEN 16
|
||||
#define PATLEN 23
|
||||
|
||||
typedef struct HT_tag
|
||||
{
|
||||
/* Hash table structure */
|
||||
char htSym[SYMLEN];
|
||||
byte htPat[PATLEN];
|
||||
} HT;
|
||||
|
||||
HT *ht; /* Declare a pointer to a hash table */
|
||||
|
||||
/* prototypes */
|
||||
void grab(int n);
|
||||
word readFileShort(void);
|
||||
void cleanup(void);
|
||||
void fixWildCards(char *buf); /* In fixwild.c */
|
||||
void pattSearch(void);
|
||||
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
word w, len;
|
||||
int h, i;
|
||||
int patlen;
|
||||
|
||||
if (argc <= 2)
|
||||
{
|
||||
printf("Usage: srchsig <SigFilename> <PattFilename>\n");
|
||||
printf("Searches the signature file for the given pattern\n");
|
||||
printf("e.g. %s dccm8s.sig mypatt.bin\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((f = fopen(argv[1], "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot open signature file %s\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if ((fpat = fopen(argv[2], "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot open pattern file %s\n", argv[2]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* Read the parameters */
|
||||
grab(4);
|
||||
if (memcmp("dccs", buf, 4) != 0)
|
||||
{
|
||||
printf("Not a dccs file!\n");
|
||||
exit(3);
|
||||
}
|
||||
numKeys = readFileShort();
|
||||
numVert = readFileShort();
|
||||
PatLen = readFileShort();
|
||||
SymLen = readFileShort();
|
||||
|
||||
/* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */
|
||||
hashParams( /* Set the parameters for the hash table */
|
||||
numKeys, /* The number of symbols */
|
||||
PatLen, /* The length of the pattern to be hashed */
|
||||
256, /* The character set of the pattern (0-FF) */
|
||||
0, /* Minimum pattern character value */
|
||||
numVert); /* Specifies C, the sparseness of the graph.
|
||||
See Czech, Havas and Majewski for details
|
||||
*/
|
||||
|
||||
T1base = readT1();
|
||||
T2base = readT2();
|
||||
g = readG();
|
||||
|
||||
/* Read T1 and T2 tables */
|
||||
grab(2);
|
||||
if (memcmp("T1", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T1'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = PatLen * 256 * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T1: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T1base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T1\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
grab(2);
|
||||
if (memcmp("T2", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T2'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T2: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T2base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
/* Now read the function g[] */
|
||||
grab(2);
|
||||
if (memcmp("gg", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'gg'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = numVert * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of g[]: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(g, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
|
||||
/* This is now the hash table */
|
||||
/* First allocate space for the table */
|
||||
if ((ht = (HT *)malloc(numKeys * sizeof(HT))) == 0)
|
||||
{
|
||||
printf("Could not allocate hash table\n");
|
||||
exit(1);
|
||||
}
|
||||
grab(2);
|
||||
if (memcmp("ht", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'ht'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != numKeys * (SymLen + PatLen + sizeof(word)))
|
||||
{
|
||||
printf("Problem with size of hash table: file %d, calc %d\n", w, len);
|
||||
exit(6);
|
||||
}
|
||||
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
if ((int)fread(&ht[i], 1, SymLen + PatLen, f) != SymLen + PatLen)
|
||||
{
|
||||
printf("Could not read\n");
|
||||
exit(11);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the pattern to buf */
|
||||
if ((patlen = fread(buf, 1, 100, fpat)) == 0)
|
||||
{
|
||||
printf("Could not read pattern\n");
|
||||
exit(11);
|
||||
}
|
||||
if (patlen != PATLEN)
|
||||
{
|
||||
printf("Error: pattern length is %d, should be %d\n", patlen, PATLEN);
|
||||
exit(12);
|
||||
}
|
||||
|
||||
/* Fix the wildcards */
|
||||
fixWildCards(buf);
|
||||
|
||||
printf("Pattern:\n");
|
||||
for (i=0; i < PATLEN; i++)
|
||||
printf("%02X ", buf[i]);
|
||||
printf("\n");
|
||||
|
||||
|
||||
h = hash(buf);
|
||||
printf("Pattern hashed to %d (0x%X), symbol %s\n", h, h, ht[h].htSym);
|
||||
if (memcmp(ht[h].htPat, buf, PATLEN) == 0)
|
||||
{
|
||||
printf("Pattern matched");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Pattern mismatch: found following pattern\n");
|
||||
for (i=0; i < PATLEN; i++)
|
||||
printf("%02X ", ht[h].htPat[i]);
|
||||
printf("\n");
|
||||
pattSearch(); /* Look for it the hard way */
|
||||
}
|
||||
cleanup();
|
||||
free(ht);
|
||||
fclose(f);
|
||||
fclose(fpat);
|
||||
|
||||
}
|
||||
|
||||
void pattSearch(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
if ((i % 100) == 0) printf("\r%d ", i);
|
||||
if (memcmp(ht[i].htPat, buf, PATLEN) == 0)
|
||||
{
|
||||
printf("\nPattern matched offset %d (0x%X)\n", i, i);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
/* Free the storage for variable sized tables etc */
|
||||
if (T1base) free(T1base);
|
||||
if (T2base) free(T2base);
|
||||
if (g) free(g);
|
||||
}
|
||||
|
||||
void grab(int n)
|
||||
{
|
||||
if (fread(buf, 1, n, f) != (size_t)n)
|
||||
{
|
||||
printf("Could not read\n");
|
||||
exit(11);
|
||||
}
|
||||
}
|
||||
|
||||
word
|
||||
readFileShort(void)
|
||||
{
|
||||
byte 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;
|
||||
}
|
||||
|
||||
/* Following two functions not needed unless creating tables */
|
||||
|
||||
void getKey(int i, byte **keys)
|
||||
{
|
||||
}
|
||||
|
||||
/* Display key i */
|
||||
void
|
||||
dispKey(int i)
|
||||
{
|
||||
}
|
||||
|
||||
14
tools/dispsrch/srchsig.mak
Normal file
14
tools/dispsrch/srchsig.mak
Normal file
@ -0,0 +1,14 @@
|
||||
CFLAGS = -Zi -c -AL -W3 -D__MSDOS__
|
||||
|
||||
srchsig.exe: srchsig.obj perfhlib.obj fixwild.obj
|
||||
link /CO srchsig perfhlib fixwild;
|
||||
|
||||
srchsig.obj: srchsig.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
perfhlib.obj: perfhlib.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
fixwild.obj: fixwild.c dcc.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
11
tools/makedsig/CMakeLists.txt
Normal file
11
tools/makedsig/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
set(SRC
|
||||
makedsig
|
||||
fixwild.cpp
|
||||
LIB_PatternCollector.cpp
|
||||
LIB_PatternCollector.h
|
||||
TPL_PatternCollector.cpp
|
||||
TPL_PatternCollector.h
|
||||
)
|
||||
add_executable(makedsig ${SRC})
|
||||
target_link_libraries(makedsig dcc_hash)
|
||||
qt5_use_modules(makedsig Core)
|
||||
7
tools/makedsig/LIB_PatternCollector.cpp
Normal file
7
tools/makedsig/LIB_PatternCollector.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "LIB_PatternCollector.h"
|
||||
|
||||
LIB_PatternCollector::LIB_PatternCollector()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
11
tools/makedsig/LIB_PatternCollector.h
Normal file
11
tools/makedsig/LIB_PatternCollector.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef LIB_PATTERNCOLLECTOR_H
|
||||
#define LIB_PATTERNCOLLECTOR_H
|
||||
|
||||
|
||||
class LIB_PatternCollector
|
||||
{
|
||||
public:
|
||||
LIB_PatternCollector();
|
||||
};
|
||||
|
||||
#endif // LIB_PATTERNCOLLECTOR_H
|
||||
1
tools/makedsig/TPL_PatternCollector.cpp
Normal file
1
tools/makedsig/TPL_PatternCollector.cpp
Normal file
@ -0,0 +1 @@
|
||||
|
||||
5
tools/makedsig/TPL_PatternCollector.h
Normal file
5
tools/makedsig/TPL_PatternCollector.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef TPL_PATTERNCOLLECTOR_H
|
||||
#define TPL_PATTERNCOLLECTOR_H
|
||||
|
||||
#endif // TPL_PATTERNCOLLECTOR_H
|
||||
|
||||
525
tools/makedsig/fixwild.cpp
Normal file
525
tools/makedsig/fixwild.cpp
Normal file
@ -0,0 +1,525 @@
|
||||
/*
|
||||
*$Log: fixwild.c,v $
|
||||
* Revision 1.10 93/10/28 11:10:10 emmerik
|
||||
* Addressing mode [reg+nnnn] is now wildcarded
|
||||
*
|
||||
* Revision 1.9 93/10/26 13:40:11 cifuente
|
||||
* op0F(byte pat[])
|
||||
*
|
||||
* Revision 1.8 93/10/26 13:01:29 emmerik
|
||||
* Completed the odd opcodes, like 0F XX and F7. Result: some library
|
||||
* functions that were not recognised before are recognised now.
|
||||
*
|
||||
* Revision 1.7 93/10/11 11:37:01 cifuente
|
||||
* First walk of HIGH_LEVEL icodes.
|
||||
*
|
||||
* Revision 1.6 93/10/01 14:36:21 emmerik
|
||||
* Added $ log, and made independant of dcc.h
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * *\
|
||||
* *
|
||||
* Fix Wild Cards Code *
|
||||
* *
|
||||
\* * * * * * * * * * * * */
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdint.h>
|
||||
#ifndef PATLEN
|
||||
#define PATLEN 23
|
||||
#define WILD 0xF4
|
||||
#endif
|
||||
|
||||
static int pc; /* Indexes into pat[] */
|
||||
|
||||
/* prototypes */
|
||||
static bool ModRM(uint8_t pat[]); /* Handle the mod/rm byte */
|
||||
static bool TwoWild(uint8_t pat[]); /* Make the next 2 bytes wild */
|
||||
static bool FourWild(uint8_t pat[]); /* Make the next 4 bytes wild */
|
||||
void fixWildCards(uint8_t pat[]); /* Main routine */
|
||||
|
||||
|
||||
/* Handle the mod/rm case. Returns true if pattern exhausted */
|
||||
static bool ModRM(uint8_t pat[])
|
||||
{
|
||||
uint8_t op;
|
||||
|
||||
/* A standard mod/rm byte follows opcode */
|
||||
op = pat[pc++]; /* The mod/rm byte */
|
||||
if (pc >= PATLEN) return true; /* Skip Mod/RM */
|
||||
switch (op & 0xC0)
|
||||
{
|
||||
case 0x00: /* [reg] or [nnnn] */
|
||||
if ((op & 0xC7) == 6)
|
||||
{
|
||||
/* Uses [nnnn] address mode */
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true;
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true;
|
||||
}
|
||||
break;
|
||||
case 0x40: /* [reg + nn] */
|
||||
if ((pc+=1) >= PATLEN) return true;
|
||||
break;
|
||||
case 0x80: /* [reg + nnnn] */
|
||||
/* Possibly just a long constant offset from a register,
|
||||
but often will be an index from a variable */
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true;
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true;
|
||||
break;
|
||||
case 0xC0: /* reg */
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Change the next two bytes to wild cards */
|
||||
static bool TwoWild(uint8_t pat[])
|
||||
{
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true; /* Pattern exhausted */
|
||||
pat[pc++] = WILD;
|
||||
if (pc >= PATLEN) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Change the next four bytes to wild cards */
|
||||
static bool FourWild(uint8_t pat[])
|
||||
{
|
||||
TwoWild(pat);
|
||||
return TwoWild(pat);
|
||||
}
|
||||
|
||||
/* Chop from the current point by wiping with zeroes. Can't rely on anything
|
||||
after this point */
|
||||
static void chop(uint8_t pat[])
|
||||
{
|
||||
if (pc >= PATLEN) return; /* Could go negative otherwise */
|
||||
memset(&pat[pc], 0, PATLEN - pc);
|
||||
}
|
||||
|
||||
static bool op0F(uint8_t pat[])
|
||||
{
|
||||
/* The two byte opcodes */
|
||||
uint8_t op = pat[pc++];
|
||||
switch (op & 0xF0)
|
||||
{
|
||||
case 0x00: /* 00 - 0F */
|
||||
if (op >= 0x06) /* Clts, Invd, Wbinvd */
|
||||
return false;
|
||||
else
|
||||
{
|
||||
/* Grp 6, Grp 7, LAR, LSL */
|
||||
return ModRM(pat);
|
||||
}
|
||||
case 0x20: /* Various funnies, all with Mod/RM */
|
||||
return ModRM(pat);
|
||||
|
||||
case 0x80:
|
||||
pc += 2; /* Word displacement cond jumps */
|
||||
return false;
|
||||
|
||||
case 0x90: /* Byte set on condition */
|
||||
return ModRM(pat);
|
||||
|
||||
case 0xA0:
|
||||
switch (op)
|
||||
{
|
||||
case 0xA0: /* Push FS */
|
||||
case 0xA1: /* Pop FS */
|
||||
case 0xA8: /* Push GS */
|
||||
case 0xA9: /* Pop GS */
|
||||
return false;
|
||||
|
||||
case 0xA3: /* Bt Ev,Gv */
|
||||
case 0xAB: /* Bts Ev,Gv */
|
||||
return ModRM(pat);
|
||||
|
||||
case 0xA4: /* Shld EvGbIb */
|
||||
case 0xAC: /* Shrd EvGbIb */
|
||||
if (ModRM(pat)) return true;
|
||||
pc++; /* The #num bits to shift */
|
||||
return false;
|
||||
|
||||
case 0xA5: /* Shld EvGb CL */
|
||||
case 0xAD: /* Shrd EvGb CL */
|
||||
return ModRM(pat);
|
||||
|
||||
default: /* CmpXchg, Imul */
|
||||
return ModRM(pat);
|
||||
}
|
||||
|
||||
case 0xB0:
|
||||
if (op == 0xBA)
|
||||
{
|
||||
/* Grp 8: bt/bts/btr/btc Ev,#nn */
|
||||
if (ModRM(pat)) return true;
|
||||
pc++; /* The #num bits to shift */
|
||||
return false;
|
||||
}
|
||||
return ModRM(pat);
|
||||
|
||||
case 0xC0:
|
||||
if (op <= 0xC1)
|
||||
{
|
||||
/* Xadd */
|
||||
return ModRM(pat);
|
||||
}
|
||||
/* Else BSWAP */
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false; /* Treat as double byte opcodes */
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Scan through the instructions in pat[], looking for opcodes that may
|
||||
have operands that vary with different instances. For example, load and
|
||||
store from statics, calls to other procs (even relative calls; they may
|
||||
call procs loaded in a different order, etc).
|
||||
Note that this procedure is architecture specific, and assumes the
|
||||
processor is in 16 bit address mode (real mode).
|
||||
PATLEN bytes are scanned.
|
||||
*/
|
||||
void fixWildCards(uint8_t pat[])
|
||||
{
|
||||
|
||||
uint8_t op, quad, intArg;
|
||||
|
||||
|
||||
pc=0;
|
||||
while (pc < PATLEN)
|
||||
{
|
||||
op = pat[pc++];
|
||||
if (pc >= PATLEN) return;
|
||||
|
||||
quad = op & 0xC0; /* Quadrant of the opcode map */
|
||||
if (quad == 0)
|
||||
{
|
||||
/* Arithmetic group 00-3F */
|
||||
|
||||
if ((op & 0xE7) == 0x26) /* First check for the odds */
|
||||
{
|
||||
/* Segment prefix: treat as 1 byte opcode */
|
||||
continue;
|
||||
}
|
||||
if (op == 0x0F) /* 386 2 byte opcodes */
|
||||
{
|
||||
if (op0F(pat)) return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op & 0x04)
|
||||
{
|
||||
/* All these are constant. Work out the instr length */
|
||||
if (op & 2)
|
||||
{
|
||||
/* Push, pop, other 1 byte opcodes */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (op & 1)
|
||||
{
|
||||
/* Word immediate operands */
|
||||
pc += 2;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Byte immediate operands */
|
||||
pc++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* All these have mod/rm bytes */
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (quad == 0x40)
|
||||
{
|
||||
if ((op & 0x60) == 0x40)
|
||||
{
|
||||
/* 0x40 - 0x5F -- these are inc, dec, push, pop of general
|
||||
registers */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 0x60 - 0x70 */
|
||||
if (op & 0x10)
|
||||
{
|
||||
/* 70-7F 2 byte jump opcodes */
|
||||
pc++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Odds and sods */
|
||||
switch (op)
|
||||
{
|
||||
case 0x60: /* pusha */
|
||||
case 0x61: /* popa */
|
||||
case 0x64: /* overrides */
|
||||
case 0x65:
|
||||
case 0x66:
|
||||
case 0x67:
|
||||
case 0x6C: /* insb DX */
|
||||
case 0x6E: /* outsb DX */
|
||||
continue;
|
||||
|
||||
case 0x62: /* bound */
|
||||
pc += 4;
|
||||
continue;
|
||||
|
||||
case 0x63: /* arpl */
|
||||
if (TwoWild(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0x68: /* Push byte */
|
||||
case 0x6A: /* Push byte */
|
||||
case 0x6D: /* insb port */
|
||||
case 0x6F: /* outsb port */
|
||||
/* 2 byte instr, no wilds */
|
||||
pc++;
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (quad == 0x80)
|
||||
{
|
||||
switch (op & 0xF0)
|
||||
{
|
||||
case 0x80: /* 80 - 8F */
|
||||
/* All have a mod/rm byte */
|
||||
if (ModRM(pat)) return;
|
||||
/* These also have immediate values */
|
||||
switch (op)
|
||||
{
|
||||
case 0x80:
|
||||
case 0x83:
|
||||
/* One byte immediate */
|
||||
pc++;
|
||||
continue;
|
||||
|
||||
case 0x81:
|
||||
/* Immediate 16 bit values might be constant, but
|
||||
also might be relocatable. Have to make them
|
||||
wild */
|
||||
if (TwoWild(pat)) return;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
case 0x90: /* 90 - 9F */
|
||||
if (op == 0x9A)
|
||||
{
|
||||
/* far call */
|
||||
if (FourWild(pat)) return;
|
||||
continue;
|
||||
}
|
||||
/* All others are 1 byte opcodes */
|
||||
continue;
|
||||
case 0xA0: /* A0 - AF */
|
||||
if ((op & 0x0C) == 0)
|
||||
{
|
||||
/* mov al/ax to/from [nnnn] */
|
||||
if (TwoWild(pat)) return;
|
||||
continue;
|
||||
}
|
||||
else if ((op & 0xFE) == 0xA8)
|
||||
{
|
||||
/* test al,#byte or test ax,#word */
|
||||
if (op & 1) pc += 2;
|
||||
else pc += 1;
|
||||
continue;
|
||||
|
||||
}
|
||||
case 0xB0: /* B0 - BF */
|
||||
{
|
||||
if (op & 8)
|
||||
{
|
||||
/* mov reg, #16 */
|
||||
/* Immediate 16 bit values might be constant, but also
|
||||
might be relocatable. For now, make them wild */
|
||||
if (TwoWild(pat)) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mov reg, #8 */
|
||||
pc++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In the last quadrant of the op code table */
|
||||
switch (op)
|
||||
{
|
||||
case 0xC0: /* 386: Rotate group 2 ModRM, byte, #byte */
|
||||
case 0xC1: /* 386: Rotate group 2 ModRM, word, #byte */
|
||||
if (ModRM(pat)) return;
|
||||
/* Byte immediate value follows ModRM */
|
||||
pc++;
|
||||
continue;
|
||||
|
||||
case 0xC3: /* Return */
|
||||
case 0xCB: /* Return far */
|
||||
chop(pat);
|
||||
return;
|
||||
case 0xC2: /* Ret nnnn */
|
||||
case 0xCA: /* Retf nnnn */
|
||||
pc += 2;
|
||||
chop(pat);
|
||||
return;
|
||||
|
||||
case 0xC4: /* les Gv, Mp */
|
||||
case 0xC5: /* lds Gv, Mp */
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0xC6: /* Mov ModRM, #nn */
|
||||
if (ModRM(pat)) return;
|
||||
/* Byte immediate value follows ModRM */
|
||||
pc++;
|
||||
continue;
|
||||
case 0xC7: /* Mov ModRM, #nnnn */
|
||||
if (ModRM(pat)) return;
|
||||
/* Word immediate value follows ModRM */
|
||||
/* Immediate 16 bit values might be constant, but also
|
||||
might be relocatable. For now, make them wild */
|
||||
if (TwoWild(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0xC8: /* Enter Iw, Ib */
|
||||
pc += 3; /* Constant word, byte */
|
||||
continue;
|
||||
case 0xC9: /* Leave */
|
||||
continue;
|
||||
|
||||
case 0xCC: /* Int 3 */
|
||||
continue;
|
||||
|
||||
case 0xCD: /* Int nn */
|
||||
intArg = pat[pc++];
|
||||
if ((intArg >= 0x34) && (intArg <= 0x3B))
|
||||
{
|
||||
/* Borland/Microsoft FP emulations */
|
||||
if (ModRM(pat)) return;
|
||||
}
|
||||
continue;
|
||||
|
||||
case 0xCE: /* Into */
|
||||
continue;
|
||||
|
||||
case 0xCF: /* Iret */
|
||||
continue;
|
||||
|
||||
case 0xD0: /* Group 2 rotate, byte, 1 bit */
|
||||
case 0xD1: /* Group 2 rotate, word, 1 bit */
|
||||
case 0xD2: /* Group 2 rotate, byte, CL bits */
|
||||
case 0xD3: /* Group 2 rotate, word, CL bits */
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0xD4: /* Aam */
|
||||
case 0xD5: /* Aad */
|
||||
case 0xD7: /* Xlat */
|
||||
continue;
|
||||
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB: /* Esc opcodes */
|
||||
case 0xDC: /* i.e. floating point */
|
||||
case 0xDD: /* coprocessor calls */
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0xE0: /* Loopne */
|
||||
case 0xE1: /* Loope */
|
||||
case 0xE2: /* Loop */
|
||||
case 0xE3: /* Jcxz */
|
||||
pc++; /* Short jump offset */
|
||||
continue;
|
||||
|
||||
case 0xE4: /* in al,nn */
|
||||
case 0xE6: /* out nn,al */
|
||||
pc++;
|
||||
continue;
|
||||
|
||||
case 0xE5: /* in ax,nn */
|
||||
case 0xE7: /* in nn,ax */
|
||||
pc += 2;
|
||||
continue;
|
||||
|
||||
case 0xE8: /* Call rel */
|
||||
if (TwoWild(pat)) return;
|
||||
continue;
|
||||
case 0xE9: /* Jump rel, unconditional */
|
||||
if (TwoWild(pat)) return;
|
||||
chop(pat);
|
||||
return;
|
||||
case 0xEA: /* Jump abs */
|
||||
if (FourWild(pat)) return;
|
||||
chop(pat);
|
||||
return;
|
||||
case 0xEB: /* Jmp short unconditional */
|
||||
pc++;
|
||||
chop(pat);
|
||||
return;
|
||||
|
||||
case 0xEC: /* In al,dx */
|
||||
case 0xED: /* In ax,dx */
|
||||
case 0xEE: /* Out dx,al */
|
||||
case 0xEF: /* Out dx,ax */
|
||||
continue;
|
||||
|
||||
case 0xF0: /* Lock */
|
||||
case 0xF2: /* Repne */
|
||||
case 0xF3: /* Rep/repe */
|
||||
case 0xF4: /* Halt */
|
||||
case 0xF5: /* Cmc */
|
||||
case 0xF8: /* Clc */
|
||||
case 0xF9: /* Stc */
|
||||
case 0xFA: /* Cli */
|
||||
case 0xFB: /* Sti */
|
||||
case 0xFC: /* Cld */
|
||||
case 0xFD: /* Std */
|
||||
continue;
|
||||
|
||||
case 0xF6: /* Group 3 byte test/not/mul/div */
|
||||
case 0xF7: /* Group 3 word test/not/mul/div */
|
||||
case 0xFE: /* Inc/Dec group 4 */
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
|
||||
case 0xFF: /* Group 5 Inc/Dec/Call/Jmp/Push */
|
||||
/* Most are like standard ModRM */
|
||||
if (ModRM(pat)) return;
|
||||
continue;
|
||||
|
||||
default: /* Rest are single byte opcodes */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
175
tools/makedsig/makedsig.cpp
Normal file
175
tools/makedsig/makedsig.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/* Program for making the DCC signature file */
|
||||
|
||||
#include "LIB_PatternCollector.h"
|
||||
#include "TPL_PatternCollector.h"
|
||||
#include "perfhlib.h" /* Symbol table prototypes */
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
/* Symbol table constnts */
|
||||
#define C 2.2 /* Sparseness of graph. See Czech, Havas and Majewski for details */
|
||||
|
||||
/* prototypes */
|
||||
|
||||
void saveFile(FILE *fl, const PerfectHash &p_hash, PatternCollector *coll); /* Save the info */
|
||||
|
||||
int numKeys; /* Number of useful codeview symbols */
|
||||
|
||||
|
||||
static void printUsage(bool longusage) {
|
||||
if(longusage)
|
||||
printf(
|
||||
"This program is to make 'signatures' of known c and tpl library calls for the dcc program.\n"
|
||||
"It needs as the first arg the name of a library file, and as the second arg, the name "
|
||||
"of the signature file to be generated.\n"
|
||||
"Example: makedsig CL.LIB dccb3l.sig\n"
|
||||
" or makedsig turbo.tpl dcct4p.sig\n"
|
||||
);
|
||||
else
|
||||
printf("Usage: makedsig <libname> <signame>\n"
|
||||
"or makedsig -h for help\n");
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc,argv);
|
||||
FILE *f2; // output file
|
||||
FILE *srcfile; // .lib file
|
||||
int s;
|
||||
if(app.arguments().size()<2) {
|
||||
printUsage(false);
|
||||
return 0;
|
||||
}
|
||||
QString arg2 = app.arguments()[1];
|
||||
if (arg2.startsWith("-h") || arg2.startsWith("-?"))
|
||||
{
|
||||
printUsage(true);
|
||||
return 0;
|
||||
}
|
||||
PatternCollector *collector;
|
||||
if(arg2.endsWith("tpl")) {
|
||||
collector = new TPL_PatternCollector;
|
||||
} else if(arg2.endsWith(".lib")) {
|
||||
collector = new LIB_PatternCollector;
|
||||
}
|
||||
if ((srcfile = fopen(argv[1], "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot read %s\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if ((f2 = fopen(argv[2], "wb")) == NULL)
|
||||
{
|
||||
printf("Cannot write %s\n", argv[2]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Seed: ");
|
||||
scanf("%d", &s);
|
||||
srand(s);
|
||||
|
||||
PerfectHash p_hash;
|
||||
numKeys = collector->readSyms(srcfile); /* Read the keys (symbols) */
|
||||
|
||||
printf("Num keys: %d; vertices: %d\n", numKeys, (int)(numKeys*C));
|
||||
/* Set the parameters for the hash table */
|
||||
p_hash.setHashParams( numKeys, /* The number of symbols */
|
||||
PATLEN, /* The length of the pattern to be hashed */
|
||||
256, /* The character set of the pattern (0-FF) */
|
||||
0, /* Minimum pattern character value */
|
||||
numKeys*C); /* C is the sparseness of the graph. See Czech,
|
||||
Havas and Majewski for details */
|
||||
|
||||
/* The following two functions are in perfhlib.c */
|
||||
p_hash.map(collector); /* Perform the mapping. This will call getKey() repeatedly */
|
||||
p_hash.assign(); /* Generate the function g */
|
||||
|
||||
saveFile(f2,p_hash,collector); /* Save the resultant information */
|
||||
|
||||
fclose(srcfile);
|
||||
fclose(f2);
|
||||
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * *\
|
||||
* *
|
||||
* S a v e t h e s i g f i l e *
|
||||
* *
|
||||
\* * * * * * * * * * * * */
|
||||
|
||||
|
||||
void writeFile(FILE *fl,const char *buffer, int len)
|
||||
{
|
||||
if ((int)fwrite(buffer, 1, len, fl) != len)
|
||||
{
|
||||
printf("Could not write to file\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void writeFileShort(FILE *fl,uint16_t w)
|
||||
{
|
||||
uint8_t b;
|
||||
|
||||
b = (uint8_t)(w & 0xFF);
|
||||
writeFile(fl,(char *)&b, 1); /* Write a short little endian */
|
||||
b = (uint8_t)(w>>8);
|
||||
writeFile(fl,(char *)&b, 1);
|
||||
}
|
||||
|
||||
void saveFile(FILE *fl, const PerfectHash &p_hash, PatternCollector *coll)
|
||||
{
|
||||
int i, len;
|
||||
const uint16_t *pTable;
|
||||
|
||||
writeFile(fl,"dccs", 4); /* Signature */
|
||||
writeFileShort(fl,numKeys); /* Number of keys */
|
||||
writeFileShort(fl,(short)(numKeys * C)); /* Number of vertices */
|
||||
writeFileShort(fl,PATLEN); /* Length of key part of entries */
|
||||
writeFileShort(fl,SYMLEN); /* Length of symbol part of entries */
|
||||
|
||||
/* Write out the tables T1 and T2, with their sig and byte lengths in front */
|
||||
writeFile(fl,"T1", 2); /* "Signature" */
|
||||
pTable = p_hash.readT1();
|
||||
len = PATLEN * 256;
|
||||
writeFileShort(fl,len * sizeof(uint16_t));
|
||||
for (i=0; i < len; i++)
|
||||
{
|
||||
writeFileShort(fl,pTable[i]);
|
||||
}
|
||||
writeFile(fl,"T2", 2);
|
||||
pTable = p_hash.readT2();
|
||||
writeFileShort(fl,len * sizeof(uint16_t));
|
||||
for (i=0; i < len; i++)
|
||||
{
|
||||
writeFileShort(fl,pTable[i]);
|
||||
}
|
||||
|
||||
/* Write out g[] */
|
||||
writeFile(fl,"gg", 2); /* "Signature" */
|
||||
pTable = p_hash.readG();
|
||||
len = (short)(numKeys * C);
|
||||
writeFileShort(fl,len * sizeof(uint16_t));
|
||||
for (i=0; i < len; i++)
|
||||
{
|
||||
writeFileShort(fl,pTable[i]);
|
||||
}
|
||||
|
||||
/* Now the hash table itself */
|
||||
writeFile(fl,"ht ", 2); /* "Signature" */
|
||||
writeFileShort(fl,numKeys * (SYMLEN + PATLEN + sizeof(uint16_t))); /* byte len */
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
writeFile(fl,(char *)&coll->keys[i], SYMLEN + PATLEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
188
tools/makedsig/makedsig.txt
Normal file
188
tools/makedsig/makedsig.txt
Normal file
@ -0,0 +1,188 @@
|
||||
MAKEDSIG
|
||||
|
||||
1 What is MakeDsig?
|
||||
|
||||
2 How does it work?
|
||||
|
||||
3 How do I use MakeDsig?
|
||||
|
||||
4 What's in a signature file?
|
||||
|
||||
5 What other tools are useful for signature work?
|
||||
|
||||
|
||||
1 What is MakeDsig?
|
||||
-------------------
|
||||
|
||||
MakeDsig is a program that reads a library (.lib) file from a
|
||||
compiler, and generates a signature file for use by DCC. Without
|
||||
signature files, dcc cannot recognise library functions, and so will
|
||||
attempt to decompile them, and cannot name them. This makes the
|
||||
resultant decompiled code bulkier and difficult to understand.
|
||||
|
||||
|
||||
2 How does it work?
|
||||
-------------------
|
||||
|
||||
Library files contain complete functions, relocation information,
|
||||
function names, and more. MakeDsig reads a library file, and for each
|
||||
function found, it saves the name, and creates a signature. These
|
||||
are stored in an array. When all functions are done, tables for the
|
||||
perfect hashing function are generated. During this process,
|
||||
duplicate keys (functions that produce identical signatures) may be
|
||||
detected; if so, one of the keys will be zeroed.
|
||||
|
||||
The signature file contains information needed by dcc to hash the
|
||||
signatures, as well as the symbols and signatures. Dcc reads the various
|
||||
sections of the signature file to be able to hash signatures. The
|
||||
signatures, not the symbols, are hashed, since dcc gets a signature
|
||||
from the executable file, and needs to know quickly if there is a
|
||||
symbolic name for it.
|
||||
|
||||
3 How do I use MakeDsig?
|
||||
------------------------
|
||||
|
||||
You can always find out by just executing it with no arguments, or
|
||||
MakeDsig -h for more details.
|
||||
|
||||
Basically, you just give it the names of the files that it needs:
|
||||
MakeDsig <libname> <signame>
|
||||
|
||||
It will ask you for a seed; enter any number, e.g. 1.
|
||||
|
||||
You need the library file for the appropriate compiler. For example,
|
||||
to analyse executable programs created from Turbo C 2.1 small model,
|
||||
you need the cs.lib file that comes with that compiler.
|
||||
|
||||
You also need to know the correct name for the signature file, i.e.
|
||||
<signame>. Dcc will detect certain compiler vendors and version
|
||||
numbers, and will look for a signature file named like this:
|
||||
d c c <vendor> <version> <model> . s i g
|
||||
|
||||
Here are the current vendors:
|
||||
Vendor Vendor letter
|
||||
Microsoft C/C++ m
|
||||
Borland C/C++ b
|
||||
Logitech (Modula) l
|
||||
Turbo Pascal t
|
||||
|
||||
Here are the model codes:
|
||||
small/tiny s
|
||||
medium m
|
||||
compact c
|
||||
large l
|
||||
Turbo Pascal p
|
||||
|
||||
The version codes are fairly self explanatory:
|
||||
Microsoft C 5.1 5
|
||||
Microsoft C 8 8
|
||||
Borland C 2.0 2
|
||||
Borland C 3.0 3
|
||||
Turbo Pascal 3.0 3 Note: currently no way to make dcct3p.sig
|
||||
Turbo Pascal 4.0 4 Use Makedstp, not makedsig
|
||||
Turbo Pascal 5.0 5 Use Makedstp, not makedsig
|
||||
|
||||
Some examples: the signature file for Borland C version 2.0, small
|
||||
model, would be dccb2s.sig. To generate it, you would supply as the
|
||||
library file cs.lib that came with that compiler. Suppose it was in
|
||||
the \bc\lib directory. To generate the signature file required to
|
||||
work with files produced by this compiler, you would type
|
||||
|
||||
makedsig \bc\lib\cs.lib dccb2s.sig
|
||||
|
||||
This will create dccb2s.sig in the current directory. For dcc to use
|
||||
this file, place it in the same directory as dcc itself, or point the
|
||||
environment variable DCC to the directory containing it.
|
||||
|
||||
Another example: to make the signature file for Microsoft Visual
|
||||
C/C++ (C 8.0), large model, and assuming the libraries are in
|
||||
the directory \msvc\lib, you would type
|
||||
|
||||
makedsig \msvc\lib\llibce.lib dccm8l.sig
|
||||
|
||||
Note that the signature files for Turbo Pascal from version 4 onwards
|
||||
are generated by makedstp, not makedsig. The latter program reads a
|
||||
special file called turbo.tpl, as there are no normal .lib files for
|
||||
turbo pascal. Dcc will recognise turbo pascal 3.0 files, and look
|
||||
for dcct3p.sig. Because all the library routines are contained in
|
||||
every Turbo Pascal executable, there are no library files or even a
|
||||
turbo.tpl file, so the signature file would have to be constructed by
|
||||
guesswork. You can still use dcc on these files; just ignore the
|
||||
warning about not finding the signature file.
|
||||
|
||||
For executables that dcc does not recognise, it will look for the
|
||||
signature file dccxxx.sig. That way, if you have a new compiler, you
|
||||
can at least have dcc detect library calls, even if it attempts to
|
||||
decompile them all, and has not identified the main program.
|
||||
|
||||
Logitech Modula V1.0 files are recognised, and the signature file
|
||||
dccl1x.sig is looked for. This was experimental in nature, and is not
|
||||
recommended for serious analysis at this stage.
|
||||
|
||||
|
||||
|
||||
4 What's in a signature file?
|
||||
-----------------------------
|
||||
|
||||
The details of a signature file are best documented in the source for
|
||||
makedsig; see the function saveFile(). Briefly:
|
||||
1) a 4 byte pattern identifying the file as a signature file: "dccs".
|
||||
2) a two byte integer containing the number of keys (signatures)
|
||||
3) a two byte integer containing the number of vertices on the graph
|
||||
used to generate the hash table. See the source code and/or the
|
||||
Czech, Havas and Majewski articles for details
|
||||
4) a two byte integer containing the pattern length
|
||||
5) a two byte integer containing the symbolic name length
|
||||
|
||||
The next sections all have the following structure:
|
||||
1) 2 char ID
|
||||
2) a two byte integer containing the size of the body
|
||||
3) the body.
|
||||
|
||||
There are 4 sections: "T1", "T2", "gg", and "ht". T1 and T2 are the
|
||||
tables associated with the hash function. (The hash function is a
|
||||
random function, meaning that it involves tables. T1 and T2 are the
|
||||
tables used by the hash function). "gg" is another table associated
|
||||
with the graph needed by the perfect hashing function algorithm.
|
||||
|
||||
"ht" contains the actual hash table. The body of this section is an
|
||||
array of records of this structure:
|
||||
typedef struct _hashEntry
|
||||
{
|
||||
char name[SYMLEN]; /* The symbol name */
|
||||
byte pat [PATLEN]; /* The pattern */
|
||||
word offset; /* Offset (needed temporarily) */
|
||||
} HASHENTRY;
|
||||
|
||||
This part of the signature file can be browsed with a binary dump
|
||||
program; a PATLEN length signature will follow the (null padded)
|
||||
symbol name. There are tools for searching signature files, e.g.
|
||||
srchsig, dispsig, and readsig. See below.
|
||||
|
||||
|
||||
|
||||
5 What other tools are useful for signature work?
|
||||
-------------------------------------------------
|
||||
|
||||
Makedstp - makes signature files from turbo.tpl. Needed to make
|
||||
signature files for Turbo Pascal version 4.0 and later.
|
||||
|
||||
SrchSig - tells you whether a given pattern exists in a signature
|
||||
file, and gives its name. You need a binary file with the signature
|
||||
in it, exactly the right length. This can most easily be done with
|
||||
debug (comes with MS-DOS).
|
||||
|
||||
DispSig - given the name of a function, displays its signature, and
|
||||
stores the signature into a binary file as well. (You can use this
|
||||
file with srchsig on another signature file, if you want).
|
||||
|
||||
ReadSig - reads a signature file, checking for correct structure, and
|
||||
displaying duplicate signatures. With the -a switch, it will display
|
||||
all signatures, with their symbols.
|
||||
|
||||
The file perfhlib.c is used by various of these tools to do the work
|
||||
of the perfect hashing functions. It could be used as part of other
|
||||
tools that use signature files, or just perfect hashing functions for
|
||||
that matter.
|
||||
|
||||
|
||||
0
tools/parsehdr/CMakeLists.txt
Normal file
0
tools/parsehdr/CMakeLists.txt
Normal file
117
tools/parsehdr/locident.h
Normal file
117
tools/parsehdr/locident.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*$Log: locident.h,v $
|
||||
* Revision 1.6 94/02/22 15:20:23 cifuente
|
||||
* Code generation is done.
|
||||
*
|
||||
* Revision 1.5 93/12/10 09:38:20 cifuente
|
||||
* New high-level types
|
||||
*
|
||||
* Revision 1.4 93/11/10 17:30:51 cifuente
|
||||
* Procedure header, locals
|
||||
*
|
||||
* Revision 1.3 93/11/08 12:06:35 cifuente
|
||||
* du1 analysis finished. Instantiates procedure arguments for user
|
||||
* declared procedures.
|
||||
*
|
||||
* Revision 1.2 93/10/25 11:01:00 cifuente
|
||||
* New SYNTHETIC instructions for d/u analysis
|
||||
*
|
||||
* Revision 1.1 93/10/11 11:47:39 cifuente
|
||||
* Initial revision
|
||||
*
|
||||
* File: locIdent.h
|
||||
* Purpose: High-level local identifier definitions
|
||||
* Date: October 1993
|
||||
*/
|
||||
|
||||
|
||||
/* Type definition */
|
||||
typedef struct {
|
||||
Int csym; /* # symbols used */
|
||||
Int alloc; /* # symbols allocated */
|
||||
Int *idx; /* Array of integer indexes */
|
||||
} IDX_ARRAY;
|
||||
|
||||
/* Type definitions used in the decompiled program */
|
||||
typedef enum {
|
||||
TYPE_UNKNOWN = 0, /* unknown so far */
|
||||
TYPE_BYTE_SIGN, /* signed byte (8 bits) */
|
||||
TYPE_BYTE_UNSIGN, /* unsigned byte */
|
||||
TYPE_WORD_SIGN, /* signed word (16 bits) */
|
||||
TYPE_WORD_UNSIGN, /* unsigned word (16 bits) */
|
||||
TYPE_LONG_SIGN, /* signed long (32 bits) */
|
||||
TYPE_LONG_UNSIGN, /* unsigned long (32 bits) */
|
||||
TYPE_RECORD, /* record structure */
|
||||
TYPE_PTR, /* pointer (32 bit ptr) */
|
||||
TYPE_STR, /* string */
|
||||
TYPE_CONST, /* constant (any type) */
|
||||
TYPE_FLOAT, /* floating point */
|
||||
TYPE_DOUBLE, /* double precision float */
|
||||
} hlType;
|
||||
|
||||
static char *hlTypes[13] = {"", "char", "unsigned char", "int", "unsigned int",
|
||||
"long", "unsigned long", "record", "int *", "char *",
|
||||
"", "float", "double"};
|
||||
|
||||
typedef enum {
|
||||
STK_FRAME, /* For stack vars */
|
||||
REG_FRAME, /* For register variables */
|
||||
GLB_FRAME, /* For globals */
|
||||
} frameType;
|
||||
|
||||
|
||||
/* Enumeration to determine whether pIcode points to the high or low part
|
||||
* of a long number */
|
||||
typedef enum {
|
||||
HIGH_FIRST, /* High value is first */
|
||||
LOW_FIRST, /* Low value is first */
|
||||
} hlFirst;
|
||||
|
||||
|
||||
/* LOCAL_ID */
|
||||
typedef struct {
|
||||
hlType type; /* Probable type */
|
||||
boolT illegal;/* Boolean: not a valid field any more */
|
||||
IDX_ARRAY idx; /* Index into icode array (REG_FRAME only) */
|
||||
frameType loc; /* Frame location */
|
||||
boolT hasMacro;/* Identifier requires a macro */
|
||||
char macro[10];/* Macro for this identifier */
|
||||
char name[20];/* Identifier's name */
|
||||
union { /* Different types of identifiers */
|
||||
byte regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
|
||||
struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */
|
||||
byte regOff; /* register offset (if any) */
|
||||
Int off; /* offset from BP */
|
||||
} bwId;
|
||||
struct _bwGlb { /* For TYPE_BYTE(WORD)_(UN)SIGN globals */
|
||||
int16 seg; /* segment value */
|
||||
int16 off; /* offset */
|
||||
byte regi; /* optional indexed register */
|
||||
} bwGlb;
|
||||
struct _longId{ /* For TYPE_LONG_(UN)SIGN registers */
|
||||
byte h; /* high register */
|
||||
byte l; /* low register */
|
||||
} longId;
|
||||
struct _longStkId { /* For TYPE_LONG_(UN)SIGN on the stack */
|
||||
Int offH; /* high offset from BP */
|
||||
Int offL; /* low offset from BP */
|
||||
} longStkId;
|
||||
struct { /* For TYPE_LONG_(UN)SIGN globals */
|
||||
int16 seg; /* segment value */
|
||||
int16 offH; /* offset high */
|
||||
int16 offL; /* offset low */
|
||||
byte regi; /* optional indexed register */
|
||||
} longGlb;
|
||||
struct { /* For TYPE_LONG_(UN)SIGN constants */
|
||||
dword h; /* high word */
|
||||
dword l; /* low word */
|
||||
} longKte;
|
||||
} id;
|
||||
} ID;
|
||||
|
||||
typedef struct {
|
||||
Int csym; /* No. of symbols in the table */
|
||||
Int alloc; /* No. of symbols allocated */
|
||||
ID *id; /* Identifier */
|
||||
} LOCAL_ID;
|
||||
|
||||
|
||||
1538
tools/parsehdr/parsehdr.cpp
Normal file
1538
tools/parsehdr/parsehdr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
98
tools/parsehdr/parsehdr.h
Normal file
98
tools/parsehdr/parsehdr.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
*$Log: parsehdr.h,v $
|
||||
*/
|
||||
/* Header file for parsehdr.c */
|
||||
|
||||
typedef unsigned long dword; /* 32 bits */
|
||||
typedef unsigned char byte; /* 8 bits */
|
||||
typedef unsigned short word; /* 16 bits */
|
||||
typedef unsigned char boolT; /* 8 bits */
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define BUFF_SIZE 8192 /* Holds a declaration */
|
||||
#define FBUF_SIZE 32700 /* Holds part of a header file */
|
||||
|
||||
#define NARGS 15
|
||||
#define NAMES_L 160
|
||||
#define TYPES_L 160
|
||||
#define FUNC_L 160
|
||||
|
||||
#define ERRF stdout
|
||||
|
||||
void phError(char *errmsg);
|
||||
void phWarning(char *errmsg);
|
||||
|
||||
#define ERR(msg) phError(msg)
|
||||
#ifdef DEBUG
|
||||
#define DBG(str) printf(str);
|
||||
#else
|
||||
#define DBG(str) ;
|
||||
#endif
|
||||
#define WARN(msg) phWarning(msg)
|
||||
#define OUT(str) fprintf(outfile, str)
|
||||
|
||||
#define PH_PARAMS 32
|
||||
#define PH_NAMESZ 15
|
||||
|
||||
#define SYMLEN 16 /* Including the null */
|
||||
#define Int long /* For locident.h */
|
||||
#define int16 short int /* For locident.h */
|
||||
#include "locident.h" /* For the hlType enum */
|
||||
#define bool unsigned char /* For internal use */
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
typedef
|
||||
struct ph_func_tag
|
||||
{
|
||||
char name[SYMLEN]; /* Name of function or arg */
|
||||
hlType typ; /* Return type */
|
||||
int numArg; /* Number of args */
|
||||
int firstArg; /* Index of first arg in chain */
|
||||
int next; /* Index of next function in chain */
|
||||
bool bVararg; /* True if variable num args */
|
||||
} PH_FUNC_STRUCT;
|
||||
|
||||
typedef
|
||||
struct ph_arg_tag
|
||||
{
|
||||
char name[SYMLEN]; /* Name of function or arg */
|
||||
hlType typ; /* Parameter type */
|
||||
} PH_ARG_STRUCT;
|
||||
|
||||
#define DELTA_FUNC 32 /* Number to alloc at once */
|
||||
|
||||
|
||||
#define PH_JUNK 0 /* LPSTR buffer, nothing happened */
|
||||
#define PH_PROTO 1 /* LPPH_FUNC ret val, func name, args */
|
||||
#define PH_FUNCTION 2 /* LPPH_FUNC ret val, func name, args */
|
||||
#define PH_TYPEDEF 3 /* LPPH_DEF definer and definee */
|
||||
#define PH_DEFINE 4 /* LPPH_DEF definer and definee */
|
||||
#define PH_ERROR 5 /* LPSTR error string */
|
||||
#define PH_WARNING 6 /* LPSTR warning string */
|
||||
#define PH_MPROTO 7 /* ????? multi proto???? */
|
||||
#define PH_VAR 8 /* ????? var decl */
|
||||
|
||||
/* PROTOS */
|
||||
|
||||
boolT phData(char *buff, int ndata);
|
||||
boolT phPost(void);
|
||||
boolT phFree(void);
|
||||
void checkHeap(char *msg); /* For debugging only */
|
||||
|
||||
void phBuffToFunc(char *buff);
|
||||
|
||||
void phBuffToDef(char *buff);
|
||||
|
||||
|
||||
#define TOK_TYPE 256 /* A type name (e.g. "int") */
|
||||
#define TOK_NAME 257 /* A function or parameter name */
|
||||
#define TOK_DOTS 258 /* "..." */
|
||||
#define TOK_EOL 259 /* End of line */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BT_INT, BT_CHAR, BT_FLOAT, BT_DOUBLE, BT_STRUCT, BT_VOID, BT_UNKWN
|
||||
} baseType;
|
||||
217
tools/parsehdr/parsehdr.txt
Normal file
217
tools/parsehdr/parsehdr.txt
Normal file
@ -0,0 +1,217 @@
|
||||
PARSEHDR
|
||||
|
||||
1 What is ParseHdr?
|
||||
|
||||
2 What is dcclibs.dat?
|
||||
|
||||
3 How do I use ParseHdr?
|
||||
|
||||
4 What about languages other than C?
|
||||
|
||||
5 What is the structure of the dcclibs.dat file?
|
||||
|
||||
6 What are all these errors, and why do they happen?
|
||||
|
||||
|
||||
1 What is ParseHdr?
|
||||
-------------------
|
||||
|
||||
ParseHdr is a program that creates a special prototype file for DCC
|
||||
from a set of include files (.h files). This allows DCC to be aware
|
||||
of the type of library function arguments, and return types. The file
|
||||
produced is called dcclibs.dat. ParseHdr is designed specifically for
|
||||
C header files.
|
||||
|
||||
As an example, this is what allows DCC to recognise that printf has
|
||||
(at least) a string argument, and so converts the first argument from
|
||||
a numeric constant to a string. So you get
|
||||
printf("Hello world")
|
||||
instead of
|
||||
printf(0x42).
|
||||
|
||||
|
||||
2 What is dcclibs.dat?
|
||||
----------------------
|
||||
|
||||
dcclibs.dat is the file created by the ParseHdr program. It contains
|
||||
a list of function names and parameter and return types. See section
|
||||
5 for details of the contents of the file.
|
||||
|
||||
|
||||
3 How do I use ParseHdr?
|
||||
------------------------
|
||||
|
||||
To use ParseHdr you need a file containing a list of header files,
|
||||
like this:
|
||||
\tc\include\alloc.h
|
||||
\tc\include\assert.h
|
||||
\tc\include\bios.h
|
||||
...
|
||||
\tc\include\time.h
|
||||
|
||||
There must be one file per line, no blank lines, and unless the
|
||||
header files are in the current directory, a full path must be given.
|
||||
The easiest way to create such a file is to redirect the output of a
|
||||
dir command to a file, like this:
|
||||
c>dir \tc\include\*.h > tcfiles.lst
|
||||
and then edit the resultant file. Note that the path will not be
|
||||
included in this, so you will have to add that manually. Remove
|
||||
everything after the .h, such as file size, date, etc.
|
||||
|
||||
Once you have this file, you can run parsehdr:
|
||||
|
||||
parsehdr <listfile>
|
||||
|
||||
For example,
|
||||
|
||||
parsehdr tcfiles.lst
|
||||
|
||||
You will get some messages indicating which files are being
|
||||
processed, but also some error messages. Just ignore the error
|
||||
messages, see section 6 for why they occur.
|
||||
|
||||
|
||||
|
||||
4 What about languages other than C?
|
||||
-----------------------------------------
|
||||
|
||||
ParseHdr will only work on C header files. It would be possible to
|
||||
process files for other languages that contained type information, to
|
||||
produce a dcclibs.dat file specific to that language. Ideally, DCC
|
||||
should look for a different file for each language, but since only a
|
||||
C version of dcclibs.dat has so far been created, this has not been
|
||||
done.
|
||||
|
||||
Prototype information for Turbo Pascal exists in the file turbo.tpl,
|
||||
at least for things like the graphics library, so it would be
|
||||
possible for MakeDsTp to produce a dcclibs.dat file as well as the
|
||||
signature file. However, the format of the turbo.tpl file is not
|
||||
documented by Borland; for details see
|
||||
|
||||
W. L. Peavy, "Inside Turbo Pascal 6.0 Units", Public domain software
|
||||
file tpu6doc.txt in tpu6.zip. Anonymous ftp from garbo.uwasa.fi and
|
||||
mirrors, directory /pc/turbopas, 1991.
|
||||
|
||||
|
||||
|
||||
|
||||
5 What is the structure of the dcclibs.dat file?
|
||||
------------------------------------------------
|
||||
|
||||
The first 4 bytes are "dccp", identifying it as a DCC prototype file.
|
||||
After this, there are two sections.
|
||||
|
||||
The first section begins with "FN", for Function Names. It is
|
||||
followed by a two byte integer giving the number of function names
|
||||
stored. The remainder of this section is an array of structures, one
|
||||
per function name. Each has this structure:
|
||||
char Name[SYMLEN]; /* Name of the function, NULL terminated */
|
||||
int type; /* A 2 byte integer describing the return type */
|
||||
int numArg; /* The number of arguments */
|
||||
int firstArg; /* The index of the first arg, see below */
|
||||
char bVarArg; /* 1 if variable arguments, 0 otherwise */
|
||||
|
||||
SYMLEN is 16, alowing 15 chars before the NULL. Therefore, the length
|
||||
of this structure is 23 bytes.
|
||||
|
||||
The types are as defined in locident.h (actually a part of dcc), and
|
||||
at present are as follows:
|
||||
typedef enum {
|
||||
TYPE_UNKNOWN = 0, /* unknown so far 00 */
|
||||
TYPE_BYTE_SIGN, /* signed byte (8 bits) 01 */
|
||||
TYPE_BYTE_UNSIGN, /* unsigned byte 02 */
|
||||
TYPE_WORD_SIGN, /* signed word (16 bits) 03 */
|
||||
TYPE_WORD_UNSIGN, /* unsigned word (16 bits) 04 */
|
||||
TYPE_LONG_SIGN, /* signed long (32 bits) 05 */
|
||||
TYPE_LONG_UNSIGN, /* unsigned long (32 bits) 06 */
|
||||
TYPE_RECORD, /* record structure 07 */
|
||||
TYPE_PTR, /* pointer (32 bit ptr) 08 */
|
||||
TYPE_STR, /* string 09 */
|
||||
TYPE_CONST, /* constant (any type) 0A */
|
||||
TYPE_FLOAT, /* floating point 0B */
|
||||
TYPE_DOUBLE, /* double precision float 0C */
|
||||
} hlType;
|
||||
|
||||
firstArg is an index into the array in the second section.
|
||||
|
||||
The second section begins with "PM" (for Parameters). It is followed
|
||||
by a 2 byte integer giving the number of parameter records. After
|
||||
this is the array of parameter structures. Initially, the names of the
|
||||
parameters were being stored, but this has been removed at present.
|
||||
The parameter structure is therefore now just a single 2 byte
|
||||
integer, representing the type of that argument.
|
||||
|
||||
The way it all fits together is perhaps best described by an example.
|
||||
Lets consider this entry in dcclibs.dat:
|
||||
|
||||
73 74 72 63 6D 70 00 ; "strcmp"
|
||||
00 00 00 00 00 00 00 00 00 ; Padding to 16 bytes
|
||||
03 00 ; Return type 3, TYPE_WORD_UNSIGN
|
||||
02 00 ; 2 arguments
|
||||
15 02 ; First arg is 0215
|
||||
00 ; Not var args
|
||||
|
||||
If we now skip to the "PM" part of the file, skip the number of
|
||||
arguments word, then skip 215*2 = 42A bytes, we find this:
|
||||
09 00 09 00 09 00 ...
|
||||
|
||||
The first 09 00 (TYPE_STR) refers to the type of the first parameter,
|
||||
and the second to the second parameter. There are only 2 arguments,
|
||||
so the third 09 00 refers to the first parameter of the next
|
||||
function. So both parameters are strings, as is expected.
|
||||
|
||||
For functions with variable parameters, bVarArg is set to 01, and the
|
||||
number of parameters reported is the number of fixed parameters. Here
|
||||
is another example:
|
||||
|
||||
66 70 72 69 6E 74 66 00 ; "fprintf"
|
||||
00 00 00 00 00 00 00 00 ; padding
|
||||
03 00 ; return type 3, TYPE_WORD_UNSIGN
|
||||
02 00 ; 2 fixed args
|
||||
81 01 ; First arg at index 0181
|
||||
01 ; Var args
|
||||
|
||||
and in the "PM" section at offset 181*2 = 0302, we find 08 00 09 00
|
||||
03 00 meaning that the first parameter is a pointer (in fact, we know
|
||||
it's a FILE *), and the second parameter is a string.
|
||||
|
||||
|
||||
|
||||
|
||||
6 What are all these errors, and why do they happen?
|
||||
----------------------------------------------------
|
||||
|
||||
When you run ParseHdr, as well as the progress statements like
|
||||
Processing \tc\include\alloc.h ...
|
||||
|
||||
you can get error messages. Basically, ignore these errors. They occur
|
||||
for a variety of reasons, most of which are detailed below.
|
||||
|
||||
1)
|
||||
Expected type: got ) (29)
|
||||
void __emit__()
|
||||
^
|
||||
This include file contained a non ansi prototype. This is rare, and
|
||||
__emit__ is not a standard function anyway. If it really bothers you,
|
||||
you could add the word "void" to the empty parentheses in your
|
||||
include file.
|
||||
|
||||
2)
|
||||
Expected ',' between parameter defs: got ( (28)
|
||||
void _Cdecl ctrlbrk (int _Cdecl (*handler)(void))
|
||||
|
||||
Here "handler" is a pointer to a function. Being a basically simple
|
||||
program, ParseHdr does not expand all typedef and #define statements,
|
||||
so it cannot distinguish between types and user defined function
|
||||
names. Therefore, it is not possible in general to parse any
|
||||
prototypes containing pointers to functions, so at this stage, any
|
||||
such prototypes will produce an error of some sort. DCC cannot
|
||||
currently make use of this type information anyway, so this is no
|
||||
real loss. There are typically half a dozen such errors.
|
||||
|
||||
3)
|
||||
Unknown type time_t
|
||||
|
||||
Types (such as time_t) that are structures or pointers to structures
|
||||
are not handled by ParseHdr, since typedef and #define statements are
|
||||
ignored. Again, there are typically only about a dozen of these.
|
||||
8
tools/parsehdr/parselib.mak
Normal file
8
tools/parsehdr/parselib.mak
Normal file
@ -0,0 +1,8 @@
|
||||
CFLAGS = -Zi -c -AS -W3 -D__MSDOS__
|
||||
|
||||
parselib.exe: parselib.obj
|
||||
link /CO parselib;
|
||||
|
||||
parselib.obj: parselib.c
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
24
tools/parsehdr/tcfiles.lst
Normal file
24
tools/parsehdr/tcfiles.lst
Normal file
@ -0,0 +1,24 @@
|
||||
\tc\include\alloc.h
|
||||
\tc\include\assert.h
|
||||
\tc\include\bios.h
|
||||
\tc\include\conio.h
|
||||
\tc\include\ctype.h
|
||||
\tc\include\dir.h
|
||||
\tc\include\dos.h
|
||||
\tc\include\errno.h
|
||||
\tc\include\fcntl.h
|
||||
\tc\include\float.h
|
||||
\tc\include\io.h
|
||||
\tc\include\limits.h
|
||||
\tc\include\math.h
|
||||
\tc\include\mem.h
|
||||
\tc\include\process.h
|
||||
\tc\include\setjmp.h
|
||||
\tc\include\share.h
|
||||
\tc\include\signal.h
|
||||
\tc\include\stdarg.h
|
||||
\tc\include\stddef.h
|
||||
\tc\include\stdio.h
|
||||
\tc\include\stdlib.h
|
||||
\tc\include\string.h
|
||||
\tc\include\time.h
|
||||
0
tools/readsig/CMakeLists.txt
Normal file
0
tools/readsig/CMakeLists.txt
Normal file
239
tools/readsig/readsig.cpp
Normal file
239
tools/readsig/readsig.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/* Quick program to read the output from makedsig */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "perfhlib.h"
|
||||
|
||||
/* statics */
|
||||
byte buf[100];
|
||||
int numKeys; /* Number of hash table entries (keys) */
|
||||
int numVert; /* Number of vertices in the graph (also size of g[]) */
|
||||
int PatLen; /* Size of the keys (pattern length) */
|
||||
int SymLen; /* Max size of the symbols, including null */
|
||||
FILE *f; /* File being read */
|
||||
|
||||
static word *T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
static word *g; /* g[] */
|
||||
|
||||
/* prototypes */
|
||||
void grab(int n);
|
||||
word readFileShort(void);
|
||||
void cleanup(void);
|
||||
|
||||
static bool bDispAll = FALSE;
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
word w, len;
|
||||
int h, i, j;
|
||||
long filePos;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
printf("Usage: readsig [-a] <SigFilename>\n");
|
||||
printf("-a for all symbols (else just duplicates)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 1;
|
||||
|
||||
if (strcmp(argv[i], "-a") == 0)
|
||||
{
|
||||
i++;
|
||||
bDispAll = TRUE;
|
||||
}
|
||||
if ((f = fopen(argv[i], "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot open %s\n", argv[i]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* Read the parameters */
|
||||
grab(4);
|
||||
if (memcmp("dccs", buf, 4) != 0)
|
||||
{
|
||||
printf("Not a dccs file!\n");
|
||||
exit(3);
|
||||
}
|
||||
numKeys = readFileShort();
|
||||
numVert = readFileShort();
|
||||
PatLen = readFileShort();
|
||||
SymLen = readFileShort();
|
||||
|
||||
/* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */
|
||||
hashParams( /* Set the parameters for the hash table */
|
||||
numKeys, /* The number of symbols */
|
||||
PatLen, /* The length of the pattern to be hashed */
|
||||
256, /* The character set of the pattern (0-FF) */
|
||||
0, /* Minimum pattern character value */
|
||||
numVert); /* Specifies C, the sparseness of the graph.
|
||||
See Czech, Havas and Majewski for details
|
||||
*/
|
||||
|
||||
T1base = readT1();
|
||||
T2base = readT2();
|
||||
g = readG();
|
||||
|
||||
/* Read T1 and T2 tables */
|
||||
grab(2);
|
||||
if (memcmp("T1", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T1'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = PatLen * 256 * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T1: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T1base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T1\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
grab(2);
|
||||
if (memcmp("T2", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'T2'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of T2: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(T2base, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
/* Now read the function g[] */
|
||||
grab(2);
|
||||
if (memcmp("gg", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'gg'\n");
|
||||
exit(3);
|
||||
}
|
||||
len = numVert * sizeof(word);
|
||||
w = readFileShort();
|
||||
if (w != len)
|
||||
{
|
||||
printf("Problem with size of g[]: file %d, calc %d\n", w, len);
|
||||
exit(4);
|
||||
}
|
||||
if (fread(g, 1, len, f) != len)
|
||||
{
|
||||
printf("Could not read T2\n");
|
||||
exit(5);
|
||||
}
|
||||
|
||||
|
||||
/* This is now the hash table */
|
||||
grab(2);
|
||||
if (memcmp("ht", buf, 2) != 0)
|
||||
{
|
||||
printf("Expected 'ht'\n");
|
||||
exit(3);
|
||||
}
|
||||
w = readFileShort();
|
||||
if (w != numKeys * (SymLen + PatLen + sizeof(word)))
|
||||
{
|
||||
printf("Problem with size of hash table: file %d, calc %d\n", w, len);
|
||||
exit(6);
|
||||
}
|
||||
|
||||
if (bDispAll)
|
||||
{
|
||||
fseek(f, 0, SEEK_CUR); /* Needed due to bug in MS fread()! */
|
||||
filePos = _lseek(fileno(f), 0, SEEK_CUR);
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
grab(SymLen + PatLen);
|
||||
|
||||
printf("%16s ", buf);
|
||||
for (j=0; j < PatLen; j++)
|
||||
{
|
||||
printf("%02X", buf[SymLen+j]);
|
||||
if ((j%4) == 3) printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n\n\n");
|
||||
fseek(f, filePos, SEEK_SET);
|
||||
}
|
||||
|
||||
for (i=0; i < numKeys; i++)
|
||||
{
|
||||
grab(SymLen + PatLen);
|
||||
|
||||
h = hash(&buf[SymLen]);
|
||||
if (h != i)
|
||||
{
|
||||
printf("Symbol %16s (index %3d) hashed to %d\n",
|
||||
buf, i, h);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Done!\n");
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cleanup(void)
|
||||
{
|
||||
/* Free the storage for variable sized tables etc */
|
||||
if (T1base) free(T1base);
|
||||
if (T2base) free(T2base);
|
||||
if (g) free(g);
|
||||
}
|
||||
|
||||
void grab(int n)
|
||||
{
|
||||
if (fread(buf, 1, n, f) != (size_t)n)
|
||||
{
|
||||
printf("Could not read\n");
|
||||
exit(11);
|
||||
}
|
||||
}
|
||||
|
||||
word
|
||||
readFileShort(void)
|
||||
{
|
||||
byte 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;
|
||||
}
|
||||
|
||||
/* Following two functions not needed unless creating tables */
|
||||
|
||||
void getKey(int i, byte **keys)
|
||||
{
|
||||
}
|
||||
|
||||
/* Display key i */
|
||||
void
|
||||
dispKey(int i)
|
||||
{
|
||||
}
|
||||
|
||||
11
tools/readsig/readsig.mak
Normal file
11
tools/readsig/readsig.mak
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS = -Zi -c -AL -W3 -D__MSDOS__
|
||||
|
||||
readsig.exe: readsig.obj perfhlib.obj
|
||||
link /CO readsig perfhlib;
|
||||
|
||||
readsig.obj: readsig.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
perfhlib.obj: perfhlib.c dcc.h perfhlib.h
|
||||
cl $(CFLAGS) $*.c
|
||||
|
||||
97
tools/readsig/readsig.txt
Normal file
97
tools/readsig/readsig.txt
Normal file
@ -0,0 +1,97 @@
|
||||
READSIG
|
||||
|
||||
1 What is ReadSig?
|
||||
|
||||
2 How do I use ReadSig?
|
||||
|
||||
3 What are duplicate signatures?
|
||||
|
||||
4 How can I make sense of the signatures?
|
||||
|
||||
|
||||
1 What is ReadSig?
|
||||
------------------
|
||||
|
||||
ReadSig is a quick and dirty program to read signatures from a DCC
|
||||
signature file. It was originally written as an integrity checker for
|
||||
signature files, but can now be used to see what's in a signature
|
||||
file, and which functions have duplicate signatures.
|
||||
|
||||
2 How do I use ReadSig?
|
||||
-----------------------
|
||||
|
||||
Just type
|
||||
readsig <sigfilename>
|
||||
|
||||
or
|
||||
|
||||
readsig -a <sigfilename>
|
||||
|
||||
|
||||
For example:
|
||||
readsig -a dcct2p.sig
|
||||
|
||||
Either way, you get a list of duplicate signatures, i.e. functions
|
||||
whose first 23 bytes, after wildcarding and chopping, (see section 3
|
||||
for details), that have the same signature.
|
||||
|
||||
With the -a switch, you also (before the above) get a list of all
|
||||
symbolic names in the signature file, and the signatures themselves
|
||||
in hex. This could be a dozen or more pages for large signature
|
||||
files.
|
||||
|
||||
Currently, signatures are 23 bytes long, and the symbolic names are
|
||||
truncated to 15 characters.
|
||||
|
||||
|
||||
3 What are duplicate signatures?
|
||||
--------------------------------
|
||||
|
||||
Duplicate signatures arise for 3 reasons. 1: length of the signature.
|
||||
2: wildcards. 3: chopping of the signature.
|
||||
|
||||
1: Because signatures are only 23 bytes long, there is a chance that
|
||||
two distinct signatures (first part of the binary image of a
|
||||
function) are identical in the first 23 bytes, but diverge later.
|
||||
|
||||
2: Because part of the binary image of a function depends on where it
|
||||
is loaded, parts of the signature are replaced with wildcards. It is
|
||||
possible that two functions are distinct only in places that are
|
||||
replaced by the wildcard byte (F4).
|
||||
|
||||
3: Signatures are "chopped" (cut short, and the remainder filled with
|
||||
binary zeroes) after an unconditional branch or subroutine return.
|
||||
This is to cope with functions shorter than the 23 byte size of
|
||||
signatures, so unrelated functions are not included at the end of a
|
||||
signature. (This would cause dcc to fail to recognise these short
|
||||
signatures if some other function happened to be loaded at the end).
|
||||
|
||||
The effect of duplicate signatures is that only one of the functions
|
||||
that has the same signature will be recognised. For example, suppose
|
||||
that sin, cos, and tan were just one wildcarded instruction followed
|
||||
by a jump to the same piece of code. Then all three would have the
|
||||
same signature, and calls to sin, cos, or tan would all be reported
|
||||
by dcc as just one of these, e.g. tan. If you suspect that this is
|
||||
happening, then at least ReadSig can alert you to this problem.
|
||||
|
||||
In general, the number of duplicate signatures that would actually be
|
||||
used in dcc is small, but it is possible that the above problem will
|
||||
occur.
|
||||
|
||||
|
||||
|
||||
4 How can I make sense of the signatures?
|
||||
-----------------------------------------
|
||||
|
||||
If you're one of those unfortunate individuals that can't decode hex
|
||||
instructions in your head, you can always use DispSig to copy it to a
|
||||
binary file, since you now know the name of the function. Then you
|
||||
can use debug or some other debugger to disassemble the binary file.
|
||||
Generally, most entries in signature files will be executable code,
|
||||
so it should disassemble readily.
|
||||
|
||||
Be aware that signatures are wildcarded, so don't pay any attention
|
||||
to the destination of jmp or call instructions (three or 5 byte
|
||||
jumps, anyway; 2 byte jumps are not wildcarded), and 16 bit immediate
|
||||
values. The latter will always be F4F4 (two wildcard bytes),
|
||||
regardless of what they were in the original function.
|
||||
Loading…
x
Reference in New Issue
Block a user