Determine the architecture of an ELF by looking at the file header instead of the...
[dyninst.git] / symlite / src / SymLite-elf.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "SymLite-elf.h"
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include <iostream> 
38
39 using namespace std;
40 using namespace Dyninst;
41
42 SymElf::SymElf(std::string file_) :
43    elf(NULL),
44    fd(-1),
45    need_odp(false),
46    odp_section(NULL),
47    file(file_),
48    buffer(NULL),
49    buffer_size(0),
50    cache(NULL),
51    cache_size(0),
52    sym_sections(NULL),
53    sym_sections_size(0),
54    ref_count(0),
55    construction_error(false)
56 {
57    fd = open(file_.c_str(), O_RDONLY);
58    if (fd == -1) {
59       construction_error = true;
60       return;
61    }
62    elf = Elf_X::newElf_X(fd, ELF_C_READ, NULL, file_);
63    if (!elf->isValid()) {
64       construction_error = true;
65       close(fd);
66       fd = -1;
67       return;
68    }
69    init();
70 }
71
72 SymElf::SymElf(const char *buffer_, unsigned long buffer_size_) :
73    elf(NULL),
74    fd(-1),
75    need_odp(false),
76    odp_section(NULL),
77    file(),
78    buffer(buffer_),
79    buffer_size(buffer_size_),
80    cache(NULL),
81    cache_size(0),
82    sym_sections(NULL),
83    sym_sections_size(0),
84    ref_count(0),
85    construction_error(false)
86 {
87    elf = Elf_X::newElf_X(const_cast<char *>(buffer_), (size_t) buffer_size);
88    if (!elf->isValid()) {
89       construction_error = true;
90       return;
91    }
92    init();
93 }
94
95 SymElf::~SymElf()
96 {
97    if (!elf) return;
98    if (elf->isValid())
99       elf->end();
100    if (fd != -1) {
101       close(fd);
102       fd = -1;
103    }
104    if (cache) {
105       free(cache);
106       cache = NULL;
107       cache_size = 0;
108    }
109    if (sym_sections) {
110       free(sym_sections);
111       sym_sections = NULL;
112       sym_sections_size = 0;
113    }
114 }
115
116 void SymElf::init()
117 {
118    if (elf->e_machine() == EM_PPC64) {
119       unsigned short stridx = elf->e_shstrndx();
120       Elf_X_Shdr strshdr = elf->get_shdr(stridx);
121       Elf_X_Data strdata = strshdr.get_data();
122       const char *names = (const char *) strdata.d_buf();
123       
124       for (unsigned i=0; i < elf->e_shnum(); i++) {
125          Elf_X_Shdr &shdr = elf->get_shdr(i);
126          if (strcmp(names + shdr.sh_name(), ".opd") != 0)
127             continue;
128          odp_section = & shdr;
129          need_odp = true;
130          break;
131       }
132    }
133 }
134
135 #define INVALID_SYM_CODE ((int) 0xffffffff)
136 #define UNSET_INDEX_CODE ((int) 0xfffffffe)
137
138 #define FOR_EACH_SYMBOL(shdr, symbols, str_buffer, idx) \
139    Elf_X_Data sym_data = shdr.get_data(); \
140    Elf_X_Sym symbols = sym_data.get_sym(); \
141    int str_index = shdr.sh_link(); \
142    Elf_X_Shdr str_shdr = elf->get_shdr(str_index); \
143    if (!str_shdr.isValid()) { \
144       continue; \
145    } \
146    Elf_X_Data str_data = str_shdr.get_data(); \
147    const char *str_buffer = (const char *) str_data.d_buf(); \
148    unsigned sym_count = symbols.count(); \
149    for (unsigned idx=0; idx<sym_count; idx++)
150
151 #define MAKE_SYMBOL(name, idx, shdr, sym) \
152    sym.v1 = (void *) (const_cast<char *>(name)); \
153    sym.v2 = (void *) shdr.getScn(); \
154    sym.i1 = (int) idx; \
155    sym.i2 = UNSET_INDEX_CODE;
156
157 #define SET_SYM_CACHEINDEX(sym, idx) \
158    sym.i2 = idx
159
160 #define GET_SYMBOL(sym, shdr, symbols, name, idx) \
161    assert(sym.i2 != INVALID_SYM_CODE); \
162    const char *name = (const char *) sym.v1; \
163    Elf_X_Shdr shdr = Elf_X_Shdr(elf->wordSize() == 8, (Elf_Scn *) sym.v2); \
164    unsigned idx = (unsigned) sym.i1; \
165    Elf_X_Data sym_data = shdr.get_data(); \
166    Elf_X_Sym symbols = sym_data.get_sym();
167    
168 #define GET_INVALID_SYMBOL(sym) \
169    sym.v1 = sym.v2 = NULL; \
170    sym.i1 = 0; sym.i2 = INVALID_SYM_CODE;
171
172 Symbol_t SymElf::getSymbolByName(std::string symname)
173 {
174    Symbol_t ret;
175    for (unsigned i=0; i < elf->e_shnum(); i++) 
176    {
177       Elf_X_Shdr shdr = elf->get_shdr(i);
178       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
179          continue;
180       } 
181
182       FOR_EACH_SYMBOL(shdr, symbol, str_buffer, idx) 
183       {
184          unsigned str_loc = symbol.st_name(idx);
185          if (strcmp(str_buffer+str_loc, symname.c_str()) != 0)
186             continue;
187          if (symbol.st_shndx(idx) == 0) {
188            continue;
189          }
190
191          MAKE_SYMBOL(str_buffer+str_loc, idx, shdr, ret);
192          return ret;
193       }
194    }
195    GET_INVALID_SYMBOL(ret);
196    return ret;
197 }
198
199 Symbol_t SymElf::getContainingSymbol(Dyninst::Offset offset)
200 {
201 #if 1
202    if (!cache) {
203       createSymCache();
204    }
205    return lookupCachedSymbol(offset);
206
207 #else
208    Dyninst::Offset nearest = 0;
209    bool has_nearest = false;
210    Symbol_t nearest_sym;
211
212    for (unsigned i=0; i < elf->e_shnum(); i++) 
213    {
214       Elf_X_Shdr shdr = elf->get_shdr(i);
215       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
216          continue;
217       } 
218
219       FOR_EACH_SYMBOL(shdr, symbol, str_buffer, idx) 
220       {
221          Dyninst::Offset sym_offset = getSymOffset(symbol, idx);
222          if (sym_offset <= offset && (!has_nearest || sym_offset > nearest)) {
223             unsigned str_loc = symbol.st_name(idx);
224             MAKE_SYMBOL(str_buffer+str_loc, idx, shdr, nearest_sym);
225             has_nearest = true;
226             nearest = sym_offset;
227          }
228       }
229    }
230    if (!has_nearest) {
231       GET_INVALID_SYMBOL(nearest_sym);
232    }
233
234    return nearest_sym;
235 #endif
236 }
237
238 std::string SymElf::getInterpreterName()
239 {
240    for (unsigned i=0; i < elf->e_phnum(); i++)
241    {
242       Elf_X_Phdr phdr = elf->get_phdr(i);
243       if (phdr.p_type() != PT_INTERP)
244          continue;
245       Dyninst::Offset off = (Dyninst::Offset) phdr.p_offset();
246       
247       if (fd != -1) {
248          char interp_buffer[4096];
249          ssize_t result;
250          do {
251             result = pread(fd, interp_buffer, 4096, off);
252          } while (result == -1 && errno == EINTR);
253          if (result != -1) {
254             return std::string(interp_buffer);
255          }
256       }
257       else if (buffer) {
258          return std::string(buffer + off);
259       }
260
261       //rawfile is expensive
262       size_t filesize;
263       const char *whole_file = elf->e_rawfile(filesize);
264       if (filesize < off) {
265          return std::string();
266       }
267       return std::string(whole_file + off);
268    }
269    return std::string();
270 }
271
272 unsigned SymElf::numSegments()
273 {
274    return elf->e_phnum();
275 }
276
277 bool SymElf::getSegment(unsigned num, SymSegment &seg)
278 {
279    if (num >= elf->e_phnum())
280       return false;
281
282    Elf_X_Phdr &phdr = elf->get_phdr(num);
283    seg.file_offset = phdr.p_offset();
284    seg.mem_addr = phdr.p_vaddr();
285    seg.file_size = phdr.p_filesz();
286    seg.mem_size = phdr.p_memsz();
287    seg.type = phdr.p_type();
288    seg.perms = phdr.p_flags() & 0x7;
289    return true;
290 }
291
292 unsigned SymElf::getAddressWidth()
293 {
294    return elf->wordSize();
295 }
296
297 bool SymElf::getABIVersion(int &major, int &minor) const
298 {
299    if (elf->e_machine() == EM_PPC64 && elf->e_flags() == 0x2) {
300       major = elf->e_flags();
301       minor = 0;
302       return true;
303    }
304    else {
305       return false;
306    }
307 }
308
309 bool SymElf::isBigEndianDataEncoding() const
310 {
311    return (elf->e_endian() != 0);
312 }
313
314 Architecture SymElf::getArchitecture() const
315 {
316     return elf->getArch();
317 }
318
319 unsigned long SymElf::getSymbolSize(const Symbol_t &sym)
320 {
321    GET_SYMBOL(sym, shdr, symbol, name, idx);
322    (void)name; //Silence warnings
323    unsigned long size = symbol.st_size(idx);
324    return size;
325 }
326
327 Dyninst::Offset SymElf::getSymbolOffset(const Symbol_t &sym)
328 {
329    assert(sym.i2 != INVALID_SYM_CODE);
330    if (sym.i2 != UNSET_INDEX_CODE) {
331       int cache_index = sym.i2;
332       return cache[cache_index].symaddress;
333    }
334
335    GET_SYMBOL(sym, shdr, symbols, name, idx);
336    (void)name; //Silence warnings
337    return getSymOffset(symbols, idx);
338 }
339
340 Dyninst::Offset SymElf::getSymbolTOC(const Symbol_t &sym)
341 {
342    GET_SYMBOL(sym, shdr, symbols, name, idx);
343    (void)name; //Silence warnings
344    return getSymTOC(symbols, idx);
345 }
346
347 std::string SymElf::getSymbolName(const Symbol_t &sym)
348 {
349    GET_SYMBOL(sym, shdr, symbols, name, idx);
350    (void)idx; (void)symbols; //Silence warnings
351    return std::string(name);
352 }
353
354 std::string SymElf::getDemangledName(const Symbol_t &sym)
355 {
356    assert(sym.i2 != INVALID_SYM_CODE);
357    int cache_index = -1;
358    const char *name = NULL;
359    if (sym.i2 != UNSET_INDEX_CODE) {
360       cache_index = sym.i2;
361       name = (const char *) sym.v1;
362    }
363    else {
364       assert(0); //TODO: Lookup in cache
365    }
366
367    if (cache[cache_index].demangled_name)
368       return std::string(cache[cache_index].demangled_name);
369    char *res = P_cplus_demangle(name, false, true);
370    if (!res) {
371       //Try native demangler
372       res = P_cplus_demangle(name, true, true);
373    }
374
375    cache[cache_index].demangled_name = res ? res : name;
376    return cache[cache_index].demangled_name;
377 }
378
379 bool SymElf::isValidSymbol(const Symbol_t &sym)
380 {
381    return (sym.i2 != INVALID_SYM_CODE);
382 }
383
384 static int symcache_cmp(const void *a, const void *b)
385 {
386    const SymCacheEntry *aa = (const SymCacheEntry *) a;
387    const SymCacheEntry *bb = (const SymCacheEntry *) b;
388    if (aa->symaddress < bb->symaddress) return -1;
389    else if (aa->symaddress > bb->symaddress) return 1;
390    else return 0;
391 }
392
393 unsigned long SymElf::getSymOffset(const Elf_X_Sym &symbol, unsigned idx)
394 {
395    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
396       unsigned long odp_addr = odp_section->sh_addr();
397       unsigned long odp_size = odp_section->sh_size();
398       const char *odp_data = (const char *) odp_section->get_data().d_buf();
399       
400       unsigned long sym_offset = symbol.st_value(idx);
401       while (sym_offset >= odp_addr && sym_offset < odp_addr + odp_size)
402          sym_offset = *((const unsigned long *) (odp_data + sym_offset - odp_addr));
403       return sym_offset;
404    }
405
406    return symbol.st_value(idx);
407 }
408
409 unsigned long SymElf::getSymTOC(const Elf_X_Sym &symbol, unsigned idx)
410 {
411    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
412       unsigned long odp_addr = odp_section->sh_addr();
413       unsigned long odp_size = odp_section->sh_size();
414       const char *odp_data = (const char *) odp_section->get_data().d_buf();
415       unsigned long sym_offset = symbol.st_value(idx);
416
417       if (sym_offset < odp_addr || (sym_offset >= odp_addr + odp_size)) 
418          return 0;
419
420       unsigned long toc = *((const unsigned long *) (odp_data + (sym_offset - odp_addr + sizeof(long))));
421       return toc;
422    }
423
424    return 0;
425 }
426
427 void SymElf::createSymCache()
428 {
429    unsigned long sym_count = 0, cur_sym = 0, cur_sec = 0;
430    
431    if (!cache && sym_sections)
432       return;
433
434    assert(!cache);
435    assert(!sym_sections);
436    for (unsigned i=0; i < elf->e_shnum(); i++) 
437    {
438       Elf_X_Shdr shdr = elf->get_shdr(i);
439       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
440          continue;
441       }
442       Elf_X_Data sym_data = shdr.get_data();
443       Elf_X_Sym symbols = sym_data.get_sym();
444       sym_count += symbols.count();
445       sym_sections_size++;
446    }
447
448    sym_sections = (Elf_X_Shdr *) malloc(sym_sections_size * sizeof(Elf_X_Shdr));
449    if (sym_count)
450       cache = (SymCacheEntry *) malloc(sym_count * sizeof(SymCacheEntry));
451    
452    for (unsigned i=0; i < elf->e_shnum(); i++) 
453    {
454       Elf_X_Shdr shdr = elf->get_shdr(i);
455       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
456          continue;
457       }
458
459       sym_sections[cur_sec] = shdr;
460       cur_sec++;
461
462       FOR_EACH_SYMBOL(shdr, symbols, str_buffer, idx)
463       {
464          (void)str_buffer; //Disable warnings
465          unsigned char symtype = symbols.ST_TYPE(idx);
466          if (symtype != STT_FUNC)
467             continue;
468          if (!symbols.st_value(idx))
469             continue;
470          cache[cur_sym].symaddress = getSymOffset(symbols, idx);
471          cache[cur_sym].symloc = symbols.st_symptr(idx);
472          cache[cur_sym].demangled_name = NULL;
473          cur_sym++;
474       }
475    }
476    cache_size = cur_sym;
477    if (cache)
478       cache = (SymCacheEntry *) realloc(cache, cur_sym  * sizeof(SymCacheEntry)); //Size reduction
479    if (cache)
480       qsort(cache, cache_size, sizeof(SymCacheEntry), symcache_cmp);
481 }
482
483 Symbol_t SymElf::lookupCachedSymbol(Dyninst::Offset off)
484 {
485    unsigned min = 0;
486    unsigned max = cache_size;
487    unsigned cur = cache_size / 2;
488    Symbol_t ret;
489    
490    if (!cache) {
491       ret.i2 = INVALID_SYM_CODE;
492       return ret;
493    }
494
495    for (;;) {
496       if (max == min || min+1 == max)
497          break;
498       Dyninst::Offset cur_off = cache[cur].symaddress;
499       if (cur_off < off) {
500          min = cur;
501       }
502       else if (cur_off > off) {
503          max = cur;
504       }
505       else {
506          break;
507       }
508       cur = (min + max) / 2;
509    }
510    void *sym_ptr = cache[cur].symloc;
511
512    for (unsigned i=0; i<sym_sections_size; i++) {
513       Elf_X_Shdr &shdr = sym_sections[i];
514       Elf_X_Data data = shdr.get_data();
515       
516       void *data_start = data.d_buf();
517       signed long sym_offset = ((unsigned char *) sym_ptr) - ((unsigned char *) data_start);
518       if (sym_offset < 0 || sym_offset >= (signed long) data.d_size())
519          continue;
520
521       //Calculate symbol index
522       Elf_X_Sym syms = data.get_sym();
523       unsigned sym_idx = sym_offset / syms.st_entsize();
524       
525       //Lookup symbol name
526       unsigned int str_index = shdr.sh_link();
527       Elf_X_Shdr str_shdr = elf->get_shdr(str_index);
528       Elf_X_Data str_data = str_shdr.get_data();
529       const char *str_buffer = (const char *) str_data.d_buf();
530       const char *name = str_buffer + syms.st_name(sym_idx);
531       
532       MAKE_SYMBOL(name, sym_idx, shdr, ret);
533       SET_SYM_CACHEINDEX(ret, cur);
534       return ret;
535    }
536    assert(0);
537
538    return ret;
539 }
540
541 Section_t SymElf::getSectionByName(std::string name)
542 {
543    unsigned short stridx = elf->e_shstrndx();
544    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
545    Elf_X_Data strdata = strshdr.get_data();
546    const char *names = (const char *) strdata.d_buf();
547    Section_t ret;
548    ret.i1 = -1;
549
550    for (unsigned i=0; i < elf->e_shnum(); i++) 
551    {
552       Elf_X_Shdr shdr = elf->get_shdr(i);
553       const char *sname = names + shdr.sh_name();
554       if (name == sname) {
555          ret.i1 = i;
556          break;
557       }
558    }
559    
560    return ret;
561 }
562
563 Section_t SymElf::getSectionByAddress(Dyninst::Address addr)
564 {
565    Section_t ret;
566    ret.i1 = -1;
567
568    for (unsigned i=0; i < elf->e_shnum(); i++) 
569    {
570       Elf_X_Shdr shdr = elf->get_shdr(i);
571       Dyninst::Address mem_start = shdr.sh_addr();
572       unsigned long mem_size = shdr.sh_size();
573       if (addr >= mem_start && addr < mem_start + mem_size) {
574          ret.i1 = i;
575          break;
576       }
577    }
578    return ret;
579 }
580
581 Dyninst::Address SymElf::getSectionAddress(Section_t sec)
582 {
583    assert(isValidSection(sec));
584    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
585    
586    return shdr.sh_addr();
587 }
588
589 std::string SymElf::getSectionName(Section_t sec)
590 {
591    assert(isValidSection(sec));
592    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
593
594    unsigned short stridx = elf->e_shstrndx();
595    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
596    Elf_X_Data strdata = strshdr.get_data();
597    const char *names = (const char *) strdata.d_buf();
598
599    return std::string(names + shdr.sh_name());
600 }
601
602 bool SymElf::isValidSection(Section_t sec)
603 {
604    return (sec.i1 != -1);
605 }
606
607 Dyninst::Offset SymElf::imageOffset() 
608
609    assert(0); return 0;
610 };
611
612 Dyninst::Offset SymElf::dataOffset() 
613
614    assert(0); return 0; 
615 }
616
617 void *SymElf::getElfHandle() {
618    return (void *) elf;
619 }
620
621 namespace Dyninst {
622 extern map<string, SymElf *> *getSymelfCache();
623 }
624
625 SymElfFactory::SymElfFactory()
626 {
627    open_symelfs = Dyninst::getSymelfCache();
628    assert(open_symelfs);
629 }
630
631 SymElfFactory::~SymElfFactory()
632 {
633 }
634
635 SymReader *SymElfFactory::openSymbolReader(std::string pathname)
636 {
637    SymElf *se = NULL;
638    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(pathname);
639    if (i == open_symelfs->end()) {
640       se = new SymElf(pathname);
641       if (se->construction_error) {
642          delete se;
643          return NULL;
644       }
645       se->ref_count = 1;
646       (*open_symelfs)[pathname] = se;
647    }
648    else {
649       se = i->second;
650       se->ref_count++;
651    }
652    return static_cast<SymReader *>(se);
653 }
654
655 SymReader *SymElfFactory::openSymbolReader(const char *buffer, unsigned long size)
656 {
657    SymElf *se = new SymElf(buffer, size);
658    if (se->construction_error) {
659       delete se;
660       return NULL;
661    }
662    se->ref_count = 1;
663    return static_cast<SymReader *>(se);
664 }
665
666 bool SymElfFactory::closeSymbolReader(SymReader *sr)
667 {
668    SymElf *ser = static_cast<SymElf *>(sr);
669    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(ser->file);
670    if (i == open_symelfs->end()) {
671       delete ser;
672       return true;
673    }
674
675    ser->ref_count--;
676    if (ser->ref_count == 0) {
677       open_symelfs->erase(i);
678       delete ser;
679    }
680    return true;
681 }
682
683 int SymElf::getFD()
684 {
685   return fd;
686   
687 }