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