SymLite-elf.C

Go to the documentation of this file.
00001 /*
00002  * See the dyninst/COPYRIGHT file for copyright information.
00003  * 
00004  * We provide the Paradyn Tools (below described as "Paradyn")
00005  * on an AS IS basis, and do not warrant its validity or performance.
00006  * We reserve the right to update, modify, or discontinue this
00007  * software at any time.  We shall have no obligation to supply such
00008  * updates or modifications or any other form of support to you.
00009  * 
00010  * By your use of Paradyn, you understand and agree that we (or any
00011  * other person or entity with proprietary rights in Paradyn) are
00012  * under no obligation to provide either maintenance services,
00013  * update services, notices of latent defects, or correction of
00014  * defects for Paradyn.
00015  * 
00016  * This library is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU Lesser General Public
00018  * License as published by the Free Software Foundation; either
00019  * version 2.1 of the License, or (at your option) any later version.
00020  * 
00021  * This library is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024  * Lesser General Public License for more details.
00025  * 
00026  * You should have received a copy of the GNU Lesser General Public
00027  * License along with this library; if not, write to the Free Software
00028  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00029  */
00030 
00031 #include "symlite/h/SymLite-elf.h"
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <fcntl.h>
00035 #include <unistd.h>
00036 #include <assert.h>
00037 #include <iostream> 
00038 
00039 using namespace std;
00040 using namespace Dyninst;
00041 
00042 SymElf::SymElf(std::string file_) :
00043    elf(NULL),
00044    fd(-1),
00045    need_odp(false),
00046    file(file_),
00047    buffer(NULL),
00048    buffer_size(0),
00049    cache(NULL),
00050    cache_size(0),
00051    sym_sections(NULL),
00052    sym_sections_size(0),
00053    ref_count(0),
00054    construction_error(false)
00055 {
00056    fd = open(file_.c_str(), O_RDONLY);
00057    if (fd == -1) {
00058       construction_error = true;
00059       return;
00060    }
00061    elf = Elf_X::newElf_X(fd, ELF_C_READ, NULL, file_);
00062    if (!elf->isValid()) {
00063       construction_error = true;
00064       close(fd);
00065       fd = -1;
00066       return;
00067    }
00068    init();
00069 }
00070 
00071 SymElf::SymElf(const char *buffer_, unsigned long buffer_size_) :
00072    elf(NULL),
00073    fd(-1),
00074    need_odp(false),
00075    file(),
00076    buffer(buffer_),
00077    buffer_size(buffer_size_),
00078    cache(NULL),
00079    cache_size(0),
00080    sym_sections(NULL),
00081    sym_sections_size(0),
00082    ref_count(0),
00083    construction_error(false)
00084 {
00085    elf = Elf_X::newElf_X(const_cast<char *>(buffer_), (size_t) buffer_size);
00086    if (!elf->isValid()) {
00087       construction_error = true;
00088       return;
00089    }
00090    init();
00091 }
00092 
00093 SymElf::~SymElf()
00094 {
00095    if (!elf) return;
00096    if (elf->isValid())
00097       elf->end();
00098    if (fd != -1) {
00099       close(fd);
00100       fd = -1;
00101    }
00102    if (cache) {
00103       free(cache);
00104       cache = NULL;
00105       cache_size = 0;
00106    }
00107    if (sym_sections) {
00108       free(sym_sections);
00109       sym_sections = NULL;
00110       sym_sections_size = 0;
00111    }
00112 }
00113 
00114 void SymElf::init()
00115 {
00116    if (elf->e_machine() == EM_PPC64) {
00117       unsigned short stridx = elf->e_shstrndx();
00118       Elf_X_Shdr strshdr = elf->get_shdr(stridx);
00119       Elf_X_Data strdata = strshdr.get_data();
00120       const char *names = (const char *) strdata.d_buf();
00121       
00122       for (unsigned i=0; i < elf->e_shnum(); i++) {
00123          Elf_X_Shdr &shdr = elf->get_shdr(i);
00124          if (strcmp(names + shdr.sh_name(), ".opd") != 0)
00125             continue;
00126          odp_section = & shdr;
00127          need_odp = true;
00128          break;
00129       }
00130    }
00131 }
00132 
00133 #define INVALID_SYM_CODE ((int) 0xffffffff)
00134 #define UNSET_INDEX_CODE ((int) 0xfffffffe)
00135 
00136 #define FOR_EACH_SYMBOL(shdr, symbols, str_buffer, idx) \
00137    Elf_X_Data sym_data = shdr.get_data(); \
00138    Elf_X_Sym symbols = sym_data.get_sym(); \
00139    int str_index = shdr.sh_link(); \
00140    Elf_X_Shdr str_shdr = elf->get_shdr(str_index); \
00141    if (!str_shdr.isValid()) { \
00142       continue; \
00143    } \
00144    Elf_X_Data str_data = str_shdr.get_data(); \
00145    const char *str_buffer = (const char *) str_data.d_buf(); \
00146    unsigned sym_count = symbols.count(); \
00147    for (unsigned idx=0; idx<sym_count; idx++)
00148 
00149 #define MAKE_SYMBOL(name, idx, shdr, sym) \
00150    sym.v1 = (void *) (const_cast<char *>(name)); \
00151    sym.v2 = (void *) shdr.getScn(); \
00152    sym.i1 = (int) idx; \
00153    sym.i2 = UNSET_INDEX_CODE;
00154 
00155 #define SET_SYM_CACHEINDEX(sym, idx) \
00156    sym.i2 = idx
00157 
00158 #define GET_SYMBOL(sym, shdr, symbols, name, idx) \
00159    assert(sym.i2 != INVALID_SYM_CODE); \
00160    const char *name = (const char *) sym.v1; \
00161    Elf_X_Shdr shdr = Elf_X_Shdr(elf->wordSize() == 8, (Elf_Scn *) sym.v2); \
00162    unsigned idx = (unsigned) sym.i1; \
00163    Elf_X_Data sym_data = shdr.get_data(); \
00164    Elf_X_Sym symbols = sym_data.get_sym();
00165    
00166 #define GET_INVALID_SYMBOL(sym) \
00167    sym.v1 = sym.v2 = NULL; \
00168    sym.i1 = 0; sym.i2 = INVALID_SYM_CODE;
00169 
00170 Symbol_t SymElf::getSymbolByName(std::string symname)
00171 {
00172    Symbol_t ret;
00173    for (unsigned i=0; i < elf->e_shnum(); i++) 
00174    {
00175       Elf_X_Shdr shdr = elf->get_shdr(i);
00176       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
00177          continue;
00178       } 
00179 
00180       FOR_EACH_SYMBOL(shdr, symbol, str_buffer, idx) 
00181       {
00182          unsigned str_loc = symbol.st_name(idx);
00183          if (strcmp(str_buffer+str_loc, symname.c_str()) != 0)
00184             continue;
00185      if (symbol.st_shndx(idx) == 0) {
00186        continue;
00187      }
00188 
00189          MAKE_SYMBOL(str_buffer+str_loc, idx, shdr, ret);
00190          return ret;
00191       }
00192    }
00193    GET_INVALID_SYMBOL(ret);
00194    return ret;
00195 }
00196 
00197 Symbol_t SymElf::getContainingSymbol(Dyninst::Offset offset)
00198 {
00199 #if 1
00200    if (!cache) {
00201       createSymCache();
00202    }
00203    return lookupCachedSymbol(offset);
00204 
00205 #else
00206    Dyninst::Offset nearest = 0;
00207    bool has_nearest = false;
00208    Symbol_t nearest_sym;
00209 
00210    for (unsigned i=0; i < elf->e_shnum(); i++) 
00211    {
00212       Elf_X_Shdr shdr = elf->get_shdr(i);
00213       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
00214          continue;
00215       } 
00216 
00217       FOR_EACH_SYMBOL(shdr, symbol, str_buffer, idx) 
00218       {
00219          Dyninst::Offset sym_offset = getSymOffset(symbol, idx);
00220          if (sym_offset <= offset && (!has_nearest || sym_offset > nearest)) {
00221             unsigned str_loc = symbol.st_name(idx);
00222             MAKE_SYMBOL(str_buffer+str_loc, idx, shdr, nearest_sym);
00223             has_nearest = true;
00224             nearest = sym_offset;
00225          }
00226       }
00227    }
00228    if (!has_nearest) {
00229       GET_INVALID_SYMBOL(nearest_sym);
00230    }
00231 
00232    return nearest_sym;
00233 #endif
00234 }
00235 
00236 std::string SymElf::getInterpreterName()
00237 {
00238    for (unsigned i=0; i < elf->e_phnum(); i++)
00239    {
00240       Elf_X_Phdr phdr = elf->get_phdr(i);
00241       if (phdr.p_type() != PT_INTERP)
00242          continue;
00243       Dyninst::Offset off = (Dyninst::Offset) phdr.p_offset();
00244       
00245       if (fd != -1) {
00246          off_t old_offset = lseek(fd, 0, SEEK_CUR);
00247          lseek(fd, off, SEEK_SET);
00248          char interp_buffer[4096];
00249          ssize_t result;
00250          do {
00251             result = read(fd, interp_buffer, 4096);
00252          } while (result == -1 && errno == EINTR);
00253          lseek(fd, old_offset, SEEK_SET);
00254          if (result != -1) {
00255             return std::string(interp_buffer);
00256          }
00257       }
00258       else if (buffer) {
00259          return std::string(buffer + off);
00260       }
00261 
00262       //rawfile is expensive
00263       size_t filesize;
00264       const char *whole_file = elf->e_rawfile(filesize);
00265       if (filesize < off) {
00266          return std::string();
00267       }
00268       return std::string(whole_file + off);
00269    }
00270    return std::string();
00271 }
00272 
00273 unsigned SymElf::numSegments()
00274 {
00275    return elf->e_phnum();
00276 }
00277 
00278 bool SymElf::getSegment(unsigned num, SymSegment &seg)
00279 {
00280    if (num >= elf->e_phnum())
00281       return false;
00282 
00283    Elf_X_Phdr &phdr = elf->get_phdr(num);
00284    seg.file_offset = phdr.p_offset();
00285    seg.mem_addr = phdr.p_vaddr();
00286    seg.file_size = phdr.p_filesz();
00287    seg.mem_size = phdr.p_memsz();
00288    seg.type = phdr.p_type();
00289    seg.perms = phdr.p_flags() & 0x7;
00290    return true;
00291 }
00292 
00293 unsigned SymElf::getAddressWidth()
00294 {
00295    return elf->wordSize();
00296 }
00297 
00298 unsigned long SymElf::getSymbolSize(const Symbol_t &sym)
00299 {
00300    GET_SYMBOL(sym, shdr, symbol, name, idx);
00301    name = NULL; //Silence warnings
00302    unsigned long size = symbol.st_size(idx);
00303    return size;
00304 }
00305 
00306 Dyninst::Offset SymElf::getSymbolOffset(const Symbol_t &sym)
00307 {
00308    assert(sym.i2 != INVALID_SYM_CODE);
00309    if (sym.i2 != UNSET_INDEX_CODE) {
00310       int cache_index = sym.i2;
00311       return cache[cache_index].symaddress;
00312    }
00313 
00314    GET_SYMBOL(sym, shdr, symbols, name, idx);
00315    name = NULL; //Silence warnings
00316    return getSymOffset(symbols, idx);
00317 }
00318 
00319 Dyninst::Offset SymElf::getSymbolTOC(const Symbol_t &sym)
00320 {
00321    GET_SYMBOL(sym, shdr, symbols, name, idx);
00322    name = NULL; //Silence warnings
00323    return getSymTOC(symbols, idx);
00324 }
00325 
00326 std::string SymElf::getSymbolName(const Symbol_t &sym)
00327 {
00328    GET_SYMBOL(sym, shdr, symbols, name, idx);
00329    idx = 0; //Silence warnings
00330    return std::string(name);
00331 }
00332 
00333 std::string SymElf::getDemangledName(const Symbol_t &sym)
00334 {
00335    assert(sym.i2 != INVALID_SYM_CODE);
00336    int cache_index = -1;
00337    const char *name = NULL;
00338    if (sym.i2 != UNSET_INDEX_CODE) {
00339       cache_index = sym.i2;
00340       name = (const char *) sym.v1;
00341    }
00342    else {
00343       assert(0); //TODO: Lookup in cache
00344    }
00345 
00346    if (cache[cache_index].demangled_name)
00347       return std::string(cache[cache_index].demangled_name);
00348    char *res = P_cplus_demangle(name, false, true);
00349    if (!res) {
00350       //Try native demangler
00351       res = P_cplus_demangle(name, true, true);
00352    }
00353 
00354    cache[cache_index].demangled_name = res ? res : name;
00355    return cache[cache_index].demangled_name;
00356 }
00357 
00358 bool SymElf::isValidSymbol(const Symbol_t &sym)
00359 {
00360    return (sym.i2 != INVALID_SYM_CODE);
00361 }
00362 
00363 static int symcache_cmp(const void *a, const void *b)
00364 {
00365    SymCacheEntry *aa = (SymCacheEntry *) a;
00366    SymCacheEntry *bb = (SymCacheEntry *) b;
00367    if (aa->symaddress < bb->symaddress) return -1;
00368    else if (aa->symaddress > bb->symaddress) return 1;
00369    else return 0;
00370 }
00371 
00372 unsigned long SymElf::getSymOffset(const Elf_X_Sym &symbol, unsigned idx)
00373 {
00374    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
00375       unsigned long odp_addr = odp_section->sh_addr();
00376       unsigned long odp_size = odp_section->sh_size();
00377       const char *odp_data = (const char *) odp_section->get_data().d_buf();
00378       
00379       unsigned long sym_offset = symbol.st_value(idx);
00380       while (sym_offset >= odp_addr && sym_offset < odp_addr + odp_size)
00381          sym_offset = *((unsigned long *) (odp_data + sym_offset - odp_addr));
00382       return sym_offset;
00383    }
00384 
00385    return symbol.st_value(idx);
00386 }
00387 
00388 unsigned long SymElf::getSymTOC(const Elf_X_Sym &symbol, unsigned idx)
00389 {
00390    if (need_odp && symbol.ST_TYPE(idx) == STT_FUNC) {
00391       unsigned long odp_addr = odp_section->sh_addr();
00392       unsigned long odp_size = odp_section->sh_size();
00393       const char *odp_data = (const char *) odp_section->get_data().d_buf();
00394       unsigned long sym_offset = symbol.st_value(idx);
00395 
00396       if (sym_offset < odp_addr || (sym_offset >= odp_addr + odp_size)) 
00397          return 0;
00398 
00399       unsigned long toc = *((unsigned long *) (odp_data + (sym_offset - odp_addr + sizeof(long))));
00400       return toc;
00401    }
00402 
00403    return 0;
00404 }
00405 
00406 void SymElf::createSymCache()
00407 {
00408    unsigned long sym_count = 0, cur_sym = 0, cur_sec = 0;
00409    
00410    if (!cache && sym_sections)
00411       return;
00412 
00413    assert(!cache);
00414    assert(!sym_sections);
00415    for (unsigned i=0; i < elf->e_shnum(); i++) 
00416    {
00417       Elf_X_Shdr shdr = elf->get_shdr(i);
00418       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
00419          continue;
00420       }
00421       Elf_X_Data sym_data = shdr.get_data();
00422       Elf_X_Sym symbols = sym_data.get_sym();
00423       sym_count += symbols.count();
00424       sym_sections_size++;
00425    }
00426 
00427    sym_sections = (Elf_X_Shdr *) malloc(sym_sections_size * sizeof(Elf_X_Shdr));
00428    if (sym_count)
00429       cache = (SymCacheEntry *) malloc(sym_count * sizeof(SymCacheEntry));
00430    
00431    for (unsigned i=0; i < elf->e_shnum(); i++) 
00432    {
00433       Elf_X_Shdr shdr = elf->get_shdr(i);
00434       if (shdr.sh_type() != SHT_SYMTAB && shdr.sh_type() != SHT_DYNSYM) {
00435          continue;
00436       }
00437 
00438       sym_sections[cur_sec] = shdr;
00439       cur_sec++;
00440 
00441       FOR_EACH_SYMBOL(shdr, symbols, str_buffer, idx)
00442       {
00443          str_buffer = NULL; //Disable warnings
00444          unsigned char symtype = symbols.ST_TYPE(idx);
00445          if (symtype != STT_FUNC)
00446             continue;
00447          if (!symbols.st_value(idx))
00448             continue;
00449          cache[cur_sym].symaddress = getSymOffset(symbols, idx);
00450          cache[cur_sym].symloc = symbols.st_symptr(idx);
00451          cache[cur_sym].demangled_name = NULL;
00452          cur_sym++;
00453       }
00454    }
00455    cache_size = cur_sym;
00456    if (cache)
00457       cache = (SymCacheEntry *) realloc(cache, cur_sym  * sizeof(SymCacheEntry)); //Size reduction
00458    if (cache)
00459       qsort(cache, cache_size, sizeof(SymCacheEntry), symcache_cmp);
00460 }
00461 
00462 Symbol_t SymElf::lookupCachedSymbol(Dyninst::Offset off)
00463 {
00464    unsigned min = 0;
00465    unsigned max = cache_size;
00466    unsigned cur = cache_size / 2;
00467    Symbol_t ret;
00468    
00469    if (!cache) {
00470       ret.i2 = INVALID_SYM_CODE;
00471       return ret;
00472    }
00473 
00474    for (;;) {
00475       if (max == min || min+1 == max)
00476          break;
00477       Dyninst::Offset cur_off = cache[cur].symaddress;
00478       if (cur_off < off) {
00479          min = cur;
00480       }
00481       else if (cur_off > off) {
00482          max = cur;
00483       }
00484       else {
00485          break;
00486       }
00487       cur = (min + max) / 2;
00488    }
00489    void *sym_ptr = cache[cur].symloc;
00490 
00491    for (unsigned i=0; i<sym_sections_size; i++) {
00492       Elf_X_Shdr &shdr = sym_sections[i];
00493       Elf_X_Data data = shdr.get_data();
00494       
00495       void *data_start = data.d_buf();
00496       signed long sym_offset = ((unsigned char *) sym_ptr) - ((unsigned char *) data_start);
00497       if (sym_offset < 0 || sym_offset >= (signed long) data.d_size())
00498          continue;
00499 
00500       //Calculate symbol index
00501       Elf_X_Sym syms = data.get_sym();
00502       unsigned sym_idx = sym_offset / syms.st_entsize();
00503       
00504       //Lookup symbol name
00505       unsigned int str_index = shdr.sh_link();
00506       Elf_X_Shdr str_shdr = elf->get_shdr(str_index);
00507       Elf_X_Data str_data = str_shdr.get_data();
00508       const char *str_buffer = (const char *) str_data.d_buf();
00509       const char *name = str_buffer + syms.st_name(sym_idx);
00510       
00511       MAKE_SYMBOL(name, sym_idx, shdr, ret);
00512       SET_SYM_CACHEINDEX(ret, cur);
00513       return ret;
00514    }
00515    assert(0);
00516 
00517    return ret;
00518 }
00519 
00520 Section_t SymElf::getSectionByName(std::string name)
00521 {
00522    unsigned short stridx = elf->e_shstrndx();
00523    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
00524    Elf_X_Data strdata = strshdr.get_data();
00525    const char *names = (const char *) strdata.d_buf();
00526    Section_t ret;
00527    ret.i1 = -1;
00528 
00529    for (unsigned i=0; i < elf->e_shnum(); i++) 
00530    {
00531       Elf_X_Shdr shdr = elf->get_shdr(i);
00532       const char *sname = names + shdr.sh_name();
00533       if (name == sname) {
00534          ret.i1 = i;
00535          break;
00536       }
00537    }
00538    
00539    return ret;
00540 }
00541 
00542 Section_t SymElf::getSectionByAddress(Dyninst::Address addr)
00543 {
00544    Section_t ret;
00545    ret.i1 = -1;
00546 
00547    for (unsigned i=0; i < elf->e_shnum(); i++) 
00548    {
00549       Elf_X_Shdr shdr = elf->get_shdr(i);
00550       Dyninst::Address mem_start = shdr.sh_addr();
00551       unsigned long mem_size = shdr.sh_size();
00552       if (addr >= mem_start && addr < mem_start + mem_size) {
00553          ret.i1 = i;
00554          break;
00555       }
00556    }
00557    return ret;
00558 }
00559 
00560 Dyninst::Address SymElf::getSectionAddress(Section_t sec)
00561 {
00562    assert(isValidSection(sec));
00563    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
00564    
00565    return shdr.sh_addr();
00566 }
00567 
00568 std::string SymElf::getSectionName(Section_t sec)
00569 {
00570    assert(isValidSection(sec));
00571    Elf_X_Shdr shdr = elf->get_shdr(sec.i1);
00572 
00573    unsigned short stridx = elf->e_shstrndx();
00574    Elf_X_Shdr strshdr = elf->get_shdr(stridx);
00575    Elf_X_Data strdata = strshdr.get_data();
00576    const char *names = (const char *) strdata.d_buf();
00577 
00578    return std::string(names + shdr.sh_name());
00579 }
00580 
00581 bool SymElf::isValidSection(Section_t sec)
00582 {
00583    return (sec.i1 != -1);
00584 }
00585 
00586 Dyninst::Offset SymElf::imageOffset() 
00587 { 
00588    assert(0); return 0;
00589 };
00590 
00591 Dyninst::Offset SymElf::dataOffset() 
00592 { 
00593    assert(0); return 0; 
00594 }
00595 
00596 void *SymElf::getElfHandle() {
00597    return (void *) elf;
00598 }
00599 
00600 namespace Dyninst {
00601 extern map<string, SymElf *> *getSymelfCache();
00602 }
00603 
00604 SymElfFactory::SymElfFactory()
00605 {
00606    open_symelfs = Dyninst::getSymelfCache();
00607    assert(open_symelfs);
00608 }
00609 
00610 SymElfFactory::~SymElfFactory()
00611 {
00612 }
00613 
00614 SymReader *SymElfFactory::openSymbolReader(std::string pathname)
00615 {
00616    SymElf *se = NULL;
00617    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(pathname);
00618    if (i == open_symelfs->end()) {
00619       se = new SymElf(pathname);
00620       if (se->construction_error) {
00621          delete se;
00622          return NULL;
00623       }
00624       se->ref_count = 1;
00625       (*open_symelfs)[pathname] = se;
00626    }
00627    else {
00628       se = i->second;
00629       se->ref_count++;
00630    }
00631    return static_cast<SymReader *>(se);
00632 }
00633 
00634 SymReader *SymElfFactory::openSymbolReader(const char *buffer, unsigned long size)
00635 {
00636    SymElf *se = new SymElf(buffer, size);
00637    if (se->construction_error) {
00638       delete se;
00639       return NULL;
00640    }
00641    se->ref_count = 1;
00642    return static_cast<SymReader *>(se);
00643 }
00644 
00645 bool SymElfFactory::closeSymbolReader(SymReader *sr)
00646 {
00647    SymElf *ser = static_cast<SymElf *>(sr);
00648    std::map<std::string, SymElf *>::iterator i = open_symelfs->find(ser->file);
00649    if (i == open_symelfs->end()) {
00650       delete ser;
00651    }
00652 
00653    ser->ref_count--;
00654    if (ser->ref_count == 0) {
00655       open_symelfs->erase(i);
00656       delete ser;
00657    }
00658    return true;
00659 }
00660 
00661 int SymElf::getFD()
00662 {
00663   return fd;
00664   
00665 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 12 Jul 2013 for SymtabAPI by  doxygen 1.6.1