Removed warnings, changes for compiling with Visual C++ and xlc
[dyninst.git] / common / h / Object-elf32.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-elf32.h: ELF-32 object files.
44 ************************************************************************/
45
46
47 \f
48
49
50 #if !defined(_Object_elf32_h_)
51 #define _Object_elf32_h_
52
53
54 \f
55
56
57 /************************************************************************
58  * header files.
59 ************************************************************************/
60
61 #include <util/h/DictionaryLite.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 extern "C" {
68 #include <libelf.h>
69 #include <fcntl.h>
70 #include <stdlib.h>
71 #include <unistd.h>
72
73 #include <sys/types.h>
74 #include <sys/mman.h>
75 #include <sys/stat.h>
76 }
77
78 /***
79    The standard symbol table in an elf file is the .symtab section. This section does
80    not have information to find the module to which a global symbol belongs, so we must
81    also read the .stab section to get this info.
82 ***/
83
84 // Declarations for the .stab section.
85 // These are not declared in any system header files, so we must provide our own
86 // declarations. The declarations below were taken from:
87 //       SPARCWorks 3.0.x Debugger Interface, July 1994/
88
89 struct stab_entry { // an entry in the stab section
90   unsigned long name;  // stabstr table index for this symbol
91   unsigned char type; // type of this symbol
92   unsigned char other; 
93   unsigned short desc; 
94   unsigned long val; // value of this symbol -- usually zero. The real value must
95                      // be obtained from the symtab section
96 };
97
98 // Types 
99 #define N_UNDF  0x00 /* start of object file */
100 #define N_GSYM  0x20 /* global symbol */
101 #define N_FUN   0x24 /* function or procedure */
102 #define N_STSYM 0x26 /* initialized static symbol */
103 #define N_LCSYM 0x28 /* unitialized static symbol */
104 #define N_ROSYM 0x2c /* read-only static symbol */
105 #define N_ENDM  0x62 /* end module */
106 #define N_SO    0x64 /* source directory and file */
107 #define N_ENTRY 0xa4 /* fortran alternate subroutine entry point */
108
109 // Language code -- the desc field in a N_SO entry is a language code
110 #define N_SO_AS      1 /* assembler source */
111 #define N_SO_C       2 /* K & R C source */
112 #define N_SO_ANSI_C  3 /* ANSI C source */
113 #define N_SO_CC      4 /* C++ source */
114 #define N_SO_FORTRAN 5 /* fortran source */
115 #define N_SO_PASCAL  6 /* Pascal source */
116
117 // Symbol descriptors
118 // The format of a name is "<name>:<symbol descriptor><rest of name>
119 // The following are the descriptors of interest
120 #define SD_GLOBAL_FUN 'F' /* global function or procedure */
121 #define SD_PROTOTYPE 'P'  /* function prototypes */
122 #define SD_GLOBAL_VAR 'G' /* global variable */
123
124 // end of stab declarations
125
126 \f
127
128
129 /************************************************************************
130  * class Object
131 ************************************************************************/
132
133 class Object : public AObject {
134 public:
135              Object (const string, void (*)(const char *) = log_msg);
136              Object (const string, u_int baseAddr, 
137                      void (*)(const char *) = log_msg);
138              Object (const Object &);
139     virtual ~Object ();
140
141     const Object& operator= (const Object &);
142
143 private:
144     static
145     void    log_elferror (void (*)(const char *), const char *);
146
147     bool      loaded_elf (int, bool &, Elf* &, Elf32_Ehdr* &, Elf32_Phdr* &,
148                           unsigned &, unsigned &, Elf_Scn* &, Elf_Scn* &,
149                           Elf_Scn* &, Elf_Scn* &);
150     bool      loaded_elf_obj (int, bool &, Elf* &, Elf32_Ehdr* &,Elf32_Phdr* &,
151                               unsigned &, unsigned &, Elf_Scn* &, Elf_Scn*&);
152     void     load_object ();
153     void     load_shared_object ();
154 };
155
156 inline
157 Object::~Object() {
158 }
159
160 inline
161 const Object&
162 Object::operator=(const Object& obj) {
163     (void) AObject::operator=(obj);
164     return *this;
165 }
166
167 inline
168 void
169 Object::log_elferror(void (*pfunc)(const char *), const char* msg) {
170     const char* err = elf_errmsg(elf_errno());
171     log_printf(pfunc, "%s: %s\n", msg, err ? err : "(bad elf error)");
172 }
173
174 inline
175 bool
176 Object::loaded_elf(int fd, bool& did_elf, Elf*& elfp, Elf32_Ehdr*& ehdrp,
177     Elf32_Phdr*& phdrp, unsigned& txtaddr, unsigned& bssaddr,
178     Elf_Scn*& symscnp, Elf_Scn*& strscnp, Elf_Scn*& stabscnp, Elf_Scn*& stabstrscnp) {
179
180     elf_version(EV_CURRENT);
181     elf_errno();
182
183     if (((elfp = elf_begin(fd, ELF_C_READ, 0)) == 0)
184         || (elf_kind(elfp) != ELF_K_ELF)) {
185         log_elferror(err_func_, "opening file");
186         return false;
187     }
188     did_elf = true;
189
190     if (((ehdrp = elf32_getehdr(elfp)) == 0)
191         || (ehdrp->e_ident[EI_CLASS] != ELFCLASS32)
192         || (ehdrp->e_type != ET_EXEC)
193         || (ehdrp->e_phoff == 0)
194         || (ehdrp->e_shoff == 0)
195         || (ehdrp->e_phnum == 0)
196         || (ehdrp->e_shnum == 0)) {
197         log_elferror(err_func_, "loading eheader");
198         return false;
199     }
200
201 fprintf(stderr, "#### elf machine = %d\n", ehdrp->e_machine);
202
203     if ((phdrp = elf32_getphdr(elfp)) == 0) {
204         log_elferror(err_func_, "loading pheader");
205         return false;
206     }
207
208     Elf_Scn*    shstrscnp  = 0;
209     Elf32_Shdr* shstrshdrp = 0;
210     Elf_Data*   shstrdatap = 0;
211     if (((shstrscnp = elf_getscn(elfp, ehdrp->e_shstrndx)) == 0)
212         || ((shstrshdrp = elf32_getshdr(shstrscnp)) == 0)
213         || ((shstrdatap = elf_getdata(shstrscnp, 0)) == 0)) {
214         log_elferror(err_func_, "loading header section");
215         return false;
216     }
217
218     const char* shnames = (const char *) shstrdatap->d_buf;
219     Elf_Scn*    scnp    = 0;
220     while ((scnp = elf_nextscn(elfp, scnp)) != 0) {
221         Elf32_Shdr* shdrp = elf32_getshdr(scnp);
222         if (!shdrp) {
223             log_elferror(err_func_, "scanning sections");
224             return false;
225         }
226
227         const char* TEXT_NAME   = ".text";
228         const char* BSS_NAME    = ".bss";
229         const char* SYMTAB_NAME = ".symtab";
230         const char* STRTAB_NAME = ".strtab";
231         const char* STAB_NAME   = ".stab";
232         const char* STABSTR_NAME= ".stabstr";
233         const char* name        = (const char *) &shnames[shdrp->sh_name];
234
235         if (strcmp(name, TEXT_NAME) == 0) {
236             txtaddr = shdrp->sh_addr;
237         }
238         else if (strcmp(name, BSS_NAME) == 0) {
239             bssaddr = shdrp->sh_addr;
240         }
241         else if (strcmp(name, SYMTAB_NAME) == 0) {
242             symscnp = scnp;
243         }
244         else if (strcmp(name, STRTAB_NAME) == 0) {
245             strscnp = scnp;
246         }
247         else if (strcmp(name, STAB_NAME) == 0) {
248             stabscnp = scnp;
249         }
250         else if (strcmp(name, STABSTR_NAME) == 0) {
251             stabstrscnp = scnp;
252         }
253     }
254     if (!txtaddr || !bssaddr || !symscnp || !strscnp) {
255         log_elferror(err_func_, "no text/bss/symbol/string section");
256         return false;
257     }
258
259     return true;
260 }
261
262 inline
263 bool
264 Object::loaded_elf_obj(int fd, bool& did_elf, Elf*& elfp, Elf32_Ehdr*& ehdrp,
265     Elf32_Phdr*& phdrp, unsigned& txtaddr, unsigned& bssaddr,
266     Elf_Scn*& symscnp, Elf_Scn*& strscnp) {
267
268     elf_version(EV_CURRENT);
269     elf_errno();
270
271     if (((elfp = elf_begin(fd, ELF_C_READ, 0)) == 0)
272         || (elf_kind(elfp) != ELF_K_ELF)) {
273         log_elferror(err_func_, "opening file");
274         return false;
275     }
276     did_elf = true;
277
278     if (((ehdrp = elf32_getehdr(elfp)) == 0)
279         || (ehdrp->e_ident[EI_CLASS] != ELFCLASS32)
280         || (ehdrp->e_type != ET_DYN)
281         || (ehdrp->e_phoff == 0)
282         || (ehdrp->e_shoff == 0)
283         || (ehdrp->e_phnum == 0)
284         || (ehdrp->e_shnum == 0)) {
285         log_elferror(err_func_, "loading eheader");
286         return false;
287     }
288
289     if ((phdrp = elf32_getphdr(elfp)) == 0) {
290         log_elferror(err_func_, "loading pheader");
291         return false;
292     }
293
294     Elf_Scn*    shstrscnp  = 0;
295     Elf32_Shdr* shstrshdrp = 0;
296     Elf_Data*   shstrdatap = 0;
297     if (((shstrscnp = elf_getscn(elfp, ehdrp->e_shstrndx)) == 0)
298         || ((shstrshdrp = elf32_getshdr(shstrscnp)) == 0)
299         || ((shstrdatap = elf_getdata(shstrscnp, 0)) == 0)) {
300         log_elferror(err_func_, "loading header section");
301         return false;
302     }
303
304     const char* shnames = (const char *) shstrdatap->d_buf;
305     Elf_Scn*    scnp    = 0;
306     while ((scnp = elf_nextscn(elfp, scnp)) != 0) {
307         Elf32_Shdr* shdrp = elf32_getshdr(scnp);
308         if (!shdrp) {
309             log_elferror(err_func_, "scanning sections");
310             return false;
311         }
312
313         const char* TEXT_NAME   = ".text";
314         const char* BSS_NAME    = ".bss";
315         const char* SYMTAB_NAME = ".symtab";
316         const char* STRTAB_NAME = ".strtab";
317         const char* name        = (const char *) &shnames[shdrp->sh_name];
318
319         if (strcmp(name, TEXT_NAME) == 0) {
320             txtaddr = shdrp->sh_addr;
321         }
322         else if (strcmp(name, BSS_NAME) == 0) {
323             bssaddr = shdrp->sh_addr;
324         }
325         else if (strcmp(name, SYMTAB_NAME) == 0) {
326             symscnp = scnp;
327         }
328         else if (strcmp(name, STRTAB_NAME) == 0) {
329             strscnp = scnp;
330         }
331     }
332     string temp = string(" text: ");
333     temp += string((u_int)txtaddr);
334     temp += string(" bss: ");
335     temp += string((u_int)bssaddr);
336     temp += string(" symtab: ");
337     temp += string((u_int)symscnp);
338     temp += string(" strtab: ");
339     temp += string((u_int)strscnp);
340     temp += string(" ehdrp: ");
341     temp += string((u_int)ehdrp);
342     temp += string(" phdrp: ");
343     temp += string((u_int)phdrp);
344     temp += string("\n");
345     // log_elferror(err_func_, P_strdup(temp.string_of()));
346
347     if (!txtaddr || !bssaddr || !symscnp || !strscnp) {
348         log_elferror(err_func_, "no text/bss/symbol/string section");
349         return false;
350     }
351
352     return true;
353 }
354
355
356 static int symbol_compare(const void *x, const void *y) {
357     const Symbol *s1 = (const Symbol *)x;
358     const Symbol *s2 = (const Symbol *)y;
359     return (s1->addr() - s2->addr());
360 }
361
362
363 inline
364 void
365 Object::load_object() {
366     const char* file = file_.string_of();
367     struct stat st;
368     int         fd   = -1;
369     char*       ptr  = 0;
370     Elf*        elfp = 0;
371
372     bool        did_open = false;
373     bool        did_elf  = false;
374
375     /* try */ {
376         if (((fd = open(file, O_RDONLY)) == -1) || (fstat(fd, &st) == -1)) {
377             log_perror(err_func_, file);
378             /* throw exception */ goto cleanup;
379         }
380         did_open = true;
381
382         if ((ptr = (char *) mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
383             == (char *) -1) {
384             log_perror(err_func_, "mmap");
385             /* throw exception */ goto cleanup;
386         }
387
388         Elf32_Ehdr* ehdrp   = 0;
389         Elf32_Phdr* phdrp   = 0;
390         Elf_Scn*    symscnp = 0;
391         Elf_Scn*    strscnp = 0;
392         Elf_Scn*    stabscnp = 0;
393         Elf_Scn*    stabstrscnp = 0;
394         unsigned    txtaddr = 0;
395         unsigned    bssaddr = 0;
396
397         if (!loaded_elf(fd, did_elf, elfp, ehdrp, phdrp, txtaddr,
398                 bssaddr, symscnp, strscnp, stabscnp, stabstrscnp)) {
399                 /* throw exception */ goto cleanup;
400         }
401
402         for (unsigned i0 = 0; i0 < ehdrp->e_phnum; i0++) {
403             if ((phdrp[i0].p_vaddr <= txtaddr)
404                 && ((phdrp[i0].p_vaddr+phdrp[i0].p_memsz) >= txtaddr)) {
405                 code_ptr_ = (Word *) ((void*)&ptr[phdrp[i0].p_offset]);
406                 code_off_ = (Address) phdrp[i0].p_vaddr;
407                 code_len_ = (unsigned) phdrp[i0].p_memsz / sizeof(Word);
408             }
409             else if ((phdrp[i0].p_vaddr <= bssaddr)
410                 && ((phdrp[i0].p_vaddr+phdrp[i0].p_memsz) >= bssaddr)) {
411                 data_ptr_ = (Word *) ((void *) &ptr[phdrp[i0].p_offset]);
412                 data_off_ = (Address) phdrp[i0].p_vaddr;
413                 data_len_ = (unsigned) phdrp[i0].p_memsz / sizeof(Word);
414             }
415         }
416         if (!code_ptr_ || !code_off_ || !code_len_) {
417             log_printf(err_func_, "cannot locate instructions\n");
418             /* throw exception */ goto cleanup;
419         }
420         if (!data_ptr_ || !data_off_ || !data_len_) {
421             log_printf(err_func_, "cannot locate data segment\n");
422             /* throw exception */ goto cleanup;
423         }
424
425         Elf_Data* symdatap = elf_getdata(symscnp, 0);
426         Elf_Data* strdatap = elf_getdata(strscnp, 0);
427         if (!symdatap || !strdatap) {
428             log_elferror(err_func_, "locating symbol/string data");
429             /* throw exception */ goto cleanup;
430         }
431
432         Elf32_Sym*  syms   = (Elf32_Sym *) symdatap->d_buf;
433         unsigned    nsyms  = symdatap->d_size / sizeof(Elf32_Sym);
434         const char* strs   = (const char *) strdatap->d_buf;
435         string      module = "DEFAULT_MODULE";
436         string      name   = "DEFAULT_NAME";
437
438         // global symbols are put in global_symbols. Later we read the
439         // stab section to find the module to where they belong.
440         dictionary_hash<string, Symbol> global_symbols(string::hash);
441
442         vector<Symbol> allsymbols;
443
444         for (unsigned i1 = 0; i1 < nsyms; i1++) {
445           // First, we must check st_shndx. 
446           // if st_shndx == SHN_UNDEF, this is an undefined symbol,
447           // probably defined in a shared object that will be dynamically
448           // linked with the executable. We just ignore it for now.
449           if (syms[i1].st_shndx != SHN_UNDEF) {
450             bool st_kludge = false;
451             Symbol::SymbolType type = Symbol::PDST_UNKNOWN;
452             switch (ELF32_ST_TYPE(syms[i1].st_info)) {
453             case STT_FILE:
454                 module = string(&strs[syms[i1].st_name]);
455                 type   = Symbol::PDST_MODULE;
456                 break;
457
458             case STT_OBJECT:
459                 type = Symbol::PDST_OBJECT;
460                 break;
461
462             case STT_FUNC:
463                 type = Symbol::PDST_FUNCTION;
464                 break;
465
466             default:
467                 continue;
468             }
469
470             name = string(&strs[syms[i1].st_name]);
471
472             if (ELF32_ST_BIND(syms[i1].st_info) == STB_LOCAL) {
473                allsymbols += Symbol(name, module, type, Symbol::SL_LOCAL,
474                                     syms[i1].st_value, st_kludge, 
475                                     syms[i1].st_size);
476             }
477             else {
478                allsymbols += Symbol(name, string(""), type, Symbol::SL_GLOBAL,
479                                     syms[i1].st_value, st_kludge,
480                                     syms[i1].st_size);
481             }
482           }
483         }
484
485         // some functions may have size zero in the symbol table,
486         // we need to find the correct size
487         allsymbols.sort(symbol_compare);
488         unsigned nsymbols = allsymbols.size();
489         for (unsigned u = 0; u < nsymbols; u++) {
490           if (allsymbols[u].type() == Symbol::PDST_FUNCTION
491               && allsymbols[u].size() == 0) {
492             unsigned v = u+1;
493             while (v < nsymbols && allsymbols[v].addr() == allsymbols[u].addr())
494               v++;
495             if (v < nsymbols) {
496               allsymbols[u].change_size((unsigned)allsymbols[v].addr()
497                                         - (unsigned)allsymbols[u].addr());
498             }
499           }
500
501           // We are done with the local symbols. We save the global so that
502           // we can get their module from the .stab section.
503           if (allsymbols[u].linkage() == Symbol::SL_LOCAL)
504             symbols_[allsymbols[u].name()] = allsymbols[u];
505           else {
506             // globals should be unique
507             assert(!(global_symbols.defines(allsymbols[u].name()))); 
508             global_symbols[allsymbols[u].name()] = allsymbols[u];
509           }
510         }      
511         
512
513         // Read the stab section to find the module of global symbols.
514         // The symbols appear in the stab section by module. A module begins
515         // with a symbol of type N_UNDF and ends with a symbol of type N_ENDM.
516         // All the symbols in between those two symbols belong to the module.
517
518         Elf_Data* stabdatap = elf_getdata(stabscnp, 0);
519         Elf_Data* stabstrdatap = elf_getdata(stabstrscnp, 0);
520         struct stab_entry *stabsyms = 0;
521         unsigned stab_nsyms;
522         const char *stabstrs = 0;
523
524         if (stabdatap && stabstrdatap) {
525           stabsyms = (struct stab_entry *) stabdatap->d_buf;
526           stab_nsyms = stabdatap->d_size / sizeof(struct stab_entry);
527           stabstrs = (const char *) stabstrdatap->d_buf;
528         }
529         else 
530           stab_nsyms = 0;
531
532         // the stabstr contains one string table for each module.
533         // stabstr_offset gives the offset from the begining of stabstr of the
534         // string table for the current module.
535         // stabstr_nextoffset gives the offset for the next module.
536         unsigned stabstr_offset = 0;
537         unsigned stabstr_nextoffset = 0;
538
539         bool is_fortran = false;  // is the current module fortran code?
540            /* we must know if we are reading a fortran module because fortran
541               symbol names are different in the .stab and .symtab sections.
542               A symbol that appears as 'foo' in the .stab section, appears
543               as 'foo_' in .symtab.
544            */
545         module = "";
546   
547         for (unsigned i = 0; i < stab_nsyms; i++) {
548           switch(stabsyms[i].type) {
549           case N_UNDF: /* start of object file */
550             assert(stabsyms[i].name == 1);
551             stabstr_offset = stabstr_nextoffset;
552             // stabsyms[i].val has the size of the string table of this module.
553             // We use this value to compute the offset of the next string table.
554             stabstr_nextoffset = stabstr_offset + stabsyms[i].val;
555             module = string(&stabstrs[stabstr_offset+stabsyms[i].name]);
556             break;
557
558           case N_ENDM: /* end of object file */
559             is_fortran = false;
560             module = "";
561             break;
562
563           case N_SO: /* compilation source or file name */
564             if (stabsyms[i].desc == N_SO_FORTRAN)
565               is_fortran = true;
566             break;
567
568           case N_ENTRY: /* fortran alternate subroutine entry point */
569           case N_FUN: /* function */
570           case N_GSYM: /* global symbol */
571             // the name string of a function or object appears in the stab string table
572             // as <symbol name>:<symbol descriptor><other stuff>
573             // where <symbol descriptor> is a one char code.
574             // we must extract the name and descriptor from the string
575           {
576             const char *p = &stabstrs[stabstr_offset+stabsyms[i].name];
577             const char *q = strchr(p,':');
578             assert(q);
579             unsigned len = q - p;
580             assert(len > 0);
581             char *sname = new char[len+1];
582             strncpy(sname, p, len);
583             sname[len] = 0;
584             
585             // q points to the ':' in the name string, so 
586             // q[1] is the symbol descriptor. We must check the symbol descriptor
587             // here to skip things we are not interested in, such as local functions
588             // and prototypes.
589             if (q[1] == SD_GLOBAL_FUN || q[1] == SD_GLOBAL_VAR || stabsyms[i].type==N_ENTRY) { 
590               string SymName = string(sname);
591               bool res = global_symbols.defines(SymName);
592               if (!res && is_fortran) {
593                 // Fortran symbols usually appear with an '_' appended in .symtab,
594                 // but not on .stab
595                 SymName += "_";
596                 res = global_symbols.defines(SymName);
597               }
598               assert(res); // All globals in .stab should be defined in .symtab
599               Symbol sym = global_symbols[SymName];
600               symbols_[SymName] = Symbol(sym.name(), module, sym.type(), sym.linkage(), 
601                                   sym.addr(), sym.kludge(), sym.size());
602             }
603           }
604             break;
605
606           default:
607             /* ignore other entries */
608             break;
609           }
610         }
611
612         /* The remaing symbols go without module */
613         vector<string> k = global_symbols.keys();
614         for (unsigned i2 = 0; i2 < k.size(); i2++) {
615           Symbol sym = global_symbols[k[i2]];
616           if (!(symbols_.defines(sym.name())))
617              symbols_[sym.name()] = sym;
618         }
619     }  /* try */
620
621     /* catch */
622 cleanup: {
623         if (did_elf && (elf_end(elfp) != 0)) {
624             log_elferror(err_func_, "closing file");
625         }
626         if (did_open && (close(fd) == -1)) {
627             log_perror(err_func_, "close");
628         }
629     }
630 }
631
632
633 inline
634 void
635 Object::load_shared_object() {
636     const char* file = file_.string_of();
637     struct stat st;
638     int         fd   = -1;
639     char*       ptr  = 0;
640     Elf*        elfp = 0;
641
642     bool        did_open = false;
643     bool        did_elf  = false;
644
645     /* try */ {
646         if (((fd = open(file, O_RDONLY)) == -1) || (fstat(fd, &st) == -1)) {
647             log_perror(err_func_, file);
648             /* throw exception */ goto cleanup2;
649         }
650         did_open = true;
651
652         if ((ptr = (char *) mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
653             == (char *) -1) {
654             log_perror(err_func_, "mmap");
655             /* throw exception */ goto cleanup2;
656         }
657
658         Elf32_Ehdr* ehdrp   = 0;  /* ELF header */
659         Elf32_Phdr* phdrp   = 0;  /* program header */
660         Elf_Scn*    symscnp = 0;
661         Elf_Scn*    strscnp = 0;
662         unsigned    txtaddr = 0;
663         unsigned    bssaddr = 0;
664
665         if (!loaded_elf_obj(fd, did_elf, elfp, ehdrp, phdrp, txtaddr,
666                             bssaddr, symscnp, strscnp)) {
667                 /* throw exception */ goto cleanup2;
668         }
669
670         for (unsigned i0 = 0; i0 < ehdrp->e_phnum; i0++) {
671             if ((phdrp[i0].p_vaddr <= txtaddr)
672                 && ((phdrp[i0].p_vaddr+phdrp[i0].p_memsz) >= txtaddr)) {
673                 code_ptr_ = (Word *) ((void*)&ptr[phdrp[i0].p_offset]);
674                 code_off_ = (Address) phdrp[i0].p_vaddr;
675                 code_len_ = (unsigned) phdrp[i0].p_memsz / sizeof(Word);
676             }
677             else if ((phdrp[i0].p_vaddr <= bssaddr)
678                 && ((phdrp[i0].p_vaddr+phdrp[i0].p_memsz) >= bssaddr)) {
679                 data_ptr_ = (Word *) ((void *) &ptr[phdrp[i0].p_offset]);
680                 data_off_ = (Address) phdrp[i0].p_vaddr;
681                 data_len_ = (unsigned) phdrp[i0].p_memsz / sizeof(Word);
682             }
683         }
684
685         Elf_Data* symdatap = elf_getdata(symscnp, 0);
686         Elf_Data* strdatap = elf_getdata(strscnp, 0);
687         if (!symdatap || !strdatap) {
688             log_elferror(err_func_, "locating symbol/string data");
689             /* throw exception */ goto cleanup2;
690         }
691
692         Elf32_Sym*  syms   = (Elf32_Sym *) symdatap->d_buf;
693         unsigned    nsyms  = symdatap->d_size / sizeof(Elf32_Sym);
694         const char* strs   = (const char *) strdatap->d_buf;
695         string      module = "DEFAULT_MODULE";
696         string      name   = "DEFAULT_NAME";
697
698         // for shared objects add a module that is the file name
699         // and add all the global symbols as functions 
700         const char *libname = file_.string_of();
701         // find short name
702         const char *last = 0;
703         for(u_int i=0; i < file_.length();i++) {
704             if(libname[i] == '/'){
705                 last = (const char *)(&(libname[i]));
706                 // log_elferror(err_func_, P_strdup(last));
707             }
708         }
709         if(last){
710             module = (const char *)(last +1);  
711         }
712         else{
713             module = string("DEFAULT_MODULE");  
714         }
715         // string blah = string("module name: ");
716         // blah += module.string_of();
717         // blah += ("\n");
718         // log_elferror(err_func_, P_strdup(blah.string_of()));
719
720         vector<Symbol> allsymbols;
721         bool found = false;
722         for (unsigned i1 = 0; i1 < nsyms; i1++) {
723           // First, we must check st_shndx. 
724           // if st_shndx == SHN_UNDEF, this is an undefined symbol,
725           // probably defined in a shared object that will be dynamically
726           // linked with the executable. We just ignore it for now.
727           if (syms[i1].st_shndx != SHN_UNDEF) {
728             bool st_kludge = false;
729             Symbol::SymbolType type = Symbol::PDST_UNKNOWN;
730             switch (ELF32_ST_TYPE(syms[i1].st_info)) {
731             case STT_FILE: {
732                 string temp2 = string(&strs[syms[i1].st_name]);
733                 if(temp2 == module){
734                     module = string(&strs[syms[i1].st_name]);
735                     type   = Symbol::PDST_MODULE;
736                     found = true;
737                 }
738                 break;
739                 }
740
741             case STT_OBJECT:
742                 type = Symbol::PDST_OBJECT;
743                 break;
744
745             case STT_FUNC:
746                 type = Symbol::PDST_FUNCTION;
747                 break;
748
749             case STT_NOTYPE:
750                 type = Symbol::PDST_NOTYPE;
751                 break;
752
753             default:
754                 continue;
755             }
756
757             name = string(&strs[syms[i1].st_name]);
758
759             // only add symbols of type STB_LOCAL and  FILE if they are 
760             // the shared object name
761             if ((ELF32_ST_BIND(syms[i1].st_info) == STB_LOCAL) && (found)){
762                    symbols_[name] = Symbol(name, module, type, Symbol::SL_LOCAL,
763                                     syms[i1].st_value, st_kludge, 
764                                     syms[i1].st_size);
765                    found = false;
766             }
767             else if((ELF32_ST_BIND(syms[i1].st_info) == STB_LOCAL)
768                         && (ELF32_ST_TYPE(syms[i1].st_info) != STT_FUNC)) {
769                 allsymbols += Symbol(name, module, type, Symbol::SL_LOCAL,
770                                                 syms[i1].st_value, st_kludge,
771                                                 syms[i1].st_size);
772             }
773             else {
774                if(ELF32_ST_BIND(syms[i1].st_info) == STB_WEAK){
775                    allsymbols += Symbol(name, module, 
776                                         type, Symbol::SL_WEAK,
777                                         syms[i1].st_value, st_kludge,
778                                         syms[i1].st_size);
779                }
780                else{
781                    allsymbols += Symbol(name, module, 
782                                         type, Symbol::SL_GLOBAL,
783                                         syms[i1].st_value, st_kludge,
784                                         syms[i1].st_size);
785                }
786             }
787           }
788         }
789
790
791         // Sort all the symbols, and fix the sizes
792         allsymbols.sort(symbol_compare);
793
794         // if the symbol is type PDST_FUNCTION and the next symbol is 
795         // type PDST_FUNCTION size needs to be changed...this occurs when
796         // one function's binding is WEAK and the other is GLOBAL, or when
797         // two functions overlap 
798         for(u_int i=0; i < (allsymbols.size() -1); i++){
799             u_int new_size = 0;
800             bool  change_size = false;
801
802             // some functions may have size zero in the symbol table
803             // we have to fix the size of the global functions
804             if (allsymbols[i].type() == Symbol::PDST_FUNCTION
805                 && allsymbols[i].linkage() == Symbol::SL_GLOBAL
806                 && allsymbols[i].size() == 0) {
807                unsigned j = i+1;
808                while (j < allsymbols.size() 
809                       && allsymbols[j].addr() == allsymbols[i].addr())
810                  j++;
811                allsymbols[i].change_size(allsymbols[j].addr()-allsymbols[i].addr());
812             }
813
814             if((allsymbols[i].type() == Symbol::PDST_FUNCTION)
815                 && (allsymbols[i+1].type() == Symbol::PDST_FUNCTION)){
816                 u_int next_start=allsymbols[i].addr()+allsymbols[i].size();
817
818                 // if the symbols have the same address and one is weak
819                 // and the other is global keeep the global one
820                 if((allsymbols[i].addr() == allsymbols[i+1].addr()) && 
821                     (((allsymbols[i].linkage() == Symbol::SL_WEAK) &&
822                       (allsymbols[i+1].linkage() == Symbol::SL_GLOBAL)) || 
823                      ((allsymbols[i].linkage() == Symbol::SL_GLOBAL) &&
824                       (allsymbols[i+1].linkage() == Symbol::SL_WEAK)))) {
825
826                       if(allsymbols[i].linkage() == Symbol::SL_WEAK){
827                           allsymbols[i].change_size(0);
828                       } else {
829                           allsymbols[i+1].change_size(0);
830                       }
831                 }
832                 else if(next_start > allsymbols[i+1].addr()){
833                         new_size =  allsymbols[i+1].addr()-allsymbols[i].addr();
834                         change_size = true;
835                 }
836             }
837
838             if((allsymbols[i].type() == Symbol::PDST_FUNCTION) && change_size){
839                 symbols_[allsymbols[i].name()] =
840                     Symbol(allsymbols[i].name(), allsymbols[i].module(),
841                     allsymbols[i].type(), allsymbols[i].linkage(),
842                     allsymbols[i].addr(), allsymbols[i].kludge(),
843                     new_size);
844             }
845             else {
846                 symbols_[allsymbols[i].name()] =
847                     Symbol(allsymbols[i].name(), allsymbols[i].module(),
848                     allsymbols[i].type(), allsymbols[i].linkage(),
849                     allsymbols[i].addr(), allsymbols[i].kludge(),
850                     allsymbols[i].size());
851             }
852         }
853         // add last symbol
854         u_int last_sym = allsymbols.size()-1;
855         symbols_[allsymbols[last_sym].name()] =
856             Symbol(allsymbols[last_sym].name(), allsymbols[last_sym].module(),
857             allsymbols[last_sym].type(), allsymbols[last_sym].linkage(),
858             allsymbols[last_sym].addr(), allsymbols[last_sym].kludge(),
859             allsymbols[last_sym].size());
860
861     }  /* try */
862
863     /* catch */
864
865 cleanup2: {
866         if (did_elf && (elf_end(elfp) != 0)) {
867             log_elferror(err_func_, "closing file");
868         }
869         if (did_open && (close(fd) == -1)) {
870             log_perror(err_func_, "close");
871         }
872     }
873 }
874
875
876 inline
877 Object::Object(const string file, void (*err_func)(const char *))
878     : AObject(file, err_func) {
879     load_object();
880 }
881
882 inline
883 Object::Object(const string file, u_int ,void (*err_func)(const char *))
884     : AObject(file, err_func) {
885     load_shared_object();
886 }
887
888 inline
889 Object::Object(const Object& obj)
890     : AObject(obj) {
891     load_object();
892 }
893
894
895 \f
896
897
898 #endif /* !defined(_Object_elf32_h_) */