00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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;
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;
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;
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;
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);
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
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;
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));
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
00501 Elf_X_Sym syms = data.get_sym();
00502 unsigned sym_idx = sym_offset / syms.st_entsize();
00503
00504
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 }