symlite: Fix Coverity UNINIT_CTOR errors
[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/h/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 unsigned long SymElf::getSymbolSize(const Symbol_t &sym)
298 {
299    GET_SYMBOL(sym, shdr, symbol, name, idx);
300    (void)name; //Silence warnings
301    unsigned long size = symbol.st_size(idx);
302    return size;
303 }
304
305 Dyninst::Offset SymElf::getSymbolOffset(const Symbol_t &sym)
306 {
307    assert(sym.i2 != INVALID_SYM_CODE);
308    if (sym.i2 != UNSET_INDEX_CODE) {
309       int cache_index = sym.i2;
310       return cache[cache_index].symaddress;
311    }
312
313    GET_SYMBOL(sym, shdr, symbols, name, idx);
314    (void)name; //Silence warnings
315    return getSymOffset(symbols, idx);
316 }
317
318 Dyninst::Offset SymElf::getSymbolTOC(const Symbol_t &sym)
319 {
320    GET_SYMBOL(sym, shdr, symbols, name, idx);
321    (void)name; //Silence warnings
322    return getSymTOC(symbols, idx);
323 }
324
325 std::string SymElf::getSymbolName(const Symbol_t &sym)
326 {
327    GET_SYMBOL(sym, shdr, symbols, name, idx);
328    (void)idx; (void)symbols; //Silence warnings
329    return std::string(name);
330 }
331
332 std::string SymElf::getDemangledName(const Symbol_t &sym)
333 {
334    assert(sym.i2 != INVALID_SYM_CODE);
335    int cache_index = -1;
336    const char *name = NULL;
337    if (sym.i2 != UNSET_INDEX_CODE) {
338       cache_index = sym.i2;
339       name = (const char *) sym.v1;
340    }
341    else {
342       assert(0); //TODO: Lookup in cache
343    }
344
345    if (cache[cache_index].demangled_name)
346       return std::string(cache[cache_index].demangled_name);
347    char *res = P_cplus_demangle(name, false, true);
348    if (!res) {
349       //Try native demangler
350       res = P_cplus_demangle(name, true, true);
351    }
352
353    cache[cache_index].demangled_name = res ? res : name;
354    return cache[cache_index].demangled_name;
355 }
356
357 bool SymElf::isValidSymbol(const Symbol_t &sym)
358 {
359    return (sym.i2 != INVALID_SYM_CODE);
360 }
361
362 static int symcache_cmp(const void *a, const void *b)
363 {
364    const SymCacheEntry *aa = (const SymCacheEntry *) a;
365    const SymCacheEntry *bb = (const SymCacheEntry *) b;
366    if (aa->symaddress < bb->symaddress) return -1;
367    else if (aa->symaddress > bb->symaddress) return 1;
368    else return 0;
369 }
370
371 unsigned long SymElf::getSymOffset(const Elf_X_Sym &symbol, unsigned idx)
372 {
373    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
374       unsigned long odp_addr = odp_section->sh_addr();
375       unsigned long odp_size = odp_section->sh_size();
376       const char *odp_data = (const char *) odp_section->get_data().d_buf();
377       
378       unsigned long sym_offset = symbol.st_value(idx);
379       while (sym_offset >= odp_addr && sym_offset < odp_addr + odp_size)
380          sym_offset = *((const unsigned long *) (odp_data + sym_offset - odp_addr));
381       return sym_offset;
382    }
383
384    return symbol.st_value(idx);
385 }
386
387 unsigned long SymElf::getSymTOC(const Elf_X_Sym &symbol, unsigned idx)
388 {
389    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
390       unsigned long odp_addr = odp_section->sh_addr();
391       unsigned long odp_size = odp_section->sh_size();
392       const char *odp_data = (const char *) odp_section->get_data().d_buf();
393       unsigned long sym_offset = symbol.st_value(idx);
394
395       if (sym_offset < odp_addr || (sym_offset >= odp_addr + odp_size)) 
396          return 0;
397
398       unsigned long toc = *((const unsigned long *) (odp_data + (sym_offset - odp_addr + sizeof(long))));
399       return toc;
400    }
401
402    return 0;
403 }
404
405 void SymElf::createSymCache()
406 {
407    unsigned long sym_count = 0, cur_sym = 0, cur_sec = 0;
408    
409    if (!cache && sym_sections)
410       return;
411
412    assert(!cache);
413    assert(!sym_sections);
414    for (unsigned i=0; i < elf->e_shnum(); i++) 
415    {
416       Elf_X_Shdr shdr = elf->get_shdr(i);
417       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
418          continue;
419       }
420       Elf_X_Data sym_data = shdr.get_data();
421       Elf_X_Sym symbols = sym_data.get_sym();
422       sym_count += symbols.count();
423       sym_sections_size++;
424    }
425
426    sym_sections = (Elf_X_Shdr *) malloc(sym_sections_size * sizeof(Elf_X_Shdr));
427    if (sym_count)
428       cache = (SymCacheEntry *) malloc(sym_count * sizeof(SymCacheEntry));
429    
430    for (unsigned i=0; i < elf->e_shnum(); i++) 
431    {
432       Elf_X_Shdr shdr = elf->get_shdr(i);
433       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
434          continue;
435       }
436
437       sym_sections[cur_sec] = shdr;
438       cur_sec++;
439
440       FOR_EACH_SYMBOL(shdr, symbols, str_buffer, idx)
441       {
442          (void)str_buffer; //Disable warnings
443          unsigned char symtype = symbols.ST_TYPE(idx);
444          if (symtype != STT_FUNC)
445             continue;
446          if (!symbols.st_value(idx))
447             continue;
448          cache[cur_sym].symaddress = getSymOffset(symbols, idx);
449          cache[cur_sym].symloc = symbols.st_symptr(idx);
450          cache[cur_sym].demangled_name = NULL;
451          cur_sym++;
452       }
453    }
454    cache_size = cur_sym;
455    if (cache)
456       cache = (SymCacheEntry *) realloc(cache, cur_sym  * sizeof(SymCacheEntry)); //Size reduction
457    if (cache)
458       qsort(cache, cache_size, sizeof(SymCacheEntry), symcache_cmp);
459 }
460
461 Symbol_t SymElf::lookupCachedSymbol(Dyninst::Offset off)
462 {
463    unsigned min = 0;
464    unsigned max = cache_size;
465    unsigned cur = cache_size / 2;
466    Symbol_t ret;
467    
468    if (!cache) {
469       ret.i2 = INVALID_SYM_CODE;
470       return ret;
471    }
472
473    for (;;) {
474       if (max == min || min+1 == max)
475          break;
476       Dyninst::Offset cur_off = cache[cur].symaddress;
477       if (cur_off < off) {
478          min = cur;
479       }
480       else if (cur_off > off) {
481          max = cur;
482       }
483       else {
484          break;
485       }
486       cur = (min + max) / 2;
487    }
488    void *sym_ptr = cache[cur].symloc;
489
490    for (unsigned i=0; i<sym_sections_size; i++) {
491       Elf_X_Shdr &shdr = sym_sections[i];
492       Elf_X_Data data = shdr.get_data();
493       
494       void *data_start = data.d_buf();
495       signed long sym_offset = ((unsigned char *) sym_ptr) - ((unsigned char *) data_start);
496       if (sym_offset < 0 || sym_offset >= (signed long) data.d_size())
497          continue;
498
499       //Calculate symbol index
500       Elf_X_Sym syms = data.get_sym();
501       unsigned sym_idx = sym_offset / syms.st_entsize();
502       
503       //Lookup symbol name
504       unsigned int str_index = shdr.sh_link();
505       Elf_X_Shdr str_shdr = elf->get_shdr(str_index);
506       Elf_X_Data str_data = str_shdr.get_data();
507       const char *str_buffer = (const char *) str_data.d_buf();
508       const char *name = str_buffer + syms.st_name(sym_idx);
509       
510       MAKE_SYMBOL(name, sym_idx, shdr, ret);
511       SET_SYM_CACHEINDEX(ret, cur);
512       return ret;
513    }
514    assert(0);
515
516    return ret;
517 }
518
519 Section_t SymElf::getSectionByName(std::string name)
520 {
521    unsigned short stridx = elf->e_shstrndx();
522    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
523    Elf_X_Data strdata = strshdr.get_data();
524    const char *names = (const char *) strdata.d_buf();
525    Section_t ret;
526    ret.i1 = -1;
527
528    for (unsigned i=0; i < elf->e_shnum(); i++) 
529    {
530       Elf_X_Shdr shdr = elf->get_shdr(i);
531       const char *sname = names + shdr.sh_name();
532       if (name == sname) {
533          ret.i1 = i;
534          break;
535       }
536    }
537    
538    return ret;
539 }
540
541 Section_t SymElf::getSectionByAddress(Dyninst::Address addr)
542 {
543    Section_t ret;
544    ret.i1 = -1;
545
546    for (unsigned i=0; i < elf->e_shnum(); i++) 
547    {
548       Elf_X_Shdr shdr = elf->get_shdr(i);
549       Dyninst::Address mem_start = shdr.sh_addr();
550       unsigned long mem_size = shdr.sh_size();
551       if (addr >= mem_start && addr < mem_start + mem_size) {
552          ret.i1 = i;
553          break;
554       }
555    }
556    return ret;
557 }
558
559 Dyninst::Address SymElf::getSectionAddress(Section_t sec)
560 {
561    assert(isValidSection(sec));
562    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
563    
564    return shdr.sh_addr();
565 }
566
567 std::string SymElf::getSectionName(Section_t sec)
568 {
569    assert(isValidSection(sec));
570    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
571
572    unsigned short stridx = elf->e_shstrndx();
573    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
574    Elf_X_Data strdata = strshdr.get_data();
575    const char *names = (const char *) strdata.d_buf();
576
577    return std::string(names + shdr.sh_name());
578 }
579
580 bool SymElf::isValidSection(Section_t sec)
581 {
582    return (sec.i1 != -1);
583 }
584
585 Dyninst::Offset SymElf::imageOffset() 
586
587    assert(0); return 0;
588 };
589
590 Dyninst::Offset SymElf::dataOffset() 
591
592    assert(0); return 0; 
593 }
594
595 void *SymElf::getElfHandle() {
596    return (void *) elf;
597 }
598
599 namespace Dyninst {
600 extern map<string, SymElf *> *getSymelfCache();
601 }
602
603 SymElfFactory::SymElfFactory()
604 {
605    open_symelfs = Dyninst::getSymelfCache();
606    assert(open_symelfs);
607 }
608
609 SymElfFactory::~SymElfFactory()
610 {
611 }
612
613 SymReader *SymElfFactory::openSymbolReader(std::string pathname)
614 {
615    SymElf *se = NULL;
616    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(pathname);
617    if (i == open_symelfs->end()) {
618       se = new SymElf(pathname);
619       if (se->construction_error) {
620          delete se;
621          return NULL;
622       }
623       se->ref_count = 1;
624       (*open_symelfs)[pathname] = se;
625    }
626    else {
627       se = i->second;
628       se->ref_count++;
629    }
630    return static_cast<SymReader *>(se);
631 }
632
633 SymReader *SymElfFactory::openSymbolReader(const char *buffer, unsigned long size)
634 {
635    SymElf *se = new SymElf(buffer, size);
636    if (se->construction_error) {
637       delete se;
638       return NULL;
639    }
640    se->ref_count = 1;
641    return static_cast<SymReader *>(se);
642 }
643
644 bool SymElfFactory::closeSymbolReader(SymReader *sr)
645 {
646    SymElf *ser = static_cast<SymElf *>(sr);
647    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(ser->file);
648    if (i == open_symelfs->end()) {
649       delete ser;
650       return true;
651    }
652
653    ser->ref_count--;
654    if (ser->ref_count == 0) {
655       open_symelfs->erase(i);
656       delete ser;
657    }
658    return true;
659 }
660
661 int SymElf::getFD()
662 {
663   return fd;
664   
665 }