Changes having to due with my new 2-pass function relocator code.
[dyninst.git] / pdutil / h / Object-nt.h
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /************************************************************************
43  * Object-nt.h: Windows NT object files.
44 ************************************************************************/
45
46
47 \f
48
49
50 #if !defined(_Object_nt_h_)
51 #define _Object_nt_h_
52
53
54 \f
55
56
57 /************************************************************************
58  * header files.
59 ************************************************************************/
60
61 #include "util/h/Dictionary.h"
62 #include "util/h/String.h"
63 #include "util/h/Symbol.h"
64 #include "util/h/Types.h"
65 #include "util/h/Vector.h"
66
67 #include <stdlib.h>
68 #include <winnt.h>
69
70
71 \f
72
73
74 /************************************************************************
75  * class Object
76 ************************************************************************/
77
78 class Object : public AObject {
79 public:
80              Object (const string, void (*)(const char *) = log_msg);
81              Object (const Object &);
82              Object (const string, u_int, void (*)(const char *) = log_msg);
83
84     virtual ~Object ();
85
86     Object&   operator= (const Object &);
87
88     //void *getFPOtable() const; // returns a pointer to the FPO table
89     //void *getFPOtableEntry(unsigned offset) const;
90
91 private:
92     void    load_object ();
93     
94
95     HANDLE fileHandle; // handle for file
96     HANDLE mapHandle;  // handle for mapping
97     char *baseAddr;    // base address of mapping
98
99     //DWORD ptr_to_rdata;
100      
101 };
102
103 static int symbol_compare(const void *x, const void *y) {
104     Symbol *s1 = (Symbol *)x;
105     Symbol *s2 = (Symbol *)y;
106     return (s1->addr() - s2->addr());
107 }
108
109
110
111 /* break fullName into name and path parts */
112 static void getFileNameAndPath(const string fullName, string &name, string &path) {
113   unsigned long size = GetFullPathName(fullName.string_of(), 0, 0, 0);
114   char *buffer = new char[size];
115   char *fptr;
116   GetFullPathName(fullName.string_of(), size, buffer, &fptr);
117   name = fptr;
118   *fptr = 0;
119   path = buffer;
120   delete buffer;
121 }
122
123 /* get the value of environment variable varName */
124 static void getEnvVar(const string varName, string &value) {
125   unsigned long pathLen = GetEnvironmentVariable(varName.string_of(), 0, 0);
126   char *buffer = new char[pathLen];
127   GetEnvironmentVariable(varName.string_of(), buffer, pathLen);
128   value = buffer;
129   delete buffer;
130 }
131
132 /* find a .dbg file for the .exe or .dll file */
133 static bool findDbgFile(const string exeFile, DWORD exeTimeStamp,
134                         HANDLE &dbgFile, 
135                         HANDLE &dbgMapping, const char * &dbgAddr,
136                         IMAGE_SYMBOL * &syms, unsigned long &nsyms,
137                         char * &strs) {
138   string fileName;
139   string filePath;
140   getFileNameAndPath(exeFile, fileName, filePath);
141
142   /*
143      kludge: we only read a .dbg file if it is for kernel32.dll.
144      There seem to be some problems with some files - the symbols
145      don't match the code, even though the timestamps in the
146      files match, so we will not read them for now.
147   */
148   if (fileName != "kernel32.dll" && fileName != "KERNEL32.dll") {
149     return false;
150   }
151
152   string dbgName = string(fileName.string_of(), fileName.length()-3) + "dbg";
153
154   // first, look in the same directory of the .exe file
155   string dbgPath = filePath + dbgName;
156   dbgFile = CreateFile(dbgPath.string_of(), GENERIC_READ, FILE_SHARE_READ, 
157                        NULL, OPEN_EXISTING, NULL, NULL);
158   if (dbgFile != INVALID_HANDLE_VALUE) {
159     dbgMapping = CreateFileMapping(dbgFile, NULL, PAGE_READONLY,0,0,NULL);
160     if (dbgMapping == INVALID_HANDLE_VALUE) {
161       CloseHandle(dbgFile);
162       return false;
163     }
164     dbgAddr = (char *)MapViewOfFile(dbgMapping, FILE_MAP_READ, 0, 0, 0);
165     if (dbgAddr == NULL) {
166       CloseHandle(dbgMapping);
167       CloseHandle(dbgFile);
168       return false;
169     }
170   } else {
171     // now look in %SystemRoot%\SYMBOLS\DLL
172     string sysRootDir;
173     getEnvVar("SystemRoot", sysRootDir);
174     dbgPath = sysRootDir + "\\SYMBOLS\\DLL\\" + dbgName;
175     dbgFile = CreateFile(dbgPath.string_of(), GENERIC_READ, FILE_SHARE_READ, 
176                          NULL, OPEN_EXISTING, NULL, NULL);
177     if (dbgFile == INVALID_HANDLE_VALUE)
178       return false;
179     dbgMapping = CreateFileMapping(dbgFile, NULL, PAGE_READONLY,0,0,NULL);
180     if (dbgMapping == INVALID_HANDLE_VALUE) {
181       CloseHandle(dbgFile);
182       return false;
183     }
184     dbgAddr = (char *)MapViewOfFile(dbgMapping, FILE_MAP_READ, 0, 0, 0);
185     if (dbgAddr == NULL) {
186       CloseHandle(dbgMapping);
187       CloseHandle(dbgFile);
188       return false;
189     }
190   }
191
192   // read the header
193   IMAGE_SEPARATE_DEBUG_HEADER *dbgHeader =
194        (IMAGE_SEPARATE_DEBUG_HEADER *)dbgAddr;
195   IMAGE_DEBUG_DIRECTORY *dbgDir;
196
197   if (dbgHeader->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE
198       && dbgHeader->TimeDateStamp == exeTimeStamp) {
199     //printf("dgbHeader->TimeDateStamp %x %x %x %x %d\n", dbgHeader->TimeDateStamp,
200     //       exeTimeStamp, dbgHeader->CheckSum, dbgHeader->ImageBase,
201     //       dbgHeader->SizeOfImage);
202     dbgDir = (IMAGE_DEBUG_DIRECTORY *)
203                &dbgAddr[sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
204                         dbgHeader->NumberOfSections*
205                        sizeof(IMAGE_SECTION_HEADER) + 
206                        dbgHeader->ExportedNamesSize];
207
208     if (dbgDir->Type == IMAGE_DEBUG_TYPE_COFF) {
209       IMAGE_COFF_SYMBOLS_HEADER *coffHdr = 
210         (IMAGE_COFF_SYMBOLS_HEADER *)&dbgAddr[dbgDir->PointerToRawData];
211       nsyms = coffHdr->NumberOfSymbols;
212       syms = (IMAGE_SYMBOL *) &dbgAddr[dbgDir->PointerToRawData+
213                                        coffHdr->LvaToFirstSymbol];
214       strs = (char *) &dbgAddr[dbgDir->PointerToRawData+
215                                coffHdr->LvaToFirstSymbol+
216                                nsyms*sizeof(IMAGE_SYMBOL)];
217       return true;
218     }
219   }
220
221   // generate error message -- TODO
222   if (dbgHeader->Signature != IMAGE_SEPARATE_DEBUG_SIGNATURE) {
223     fprintf(stderr,"Unable to read debug file %s: invalid signature\n", dbgPath.string_of());
224   } else if (dbgHeader->TimeDateStamp != exeTimeStamp) {
225     fprintf(stderr,"Unable to read debug file %s: wrong date/timestamp\n",
226            dbgPath.string_of());
227   } else {
228     fprintf(stderr,"Unable to process debug file %s: file is not in COFF format\n",
229            dbgPath.string_of());
230   }
231   
232   UnmapViewOfFile(dbgAddr);
233   CloseHandle(dbgMapping);
234   CloseHandle(dbgFile);
235   return false;
236
237 }
238
239
240 inline
241 void
242 Object::load_object() {
243     // Set these to invalid values in case we fail along the way
244     baseAddr = NULL;
245     mapHandle = NULL;
246     fileHandle = INVALID_HANDLE_VALUE;
247
248     //
249     const char* file = file_.string_of();
250     bool        did_open = false;
251
252     IMAGE_DOS_HEADER * dosHdr;
253     IMAGE_NT_HEADERS * ntHdrs;
254     IMAGE_FILE_HEADER * header;
255     IMAGE_SECTION_HEADER * sections;
256     IMAGE_SYMBOL * syms;
257     unsigned long nsyms;
258     char *strs;
259
260     string        module = "DEFAULT_MODULE";
261     string        name   = "DEFAULT_SYMBOL";
262     vector<Symbol> allSymbols;
263     Address       addr;
264     Address       imageBase;
265     bool isDll = false;
266
267     bool useDbgFile = false;
268     HANDLE dbgFile;     // handle to .dbg file
269     HANDLE dbgMapping;  // handle to mapping of .dbg file
270     char * dbgAddr;     // base address of mapping
271
272     /* try */ {
273
274         fileHandle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, 
275                         NULL, OPEN_EXISTING, NULL, NULL);
276         if (fileHandle == INVALID_HANDLE_VALUE) {
277             log_perror(err_func_, "CreateFile");
278             /* throw exception */ goto cleanup;
279         }
280         did_open = true;
281
282         mapHandle = CreateFileMapping(fileHandle, NULL, PAGE_READONLY,0,0,NULL);
283         if (mapHandle == INVALID_HANDLE_VALUE) {
284             log_perror(err_func_, "CreateFileMapping");
285             /* throw exception */ goto cleanup;
286         }
287         baseAddr = (char *)MapViewOfFile(mapHandle, FILE_MAP_READ, 0, 0, 0);
288         if (baseAddr == NULL) {
289             log_perror(err_func_, "MapViewOfFile");
290             /* throw exception */ goto cleanup;
291         }
292
293         /* read the DOS header */
294         dosHdr = (IMAGE_DOS_HEADER *)baseAddr;
295         if (dosHdr->e_magic != IMAGE_DOS_SIGNATURE) {
296             log_perror(err_func_, "Bad magic number");
297             /* throw exception */ goto cleanup;
298         }
299
300         /* read NT headers */
301         ntHdrs = (IMAGE_NT_HEADERS *)(&baseAddr[dosHdr->e_lfanew]);
302         if (ntHdrs->Signature != IMAGE_NT_SIGNATURE) {
303             log_perror(err_func_, "Bad magic number");
304             /* throw exception */ goto cleanup;
305         }
306
307         header = &ntHdrs->FileHeader;
308
309         //printf("Machine = %x\n", header->Machine);
310         //printf("Num sections = %d\n", header->NumberOfSections);
311         //printf("Time/date = %x\n", header->TimeDateStamp);
312         //printf("symbol table = %x\n", header->PointerToSymbolTable);
313         //printf("Num syms = %d\n", header->NumberOfSymbols);
314         //printf("Optional = %d\n", header->SizeOfOptionalHeader);
315         //printf("Chararc = %x\n", header->Characteristics);
316         //printf("BC: %x\n", ntHdrs->OptionalHeader.BaseOfCode);
317         //printf("BD: %x\n", ntHdrs->OptionalHeader.BaseOfData);
318
319         isDll = header->Characteristics & IMAGE_FILE_DLL;
320
321         imageBase = ntHdrs->OptionalHeader.ImageBase;
322
323         /* read the sections */
324         sections = (IMAGE_SECTION_HEADER *) (&baseAddr[dosHdr->e_lfanew +
325                                                  +sizeof(DWORD)
326           + sizeof(IMAGE_FILE_HEADER) + header->SizeOfOptionalHeader]);
327         
328         for (unsigned u1 = 0; u1 < header->NumberOfSections; u1++) {
329           char sname[9];
330           strncpy(sname, (const char *) &sections[u1].Name[0], 8);
331           sname[8] = 0;
332           if (strcmp(sname, ".text") == 0) {
333             code_ptr_ = (Word*)&baseAddr[sections[u1].PointerToRawData];
334             code_off_ = (Word)(imageBase +
335                         ntHdrs->OptionalHeader.BaseOfCode);
336             code_len_ = (unsigned)(sections[u1].Misc.VirtualSize/sizeof(Word));
337             //fprintf(stderr,"codeoff: %x, codelen: %d\n", code_off_, code_len_);
338           }
339           if (strcmp(sname, ".data") == 0) {
340             data_ptr_ = (Word*)&baseAddr[sections[u1].PointerToRawData];
341             data_off_ = (Word)(imageBase +
342                                sections[u1].VirtualAddress
343                                /*ntHdrs->OptionalHeader.BaseOfData*/);
344             data_len_ = (unsigned)(sections[u1].Misc.VirtualSize/sizeof(Word));
345             //printf("dataoff: %x, datalen: %d\n", data_off_, data_len_);
346           }
347
348           //if (strcmp(sname, ".rdata") == 0) {
349           //  ptr_to_rdata = sections[u1].PointerToRawData;
350           //}
351
352         }
353
354         if (ntHdrs->FileHeader.PointerToSymbolTable) {
355           syms = (IMAGE_SYMBOL *)
356                       (&baseAddr[ntHdrs->FileHeader.PointerToSymbolTable]);
357           nsyms = ntHdrs->FileHeader.NumberOfSymbols;
358           strs = (char *)(&baseAddr[ntHdrs->FileHeader.PointerToSymbolTable
359                             + nsyms * sizeof(IMAGE_SYMBOL)]);
360         } else {
361           // no symbol table
362           if (findDbgFile(file, header->TimeDateStamp, dbgFile, dbgMapping,
363                           dbgAddr, syms, nsyms, strs)) {
364             useDbgFile = true;
365           }
366           else {
367             //printf("File %s has no symbol table\n", file);
368             nsyms = 0;
369           }
370         }
371
372 #ifdef notdef
373         // We could use the imagehlp library to read symbols that are in
374         // CodeView format. However, the image help library symbol handler
375         // does not give some information we need. In particular,
376         // it does not give the type of symbols, so we don't known
377         // which symbols are functions and which are not.
378        
379         if (nsyms == 0) {
380           // object file has no COFF debug info. We use the imagehelp
381           // library to read symbol table in other formats
382           // This is a kludge, we should improve this code later
383           extern HANDLE kludgeProcHandle;
384           if (kludgeProcHandle) {
385
386             IMAGEHLP_MODULE mod;
387             unsigned numSyms = 0;
388
389             mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
390             if (SymGetModuleInfo(kludgeProcHandle, imageBase, &mod)) {
391               numSyms = mod.NumSyms;
392               //fprintf(stderr,"#### numSyms=%d, type=%d\n", numSyms, mod.SymType);
393             }
394
395             if (numSyms > 0 && (mod.SymType==SymCoff || mod.SymType==SymCv
396                                 || mod.SymType==SymPdb)) {
397               
398               char buffer[1024+sizeof(IMAGEHLP_SYMBOL)];
399               IMAGEHLP_SYMBOL *sym = (IMAGEHLP_SYMBOL *)&buffer;
400
401               sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
402               sym->Address = code_off_;
403               sym->MaxNameLength = 1024;
404
405               // SymGetSymNext doesn't always find a symbol if we
406               // set the initial address as the code offset,
407               // so we keep trying successive addresses 
408               // to make sure we get the first symbol
409               while (!SymGetSymNext(kludgeProcHandle, sym)
410                      && sym->Address <= code_off_ + code_len_*sizeof(Word))
411                 sym->Address++;
412               
413               do {
414                 //printf(">> %s %x %d\n", sym->Name, sym->Address, sym->Size);
415                 if (sym->Address > code_off_ + code_len_*sizeof(Word))
416                   continue;
417                 allSymbols += Symbol(sym->Name, "", Symbol::PDST_FUNCTION,
418                                      Symbol::SL_GLOBAL,
419                                      sym->Address, false, sym->Size);
420               } while (SymGetSymNext(kludgeProcHandle, sym));
421             }
422           }
423         }
424 #endif
425
426         if (isDll) {
427           // for dynamic linked libraries, we have a single module, with
428           // the same name as the library
429           string fileName;
430           string filePath;
431           getFileNameAndPath(file, fileName, filePath);
432           allSymbols += Symbol(fileName, "", Symbol::PDST_MODULE,
433                                 Symbol::SL_GLOBAL, imageBase, false);
434         }
435
436         for (unsigned v = 0; v < nsyms; v++) {
437           
438           if (syms[v].N.Name.Short != 0) {
439               char sname[9];
440               strncpy(sname, (char *)(&syms[v].N.ShortName), 8);
441               sname[8] = 0;
442               name = sname;
443           } else {
444               name = &strs[syms[v].N.Name.Long];
445           }
446
447           if (name.prefixed_by("_$$$") || name.prefixed_by("$$$")) {
448             v += syms[v].NumberOfAuxSymbols;
449           } else if (syms[v].StorageClass == IMAGE_SYM_CLASS_FILE) {
450             // a file name. The name of the file is a zero terminated
451             // string in one or more auxiliar entries following this one
452             name = (char *) (&syms[v+1]);
453             // skip the auxiliary entries
454             v += (strlen(name.string_of()) / sizeof(IMAGE_SYMBOL)) + 1;
455
456             // there may be a .text entry following the file name
457             // this entry has the starting address for this file
458             if (syms[v+1].N.Name.Short != 0 &&
459                 strncmp((char *)(&syms[v+1].N.ShortName), ".text", 5)==0) {
460               addr = syms[v+1].Value;
461               v++;
462             } else {
463               addr = 0;
464             }
465             if (!isDll)
466               allSymbols += Symbol(name, "", Symbol::PDST_MODULE,
467                                 Symbol::SL_GLOBAL, imageBase+addr, false);
468
469           } else if (ISFCN(syms[v].Type)) {
470             if (syms[v].N.Name.Short != 0) {
471               char sname[9];
472               strncpy(sname, (char *)(&syms[v].N.ShortName), 8);
473               sname[8] = 0;
474               name = sname;
475             } else {
476               name = &strs[syms[v].N.Name.Long];
477             }
478
479             if (syms[v].StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
480               allSymbols += Symbol(name, "", Symbol::PDST_FUNCTION,
481                                    Symbol::SL_GLOBAL,
482                                    imageBase+syms[v].Value, false);
483             else
484               allSymbols += Symbol(name, "", Symbol::PDST_FUNCTION,
485                                    Symbol::SL_LOCAL,
486                                    imageBase+syms[v].Value, false);
487
488             v += syms[v].NumberOfAuxSymbols;
489           } else if (syms[v].SectionNumber > 0) {
490             if (syms[v].N.Name.Short != 0) {
491               char sname[9];
492               strncpy(sname, (char *)(&syms[v].N.ShortName), 8);
493               sname[8] = 0;
494               name = sname;
495             } else {
496               name = &strs[syms[v].N.Name.Long];
497             }
498             if (name == ".text") {
499
500             }
501             else if (syms[v].StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
502               allSymbols += Symbol(name, "", Symbol::PDST_OBJECT,
503                                    Symbol::SL_GLOBAL,
504                                    imageBase+syms[v].Value, false);
505             else
506               allSymbols += Symbol(name, "", Symbol::PDST_OBJECT,
507                                    Symbol::SL_LOCAL,
508                                    imageBase+syms[v].Value, false);
509             v += syms[v].NumberOfAuxSymbols;
510           }
511
512         }
513
514         const string emptyStr = "";
515         // add an extra symbol to mark the end of the text segment
516         allSymbols += Symbol("", "", Symbol::PDST_OBJECT, Symbol::SL_GLOBAL, 
517                              code_off_+code_len_*sizeof(Word), false);
518
519         // Sort the symbols on address to find the function boundaries
520         allSymbols.sort(symbol_compare);
521
522
523 #ifdef XXX_GENERATE_MODULES
524 static unsigned int modnumber = 0;
525 static unsigned numfuncs = 0;
526 static const unsigned funcspermod = 500;
527 #endif
528
529         // find the function boundaries
530         unsigned nsymbols = allSymbols.size();
531         string modName = "";
532         for (unsigned u = 0; u < nsymbols; u++) {
533
534 #ifdef XXX_GENERATE_MODULES
535           if (!isDll && ++numfuncs % 500 == 0) {
536             modName = string("Mod") + string(++modnumber);
537             symbols_[modName] = Symbol(modName, "", Symbol::PDST_MODULE,
538                          Symbol::SL_GLOBAL, allSymbols[u].addr(), false);
539 }
540 #endif
541             unsigned v = u+1;
542             while (v < nsymbols 
543                    && allSymbols[v].addr() == allSymbols[u].addr())
544               v++;
545             unsigned size = 0;
546             if (v < nsymbols)
547               size = (unsigned)allSymbols[v].addr() 
548                      - (unsigned)allSymbols[u].addr();
549
550             if (allSymbols[u].name() != "")
551               symbols_[allSymbols[u].name()] =
552                 Symbol(allSymbols[u].name(), 
553                        isDll ? allSymbols[u].module(): modName, 
554                        allSymbols[u].type(), allSymbols[u].linkage(),
555                        allSymbols[u].addr(), allSymbols[u].kludge(),
556                        size);
557         }      
558
559       if (useDbgFile) {
560         UnmapViewOfFile(dbgAddr);
561         CloseHandle(dbgMapping);
562         CloseHandle(dbgFile);
563       }
564     }
565     /* catch */
566 cleanup: {
567       /*
568         if (did_open && (close(fd) == -1)) {
569             log_perror(err_func_, "close");
570         }
571         */
572     }
573
574 }
575
576
577 inline
578 Object::Object(const string file, void (*err_func)(const char *))
579     : AObject(file, err_func) {
580     load_object();
581 }
582
583 // for shared object files
584 inline
585 Object::Object(const string file,u_int,void (*err_func)(const char *))
586     : AObject(file, err_func) {
587    load_object();
588 }
589
590 inline
591 Object::Object(const Object& obj)
592     : AObject(obj) {
593     load_object();
594 }
595
596
597 inline
598 Object::~Object() {
599     if (baseAddr != NULL)
600         UnmapViewOfFile(baseAddr);
601     if (mapHandle != NULL)
602         CloseHandle(mapHandle);
603     if (fileHandle != INVALID_HANDLE_VALUE)
604         CloseHandle(fileHandle);
605 }
606
607 inline
608 Object&
609 Object::operator=(const Object& obj) {
610     (void) AObject::operator=(obj);
611     return *this;
612 }
613
614
615 #endif /* !defined(_Object_nt_h_) */