Updates for StackwalkerAPI
[dyninst.git] / symtabAPI / src / Object-elf.h
1 /*
2  * Copyright (c) 1996-2007 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  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
30  */
31
32 /************************************************************************
33  * $Id: Object-elf.h,v 1.21 2008/06/23 18:45:42 legendre Exp $
34  * Object-elf.h: Object class for ELF file format
35 ************************************************************************/
36
37
38 #if !defined(_Object_elf_h_)
39 #define _Object_elf_h_
40
41 #if defined(USES_DWARF_DEBUG)
42 #include "dwarf.h"
43 #include "libdwarf.h"
44 #endif
45
46
47 #include "common/h/MappedFile.h"
48 #include "symtabAPI/h/Symbol.h"
49 #include "symtabAPI/h/Symtab.h"
50 #include "common/h/headers.h"
51 #include "common/h/Types.h"
52 #include <elf.h>
53 #include <libelf.h>
54
55 #include "Elf_X.h"
56
57 #include <fcntl.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60
61 #include <sys/types.h>
62 #include <sys/mman.h>
63 #include <sys/stat.h>
64
65
66 namespace Dyninst{
67 namespace SymtabAPI{
68 /*
69  * The standard symbol table in an elf file is the .symtab section. This section does
70  * not have information to find the module to which a global symbol belongs, so we must
71  * also read the .stab section to get this info.
72  */
73
74 // Declarations for the .stab section.
75 // These are not declared in any system header files, so we must provide our own
76 // declarations. The declarations below were taken from:
77 //       SPARCWorks 3.0.x Debugger Interface, July 1994
78 // 
79 struct stab32 {
80     unsigned int name;  // stabstr table index for this symbol
81     unsigned char type; // type of this symbol
82     unsigned char other;
83     unsigned short desc;
84     unsigned int val;   // value of this symbol -- usually zero. The real value must
85                         // be obtained from the symtab section
86 };
87 struct stab64 {
88     // XXX ELF stabs are currently not implementing actual 64-bit support
89     //     on AMD-64, for which this separation was introduced. Until we
90     //     start seeing stab records with fields of the appropriate length,
91     //     we should assume the smaller records.
92     //unsigned long name; // stabstr table index for this symbol
93     unsigned int name; // stabstr table index for this symbol
94     unsigned char type; // type of this symbol
95     unsigned char other;
96     unsigned short desc;
97     //unsigned long val;
98     unsigned int val;  // value of this symbol -- usually zero. The real value must
99                         // be obtained from the symtab section
100 };
101
102 // 
103 // Extended to a class for 32/64-bit stab entries at runtime. - Ray
104 // 
105 class stab_entry {
106   public:
107     stab_entry(void *_stabptr = 0, const char *_stabstr = 0, long _nsyms = 0)
108         : stabptr(_stabptr), stabstr(_stabstr), nsyms(_nsyms) { }
109     virtual ~stab_entry() {};
110
111     virtual const char *name(int i) = 0;
112     virtual unsigned long nameIdx(int i) = 0;
113     virtual unsigned char type(int i) = 0;
114     virtual unsigned char other(int i) = 0;
115     virtual unsigned short desc(int i) = 0;
116     virtual unsigned long val(int i) = 0;
117
118     unsigned long count() { return nsyms; }
119     void setStringBase(const char *ptr) { stabstr = const_cast<char *>(ptr); }
120     const char *getStringBase() { return stabstr; }
121
122   protected:
123     void *stabptr;
124     const char *stabstr;
125     long nsyms;
126 };
127
128 class stab_entry_32 : public stab_entry {
129   public:
130     stab_entry_32(void *_stabptr = 0, const char *_stabstr = 0, long _nsyms = 0)
131         : stab_entry(_stabptr, _stabstr, _nsyms) { }
132     virtual ~stab_entry_32() {};
133
134     const char *name(int i = 0) { 
135        if (!stabptr) {
136           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
137                 FILE__, __LINE__);
138           return "bad_name";
139        }
140        return stabstr + ((stab32 *)stabptr)[i].name; 
141     }
142     unsigned long nameIdx(int i = 0) {
143        if (!stabptr) {
144           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
145                 FILE__, __LINE__);
146           return 0L;
147        }
148        return ((stab32 *)stabptr)[i].name; 
149     }
150     unsigned char type(int i = 0) {
151        if (!stabptr) {
152           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
153                 FILE__, __LINE__);
154           return 0;
155        }
156        return ((stab32 *)stabptr)[i].type; 
157     }
158     unsigned char other(int i = 0) {
159        if (!stabptr) {
160           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
161                 FILE__, __LINE__);
162           return 0;
163        }
164        return ((stab32 *)stabptr)[i].other; 
165     }
166     unsigned short desc(int i = 0) { 
167        if (!stabptr) {
168           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
169                 FILE__, __LINE__);
170           return 0;
171        }
172        return ((stab32 *)stabptr)[i].desc; 
173     }
174     unsigned long val(int i = 0) { 
175        if (!stabptr) {
176           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
177                 FILE__, __LINE__);
178           return 0L;
179        }
180        return ((stab32 *)stabptr)[i].val; 
181     }
182 };
183
184 class stab_entry_64 : public stab_entry {
185   public:
186     stab_entry_64(void *_stabptr = 0, const char *_stabstr = 0, long _nsyms = 0)
187         : stab_entry(_stabptr, _stabstr, _nsyms) { }
188     virtual ~stab_entry_64() {};
189
190     const char *name(int i = 0) { 
191        if (!stabptr) {
192           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
193                 FILE__, __LINE__);
194           return "bad_name";
195        }
196        return stabstr + ((stab64 *)stabptr)[i].name; 
197     }
198     unsigned long nameIdx(int i = 0) {
199        if (!stabptr) {
200           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
201                 FILE__, __LINE__);
202           return 0L;
203        }
204        return ((stab64 *)stabptr)[i].name; 
205     }
206     unsigned char type(int i = 0) {
207        if (!stabptr) {
208           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
209                 FILE__, __LINE__);
210           return 0;
211        }
212        return ((stab64 *)stabptr)[i].type; 
213     }
214     unsigned char other(int i = 0) { 
215        if (!stabptr) {
216           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
217                 FILE__, __LINE__);
218           return 0;
219        }
220        return ((stab64 *)stabptr)[i].other; 
221     }
222     unsigned short desc(int i = 0) { 
223        if (!stabptr) {
224           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
225                 FILE__, __LINE__);
226           return 0;
227        }
228        return ((stab64 *)stabptr)[i].desc; 
229     }
230     unsigned long val(int i = 0) { 
231        if (!stabptr) {
232           fprintf(stderr, "%s[%d]:  warning, accessing uninitialized stab_entry\n",
233                 FILE__, __LINE__);
234           return 0L;
235        }
236        return ((stab64 *)stabptr)[i].val; 
237     }
238 };
239
240 // Types 
241 #define N_UNDF  0x00 /* start of object file */
242 #define N_GSYM  0x20 /* global symbol */
243 #define N_FUN   0x24 /* function or procedure */
244 #define N_STSYM 0x26 /* initialized static symbol */
245 #define N_LCSYM 0x28 /* unitialized static symbol */
246 #define N_ROSYM 0x2c /* read-only static symbol */
247 #define N_OPT   0x3c /* compiler options */
248 #define N_ENDM  0x62 /* end module */
249 #define N_SO    0x64 /* source directory and file */
250 #define N_ENTRY 0xa4 /* fortran alternate subroutine entry point */
251 #define N_BCOMM 0xe2 /* start fortran named common block */
252 #define N_ECOMM 0xe4 /* start fortran named common block */
253
254 // Language code -- the desc field in a N_SO entry is a language code
255 #define N_SO_AS      1 /* assembler source */
256 #define N_SO_C       2 /* K & R C source */
257 #define N_SO_ANSI_C  3 /* ANSI C source */
258 #define N_SO_CC      4 /* C++ source */
259 #define N_SO_FORTRAN 5 /* fortran source */
260 #define N_SO_PASCAL  6 /* Pascal source */
261 #define N_SO_F90     7 /* Fortran90 source */
262
263 //line information data
264 #define N_SLINE  0x44 /* line number in text segment */
265 #define N_SOL    0x84 /* name of the include file*/
266
267 // Symbol descriptors
268 // The format of a name is "<name>:<symbol descriptor><rest of name>
269 // The following are the descriptors of interest
270 #define SD_GLOBAL_FUN 'F' /* global function or procedure */
271 #define SD_PROTOTYPE  'P'  /* function prototypes */
272 #define SD_GLOBAL_VAR 'G' /* global variable */
273
274 // end of stab declarations
275
276 class pdElfShdr;
277
278 class Symtab;
279 class Region;
280 class Object;
281
282 typedef struct {
283   Dwarf_Fde *fde_data;
284   Dwarf_Signed fde_count;
285   Dwarf_Cie *cie_data;
286   Dwarf_Signed cie_count;   
287 } fde_cie_data;
288
289 class DwarfHandle {
290    friend class Object;
291  private:
292    typedef enum {
293       dwarf_status_uninitialized,
294       dwarf_status_error,
295       dwarf_status_ok
296    } dwarf_status_t;
297    dwarf_status_t fde_dwarf_status;
298    dwarf_status_t init_dwarf_status;
299
300    std::vector<fde_cie_data> fde_data;
301    Dwarf_Debug dbg_data;
302    Object *obj;
303
304  public:
305   DwarfHandle(Object *obj_);
306   ~DwarfHandle();
307
308
309   Dwarf_Debug *dbg();
310   void setupFdeData();
311 };
312
313 class Object : public AObject {
314   friend class DwarfHandle;   
315  public:
316   Object() : dwarf(this) {}
317   Object(MappedFile *, MappedFile *, void (*)(const char *) = log_msg, bool alloc_syms = true);
318   Object(MappedFile *, MappedFile *, dyn_hash_map<std::string, LineInformation> &, std::vector<Region *> &, void (*)(const char *) = log_msg);
319   Object(MappedFile *, MappedFile *, std::string &member_name, Offset offset,   
320           void (*)(const char *) = log_msg, void *base = NULL, bool alloc_syms = true);
321   Object(const Object &);
322   virtual ~Object();
323   const Object& operator=(const Object &);
324
325   bool emitDriver(Symtab *obj, std::string fName, std::vector<Symbol *>&allSymbols, unsigned flag);  
326   
327   const char *elf_vaddr_to_ptr(Offset vaddr) const;
328   bool hasStabInfo() const { return ! ( !stab_off_ || !stab_size_ || !stabstr_off_ ); }
329   bool hasDwarfInfo() const { return dwarvenDebugInfo; }
330   stab_entry * get_stab_info() const;
331   const char * getFileName() const { return mf->filename().c_str(); }
332   void getModuleLanguageInfo(dyn_hash_map<std::string, supportedLanguages> *mod_langs);
333   void parseFileLineInfo(Symtab *obj, dyn_hash_map<std::string, LineInformation> &li);
334   void parseTypeInfo(Symtab *obj);
335
336   bool needs_function_binding() const { return (plt_addr_ > 0); } 
337   bool get_func_binding_table(std::vector<relocationEntry> &fbt) const;
338   bool get_func_binding_table_ptr(const std::vector<relocationEntry> *&fbt) const;
339   void getDependencies(std::vector<std::string> &deps);
340
341   bool addRelocationEntry(relocationEntry &re);
342
343   //getLoadAddress may return 0 on shared objects
344   Offset getLoadAddress() const { return loadAddress_; }
345
346   Offset getEntryAddress() const { return entryAddress_; }
347   // To be changed later - Giri
348   Offset getBaseAddress() const { return 0; }
349   static bool truncateLineFilenames;
350  
351   virtual char *mem_image() const 
352   {
353      assert(mf);
354      return (char *)mf->base_addr();
355   }
356
357   SYMTAB_EXPORT ObjectType objType() const;
358   const char *interpreter_name() const;
359
360
361 //TODO Later - change this #ifdef later.. make getTOCoffset available for all platforms  
362
363 #if defined(arch_ia64)
364   Offset getTOCoffset() const { return gp; }
365 #elif defined(os_linux) && defined(arch_power) && defined(arch_64bit)
366   // 64-bit PowerPC ELF ABI Supplement, Version 1.9, 2004-10-23:
367   //   The TOC section contains a conventional ELF GOT, and may optionally
368   //   contain a small data area.
369   //   The TOC base is typically the first address in the TOC plus 0x8000.
370   // I don't understand why I can find a ".got" within binaries, but I can't
371   // find a ".toc".  ssuen  August 7, 2007
372   Offset getTOCoffset() const { return got_addr_ + 0x8000; }
373 #else
374   Offset getTOCoffset() const { return 0; }
375 #endif
376
377   const std::ostream &dump_state_info(std::ostream &s);
378   bool isEEL() { return EEL; }
379
380         //to determine if a mutation falls in the text section of
381         // a shared library
382         bool isinText(Offset addr, Offset baseaddr) const { 
383                 //printf(" baseaddr %x TESTING %x %x \n", baseaddr, text_addr_ + baseaddr  , text_addr_ + baseaddr + text_size_ );
384                 if(addr > text_addr_ + baseaddr     &&
385                    addr < text_addr_ + baseaddr + text_size_ ) {
386                         return true;
387                 }
388                 return false;
389         } 
390         // to determine where in the .plt this function is listed 
391         // returns an offset from the base address of the object
392         // so the entry can easily be located in memory
393         Offset getPltSlot(std::string funcName) const ;
394         bool hasSymAtAddr( Offset adr )
395         {
396             return (symbolNamesByAddr.find( adr )!=symbolNamesByAddr.end());
397         }
398         Offset textAddress(){ return text_addr_;}
399         bool isText( Offset addr ) const
400         {
401             if( addr >= text_addr_ && addr <= text_addr_ + text_size_ )
402                 return true;
403             return false;
404         }
405
406         bool is_offset_in_plt(Offset offset) const;
407     Elf_X_Shdr *getRegionHdrByAddr(Offset addr);
408     bool isRegionPresent(Offset segmentStart, Offset segmentSize, unsigned newPerms);
409
410     bool getRegValueAtFrame(Address pc, 
411                             Dyninst::MachRegister reg, 
412                             Dyninst::MachRegisterVal &reg_result,
413                             MemRegReader *reader);
414     bool hasFrameDebugInfo();
415
416     bool convertDebugOffset(Offset off, Offset &new_off);
417  private:
418   static void log_elferror (void (*)(const char *), const char *);
419     
420   Elf_X    elfHdr;
421
422   Elf_X    elfHdrForDebugInfo;
423   
424   Offset   fini_addr_;
425   Offset   text_addr_;   //.text section 
426   Offset   text_size_;   //.text section size
427   Offset   dynamic_addr_;        //.dynamic section
428   Offset   dynsym_addr_;        // .dynsym section
429   Offset   dynstr_addr_;        // .dynstr section
430   Offset   got_addr_;           // global offset table
431   unsigned  got_size_;           // global offset table
432   Offset   plt_addr_;           // procedure linkage table
433   unsigned  plt_size_;           // procedure linkage table
434   unsigned  plt_entry_size_;     // procedure linkage table
435   Offset   rel_plt_addr_;       // .rel[a].plt section
436   unsigned  rel_plt_size_;       // .rel[a].plt section
437   unsigned  rel_plt_entry_size_; // .rel[a].plt section
438   
439   unsigned  rel_size_;       // DT_REL/DT_RELA in dynamic section
440   unsigned  rel_entry_size_; // DT_REL/DT_RELA in dynamic section
441
442   Offset   stab_off_;           // .stab section
443   unsigned  stab_size_;          // .stab section
444   Offset   stabstr_off_;        // .stabstr section
445
446   Offset   stab_indx_off_;       // .stab.index section
447   unsigned  stab_indx_size_;     // .stab.index section
448   Offset   stabstr_indx_off_;    // .stabstr.index section
449
450   bool      dwarvenDebugInfo;    // is DWARF debug info present?
451   Offset   loadAddress_;      // The object may specify a load address
452                                //   Set to 0 if it may load anywhere
453   Offset entryAddress_;
454   char *interpreter_name_;
455   bool  isStripped;
456
457   DwarfHandle dwarf;
458
459 #if defined(arch_ia64)
460   Offset   gp;                   // The gp for this object.
461 #endif
462   bool      EEL;                 // true if EEL rewritten
463   bool      did_open;           // true if the file has been mmapped
464   ObjectType obj_type_;
465
466   // for sparc-solaris this is a table of PLT entry addr, function_name
467   // for x86-solaris this is a table of GOT entry addr, function_name
468   // on sparc-solaris the runtime linker modifies the PLT entry when it
469   // binds a function, on X86 the PLT entry is not modified, but it uses
470   // an indirect jump to a GOT entry that is modified when the function 
471   // is bound....is this correct???? or should it be <PLTentry_addr, name> 
472   // for both?
473   std::vector<relocationEntry> relocation_table_;
474   std::vector<relocationEntry> fbt_;
475
476   // all section headers, sorted by address
477   // we use these to do a better job of finding the end of symbols
478   std::vector<Elf_X_Shdr*> allRegionHdrs;
479
480   // It doesn't look like image's equivalent hashtable is built by
481   // the time we need it, and it's hard to get to anyway.
482   dyn_hash_map< Offset, std::string > symbolNamesByAddr;
483
484   // Symbol version mappings. used to store symbol version names.
485   dyn_hash_map<unsigned, std::vector<std::string> >versionMapping;
486   dyn_hash_map<unsigned, std::string> versionFileNameMapping;
487
488   std::vector<std::string> deps_;
489
490   bool loaded_elf( Offset &, Offset &,
491                     Elf_X_Shdr* &,
492                     Elf_X_Shdr* &, Elf_X_Shdr* &, 
493                     Elf_X_Shdr* &, Elf_X_Shdr* &, 
494                     Elf_X_Shdr* &, Elf_X_Shdr* &, 
495                     Elf_X_Shdr*& rel_plt_scnp, Elf_X_Shdr*& plt_scnp, 
496                     Elf_X_Shdr*& got_scnp,  Elf_X_Shdr*& dynsym_scnp,
497                     Elf_X_Shdr*& dynstr_scnp, Elf_X_Shdr*& dynamic_scnp, Elf_X_Shdr*& eh_frame,
498                     Elf_X_Shdr*& gcc_except, Elf_X_Shdr *& interp_scnp,
499           bool a_out=false);
500   
501   void parseStabFileLineInfo(Symtab *, dyn_hash_map<std::string, LineInformation> &li);
502   void parseDwarfFileLineInfo(dyn_hash_map<std::string, LineInformation> &li);
503
504   void parseDwarfTypes(Symtab *obj);
505   void parseStabTypes(Symtab *obj);
506
507   void load_object(bool);
508   void load_shared_object(bool);
509
510   // initialize relocation_table_ from .rel[a].plt section entries 
511   bool get_relocation_entries(Elf_X_Shdr *&rel_plt_scnp,
512                               Elf_X_Shdr *&dynsym_scnp, 
513                               Elf_X_Shdr *&dynstr_scnp);
514
515   bool get_relocationDyn_entries( Elf_X_Shdr *&rel_scnp,
516                      Elf_X_Shdr *&dynsym_scnp,
517                      Elf_X_Shdr *&dynstr_scnp );
518   
519   void parseDynamic(Elf_X_Shdr *& dyn_scnp, Elf_X_Shdr *&dynsym_scnp, 
520                     Elf_X_Shdr *&dynstr_scnp);
521   
522   void parse_symbols(std::vector<Symbol *> &allsymbols, 
523                      Elf_X_Data &symdata, Elf_X_Data &strdata,
524                     Elf_X_Shdr* &,
525                      bool shared_library,
526                      std::string module);
527   
528   void parse_dynamicSymbols( Elf_X_Shdr *& dyn_scnp, Elf_X_Data &symdata,
529              Elf_X_Data &strdata, bool shared_library,
530                      std::string module);
531
532   void fix_zero_function_sizes(std::vector<Symbol *> &allsymbols, bool EEL);
533   void override_weak_symbols(std::vector<Symbol *> &allsymbols);
534   void insert_symbols_shared(std::vector<Symbol *> &allsymbols);
535   void find_code_and_data(Elf_X &elf,
536        Offset txtaddr, Offset dataddr);
537   void insert_symbols_static(std::vector<Symbol *> &allsymbols);
538   bool fix_global_symbol_modules_static_stab(Elf_X_Shdr *stabscnp,
539                                              Elf_X_Shdr *stabstrscnp);
540   bool fix_global_symbol_modules_static_dwarf();
541
542   void get_valid_memory_areas(Elf_X &elf);
543
544   MappedFile *findMappedFileForDebugInfo();
545   bool find_catch_blocks(Elf_X_Shdr *eh_frame, Elf_X_Shdr *except_scn,
546                          Address textaddr, Address dataaddr,
547                          std::vector<ExceptionBlock> &catch_addrs);
548   
549   struct DbgAddrConversion_t {
550      DbgAddrConversion_t() : dbg_offset(0x0), dbg_size(0x0), orig_offset(0x0) {}
551      std::string name;
552      Offset dbg_offset;
553      unsigned dbg_size;
554      Offset orig_offset;
555   };
556   bool DbgSectionMapSorted;
557   std::vector<DbgAddrConversion_t> DebugSectionMap;
558 };
559
560
561 //const char *pdelf_get_shnames(Elf *elfp, bool is64);
562
563 }//namespace SymtabAPI
564 }//namespace Dyninst
565
566 #endif /* !defined(_Object_elf_h_) */