-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSYMBFILE.C
257 lines (214 loc) · 6.27 KB
/
SYMBFILE.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
* symbfile.c
*
* This file is part of Emu42
*
* Copyright (C) 2008 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu42.h"
//################
//#
//# Saturn Object File Reading
//#
//################
#define RECORD_BLOCK 256 // block size
#define OS_RESOLVED 0x8000 // resolved symbol
#define OS_RELOCATABLE 0x4000 // relocatable symbol
#define SAT_ID "Saturn3" // saturn block header
#define SYMB_ID "Symb" // symbol block header
#define HASHENTRIES 199 // size of hash table
typedef struct _REFDATA
{
LPTSTR lpszName; // symbol name
DWORD dwAddr; // resolved address
struct _REFDATA* pNext;
} REFDATA, *PREFDATA;
static PREFDATA ppsBase[HASHENTRIES]; // base of symbol references (initialized with NULL)
static __inline DWORD GetHash(DWORD dwVal)
{
return dwVal % HASHENTRIES; // hash function
}
static DWORD GetBigEndian(LPBYTE pbyData, INT nSize)
{
DWORD dwVal = 0;
while (nSize-- > 0)
{
dwVal <<= 8;
dwVal += *pbyData++;
}
return dwVal;
}
//
// check if entry table is empty
//
BOOL RplTableEmpty(VOID)
{
DWORD i;
BOOL bEmpty = TRUE;
// check if hash table is empty
for (i = 0; bEmpty && i < ARRAYSIZEOF(ppsBase); ++i)
{
bEmpty = (ppsBase[i] == NULL); // check if empty
}
return bEmpty;
}
//
// load entry table
//
BOOL RplLoadTable(LPCTSTR lpszFilename)
{
BYTE byPage[RECORD_BLOCK]; // record page size
HANDLE hFile;
DWORD dwFileLength,dwCodeLength,dwNoSymbols,dwNoReferences;
DWORD dwFilePos,dwBytesRead,dwSymb,dwPageIndex,dwResolvedSymb;
BOOL bSymbol,bSucc;
bSucc = FALSE;
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwResolvedSymb = 0; // no resolved symbols added
bSymbol = TRUE; // next set is a symbol
// read first page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
if (dwBytesRead == sizeof(byPage) && memcmp(byPage,SAT_ID,7) == 0)
{
// file length in bytes
dwFileLength = GetBigEndian(byPage+7,sizeof(WORD)) * sizeof(byPage);
// code area in nibbles
dwCodeLength = GetBigEndian(byPage+9,sizeof(DWORD));
// no. of symbols & references
dwNoSymbols = GetBigEndian(byPage+13,sizeof(WORD));
// no. of references
dwNoReferences = GetBigEndian(byPage+15,sizeof(WORD));
// convert code area length into no. of pages
dwPageIndex = (dwCodeLength + (2 * sizeof(byPage) - 1)) / (2 * sizeof(byPage));
// calculate no. of code pages
dwFilePos = dwPageIndex * sizeof(byPage);
// jump to begin of symbols by skipping no. of code pages
bSucc = SetFilePointer(hFile,dwFilePos,NULL,FILE_CURRENT) != INVALID_SET_FILE_POINTER;
dwFilePos += sizeof(byPage); // actual file position
}
// read all symbol pages
for (dwPageIndex = 256, dwSymb = 0; bSucc && dwSymb < dwNoSymbols; dwPageIndex += 42)
{
if (dwPageIndex >= 256) // read complete page
{
// read new symbol page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
dwFilePos += dwBytesRead; // update file position
if ( dwFilePos > dwFileLength
|| dwBytesRead != sizeof(byPage)
|| memcmp(byPage,SYMB_ID,4) != 0)
{
bSucc = FALSE;
break;
}
dwPageIndex = 4; // begin of new symbol
}
if (bSymbol) // this is the 42 byte symbol set
{
WORD wSymbolType = (WORD) GetBigEndian(byPage+dwPageIndex+36,sizeof(WORD));
// check if it's a resolved or relocatable symbol
bSymbol = (wSymbolType & OS_RESOLVED) != 0;
if (bSymbol) ++dwResolvedSymb; // added resolved symbol
if (wSymbolType == OS_RESOLVED) // resolved symbol type
{
TCHAR szSymbolName[36+1],*pcPtr;
PREFDATA pData;
DWORD dwHash;
#if defined _UNICODE
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,(LPCSTR)byPage+dwPageIndex,36,
szSymbolName,ARRAYSIZEOF(szSymbolName));
szSymbolName[36] = 0; // set EOS
}
#else
{
lstrcpyn(szSymbolName,(LPCSTR)byPage+dwPageIndex,ARRAYSIZEOF(szSymbolName));
}
#endif
// cut symbol name at first space character
if ((pcPtr = _tcschr(szSymbolName,_T(' '))) != NULL)
*pcPtr = 0; // set EOS
// allocate symbol memory
VERIFY(pData = (PREFDATA) malloc(sizeof(*pData)));
pData->lpszName = DuplicateString(szSymbolName);
pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD));
// add to hash table
dwHash = GetHash(pData->dwAddr);
pData->pNext = ppsBase[dwHash];
ppsBase[dwHash] = pData;
}
++dwSymb; // got symbol
}
else // 42 byte fill reference
{
bSymbol = TRUE; // nothing to do, next is a symbol set
}
}
bSucc = bSucc && (dwFilePos <= dwFileLength)
&& (dwNoSymbols == (dwResolvedSymb + dwNoReferences));
CloseHandle(hFile);
}
if (!bSucc) RplDeleteTable(); // delete current table
return bSucc;
}
//
// delete entry table
//
VOID RplDeleteTable(VOID)
{
PREFDATA pData;
DWORD i;
// clear hash entries
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
while (ppsBase[i] != NULL) // walk through all datasets
{
pData = ppsBase[i]->pNext;
free(ppsBase[i]->lpszName);
free(ppsBase[i]);
ppsBase[i] = pData;
}
}
return;
}
//
// return name for given entry address
//
LPCTSTR RplGetName(DWORD dwAddr)
{
PREFDATA pData = ppsBase[GetHash(dwAddr)];
// walk through all datasets of hash entry
for (; pData != NULL; pData = pData->pNext)
{
if (pData->dwAddr == dwAddr) // found address
return pData->lpszName; // return symbol name
}
return NULL;
}
//
// return entry address for given name
//
BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr)
{
PREFDATA pData;
DWORD i;
// check for every dataset in hash table
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
// walk through all datasets of hash entry
for (pData = ppsBase[i]; pData != NULL; pData = pData->pNext)
{
// found symbol name
if (lstrcmp(lpszName,pData->lpszName) == 0)
{
*pdwAddr = pData->dwAddr; // return address
return FALSE; // found
}
}
}
return TRUE; // not found
}