source: trunk/tools/common/kFilePE.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 14.2 KB
Line 
1/* $Id: kFilePE.cpp,v 1.5 2002-02-24 02:47:26 bird Exp $
2 *
3 * kFilePE - PE files.
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 */
8
9/******************************************************************************
10* Header Files *
11******************************************************************************/
12#include <string.h>
13#include <malloc.h>
14
15#include "MZexe.h"
16#include "PEexe.h"
17
18#include "kTypes.h"
19#include "kError.h"
20#include "kFile.h"
21#include "kFileFormatBase.h"
22#include "kFileInterfaces.h"
23#include "kFilePE.h"
24
25
26/*******************************************************************************
27* Global Variables *
28*******************************************************************************/
29#if 0
30kFilePE kFilePE((kFile*)NULL);
31#endif
32
33
34/**
35 * Constructs a kFilePE object for a file.
36 * @param pFile File to create object from.
37 * @remark throws errorcode
38 */
39kFilePE::kFilePE(kFile *pFile) throw (kError) :
40 kFileFormatBase(pFile),
41 pvBase(NULL),
42 pDosHdr(NULL), pFileHdr(NULL), pOptHdr(NULL), paDataDir(NULL), paSectionHdr(NULL),
43 pExportDir(NULL),
44 pImportDir(NULL),
45 pRsrcDir(NULL),
46 pBRelocDir(NULL),
47 pDebugDir(NULL),
48 pCopyright(NULL),
49 pulGlobalPtr(NULL),
50 pTLSDir(NULL),
51 pLoadConfigDir(NULL),
52 pBoundImportDir(NULL),
53 pIATDir(NULL),
54 pDelayImportDir(NULL)
55{
56 IMAGE_DOS_HEADER doshdr;
57 long offPEHdr = 0;
58 IMAGE_NT_HEADERS pehdr;
59
60 /* read dos-header (If tehre is one) */
61 pFile->setThrowOnErrors();
62 pFile->readAt(&doshdr, sizeof(doshdr), 0);
63 if (doshdr.e_magic == IMAGE_DOS_SIGNATURE)
64 {
65 if (doshdr.e_lfanew <= sizeof(doshdr))
66 throw(kError(kError::INVALID_EXE_SIGNATURE));
67 offPEHdr = doshdr.e_lfanew;
68 }
69
70 /* read pe headers and do minor verifications */
71 pFile->readAt(&pehdr, sizeof(pehdr), offPEHdr);
72 if (pehdr.Signature != IMAGE_NT_SIGNATURE)
73 throw(kError(kError::INVALID_EXE_SIGNATURE));
74 if ( pehdr.FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)
75 || pehdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
76 throw(kError(kError::BAD_EXE_FORMAT));
77
78 /* create mapping */
79 pvBase = malloc(pehdr.OptionalHeader.SizeOfImage);
80 if (pvBase == NULL)
81 throw(kError(kError::NOT_ENOUGH_MEMORY));
82 memset(pvBase, 0, pehdr.OptionalHeader.SizeOfImage);
83
84 /*
85 printf("%ld\n", pehdr.OptionalHeader.SizeOfHeaders);
86 printf("%ld\n", sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
87 kASSERT(pehdr.OptionalHeader.SizeOfHeaders ==
88 sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
89 */
90 try
91 {
92 /* read optional header */
93 pFile->readAt(pvBase, pehdr.OptionalHeader.SizeOfHeaders, 0);
94
95 /* read sections */
96 int i;
97 for (i = 0; i < pehdr.FileHeader.NumberOfSections; i++)
98 {
99 unsigned long cbSection;
100 PIMAGE_SECTION_HEADER pSectionHdr =
101 #if 0
102 IMAGE_FIRST_SECTION(((unsigned long)pvBase + ((PIMAGE_DOS_HEADER)pvBase)->e_lfanew));
103 #else
104 (PIMAGE_SECTION_HEADER) ( (unsigned long)pvBase + doshdr.e_lfanew + sizeof(IMAGE_NT_HEADERS) );
105 #endif
106 pSectionHdr += i;
107
108 cbSection = KMIN(pSectionHdr->Misc.VirtualSize, pSectionHdr->SizeOfRawData);
109 if (cbSection)
110 pFile->readAt((char*)pvBase + pSectionHdr->VirtualAddress,
111 cbSection, pSectionHdr->PointerToRawData);
112 }
113
114 /* set pointers */
115 if (*(unsigned short*)pvBase == IMAGE_DOS_SIGNATURE)
116 {
117 pDosHdr = (PIMAGE_DOS_HEADER)pvBase;
118 pFileHdr = (PIMAGE_FILE_HEADER)((char*)pvBase + pDosHdr->e_lfanew + 4);
119 }
120 else
121 pFileHdr = (PIMAGE_FILE_HEADER)((char*)pvBase + 4);
122
123 pOptHdr = (PIMAGE_OPTIONAL_HEADER)((int)pFileHdr + sizeof(*pFileHdr));
124 paDataDir = (PIMAGE_DATA_DIRECTORY)((int)pOptHdr + pFileHdr->SizeOfOptionalHeader
125 - pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
126 paSectionHdr = (PIMAGE_SECTION_HEADER)((int)paDataDir +
127 pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
128
129 //if (paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
130 // pExportDir = (PIMAGE_EXPORT_DIRECTORY)((int)pvBase + paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
131 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes && i < 16; i++)
132 {
133 if (paDataDir[i].VirtualAddress != 0)
134 {
135 if (paDataDir[i].VirtualAddress < pOptHdr->SizeOfImage)
136 ((unsigned long*)&this->pExportDir)[i] = (int)pvBase + paDataDir[i].VirtualAddress;
137 }
138 }
139 }
140 catch (kError err)
141 {
142 free(pvBase);
143 pvBase = NULL;
144 throw(err);
145 }
146}
147
148
149/**
150 * Destructor.
151 */
152kFilePE::~kFilePE() throw (kError)
153{
154 if (pvBase)
155 free(pvBase);
156}
157
158
159/**
160 * Query for the module name.
161 * @returns Success indicator. TRUE / FALSE.
162 * @param pszBuffer Pointer to buffer which to put the name into.
163 * @param cchBuffer Size of the buffer (defaults to 260 chars).
164 */
165KBOOL kFilePE::moduleGetName(char *pszBuffer, int cchSize/* = 260*/)
166{
167 if (pExportDir && pExportDir->Name)
168 {
169 char *psz = (char*)((int)pExportDir->Name + (int)pvBase);
170 int cch = strlen(psz) + 1;
171 if (cch > cchSize)
172 return FALSE;
173 memcpy(pszBuffer, psz, cch);
174 }
175 else
176 return FALSE;
177
178 return TRUE;
179}
180
181
182/**
183 * Finds the first exports.
184 * @returns Success indicator. TRUE / FALSE.
185 * @param pExport Pointer to export structure.
186 * @remark
187 */
188KBOOL kFilePE::exportFindFirst(kExportEntry *pExport)
189{
190 if (pExportDir && pExportDir->NumberOfFunctions)
191 {
192 memset(pExport, 0, sizeof(kExportEntry));
193 pExport->ulOrdinal = pExportDir->Base - 1;
194 return exportFindNext(pExport);
195 }
196
197 return FALSE;
198}
199
200
201/**
202 * Finds the next export.
203 * @returns Success indicator. TRUE / FALSE.
204 * @param pExport Pointer to export structure.
205 * @remark
206 */
207KBOOL kFilePE::exportFindNext(kExportEntry *pExport)
208{
209 if (pExportDir && pExportDir->NumberOfFunctions)
210 {
211 void **ppv = (void**)((int)pExportDir->AddressOfFunctions + (int)pvBase);
212
213 ++pExport->ulOrdinal -= pExportDir->Base;
214 while (ppv[pExport->ulOrdinal] == NULL && pExport->ulOrdinal < pExportDir->NumberOfFunctions)
215 pExport->ulOrdinal++;
216
217 if (pExport->ulOrdinal < pExportDir->NumberOfFunctions)
218 {
219 int iName = 0;
220 unsigned short *pawNameOrdinals = (unsigned short *)
221 ((int)pExportDir->AddressOfNameOrdinals + (int)pvBase);
222
223 /* look for name */
224 while (iName < (int)pExportDir->NumberOfNames &&
225 pawNameOrdinals[iName] != pExport->ulOrdinal)
226 iName++;
227 if (iName < (int)pExportDir->NumberOfNames)
228 strcpy(&pExport->achName[0],
229 (char*)((int)pvBase + ((int*)((int)pvBase + (int)pExportDir->AddressOfNames))[iName]));
230 else
231 pExport->achName[0] = '\0';
232 pExport->ulOrdinal += pExportDir->Base;
233 }
234 else
235 return FALSE;
236 }
237 else
238 return FALSE;
239
240 pExport->ulAddress = pExport->iObject = pExport->ulOffset = ~0UL; /* FIXME/TODO */
241 pExport->achIntName[0] = '\0';
242 pExport->pv = NULL;
243 return TRUE;
244}
245
246
247/**
248 * Frees resources associated with the communicatin area.
249 * It's not necessary to call this when exportFindNext has return FALSE.
250 * (We don't allocate anything so it's not a problem ;-)
251 * @param pExport Communication area which has been successfully
252 * processed by findFirstExport.
253 */
254void kFilePE::exportFindClose(kExportEntry *pExport)
255{
256 pExport = pExport;
257 return;
258}
259
260
261/**
262 * Lookup information on a spesific export given by ordinal number.
263 * @returns Success indicator.
264 * @param pExport Communication area containing export information
265 * on successful return.
266 * @remark stub
267 */
268KBOOL kFilePE::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
269{
270 kASSERT(!"not implemented.");
271 ulOrdinal = ulOrdinal;
272 pExport = pExport;
273 return FALSE;
274}
275
276/**
277 * Lookup information on a spesific export given by name.
278 * @returns Success indicator.
279 * @param pExport Communication area containing export information
280 * on successful return.
281 * @remark stub
282 */
283KBOOL kFilePE::exportLookup(const char * pszName, kExportEntry *pExport)
284{
285 kASSERT(!"not implemented.");
286 pszName = pszName;
287 pExport = pExport;
288 return FALSE;
289}
290
291
292/**
293 * Mini dump function.
294 */
295KBOOL kFilePE::dump(kFile *pOut)
296{
297 int i,j,k;
298 int c;
299
300 /*
301 * Dump sections.
302 */
303 pOut->printf("Sections\n"
304 "--------\n");
305 for (i = 0; i < pFileHdr->NumberOfSections; i++)
306 {
307 pOut->printf("%2d %-8.8s VirtSize: 0x%08x RVA: 0x%08x\n"
308 " RawSize: 0x%08x FileOffset: 0x%08x\n"
309 " #Relocs: 0x%08x FileOffset: 0x%08x\n"
310 " #LineNbr: 0x%08x FileOffset: 0x%08x\n"
311 " Characteristics: 0x%08x\n",
312 i,
313 paSectionHdr[i].Name,
314 paSectionHdr[i].Misc.VirtualSize,
315 paSectionHdr[i].VirtualAddress,
316 paSectionHdr[i].PointerToRawData,
317 paSectionHdr[i].PointerToRawData,
318 paSectionHdr[i].NumberOfRelocations,
319 paSectionHdr[i].PointerToRelocations,
320 paSectionHdr[i].NumberOfLinenumbers,
321 paSectionHdr[i].PointerToLinenumbers,
322 paSectionHdr[i].Characteristics
323 );
324 }
325 pOut->printf("\n");
326
327
328 /*
329 * Dump the directories.
330 */
331 pOut->printf("Data Directory\n"
332 "--------------\n");
333 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes; i++)
334 {
335 static const char * apszDirectoryNames[] =
336 {
337 "Export",
338 "Import",
339 "Resource",
340 "Exception",
341 "Security",
342 "Base Reloc",
343 "Debug",
344 "Copyright",
345 "Global Ptr",
346 "TLS",
347 "Load Config",
348 "Bound Import",
349 "IAT",
350 "Delay Import",
351 "COM Descriptor",
352 "unknown",
353 "unknown"
354 };
355
356 pOut->printf("%2d %-16s Size: 0x%08x RVA: 0x%08x\n",
357 i,
358 apszDirectoryNames[i],
359 pOptHdr->DataDirectory[i].Size,
360 pOptHdr->DataDirectory[i].VirtualAddress);
361 }
362 pOut->printf("\n");
363
364
365 /*
366 * Dump Import Directory if present.
367 */
368 if (pImportDir)
369 {
370 pOut->printf("Import Directory\n"
371 "----------------\n");
372
373 PIMAGE_IMPORT_DESCRIPTOR pCur = pImportDir;
374 while (pCur->u.Characteristics != 0)
375 {
376 pOut->printf("%s\n", (char*)pvBase + pCur->Name);
377 pCur++;
378 }
379 }
380
381
382 /*
383 * Dump TLS directory if present
384 */
385 if (pTLSDir)
386 {
387 pOut->printf("TLS Directory\n"
388 "-------------\n");
389 if (pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size % sizeof(IMAGE_TLS_DIRECTORY))
390 pOut->printf(" Warning! The size directory isn't a multiple of the directory struct!");
391
392 c = (int)(pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size / sizeof(IMAGE_TLS_DIRECTORY));
393 for (i = 0; i < c; i++)
394 {
395
396 pOut->printf("%2d StartAddressOfRawData %p\n"
397 " EndAddressOfRawData %p\n"
398 " AddressOfIndex %p\n"
399 " AddressOfCallBacks %p\n"
400 " SizeOfZeroFill %p\n"
401 " Characteristics %p\n",
402 i,
403 pTLSDir[i].StartAddressOfRawData,
404 pTLSDir[i].EndAddressOfRawData,
405 pTLSDir[i].AddressOfIndex,
406 pTLSDir[i].AddressOfCallBacks,
407 pTLSDir[i].SizeOfZeroFill,
408 pTLSDir[i].Characteristics);
409
410 /* Print Callbacks */
411 if (pTLSDir[i].AddressOfCallBacks)
412 {
413 unsigned long * paulIndex;
414 unsigned long * paulCallback;
415 unsigned long ulBorlandRVAFix = 0UL;
416
417 /* Check if the addresses in the TLSDir is RVAs or real addresses */
418 if (pTLSDir[i].StartAddressOfRawData > pOptHdr->ImageBase)
419 ulBorlandRVAFix = pOptHdr->ImageBase;
420
421 j = 0;
422 paulIndex = (unsigned long *)((unsigned long)pTLSDir[i].AddressOfIndex - ulBorlandRVAFix + (unsigned long)this->pvBase);
423 paulCallback = (unsigned long *)((unsigned long)pTLSDir[i].AddressOfCallBacks - ulBorlandRVAFix + (unsigned long)this->pvBase);
424 if (*paulCallback)
425 {
426 pOut->printf(" Callbacks:\n");
427 for (j = 0; paulCallback[j] != 0; j++)
428 {
429 pOut->printf(" %02d Address: 0x%08x Index: 0x%08x\n",
430 paulIndex[j],
431 paulCallback[j]);
432 }
433 }
434 else
435 pOut->printf(" (Empty callback array!)\n");
436 }
437
438 }
439
440 pOut->printf("\n");
441 }
442
443
444 return TRUE;
445}
446
Note: See TracBrowser for help on using the repository browser.