source: branches/gcc-kmk/tools/common/kFilePE.cpp@ 21759

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

Make tools/common library build.

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