X-Git-Url: https://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fprof2%2Fsmap.C;fp=cinelerra-5.1%2Fprof2%2Fsmap.C;h=e6887e6bc8d11d8d14937a5aa2bee0af9210d7d0;hb=c053918502e6ec08433a0650ce37af35431f15b7;hp=0000000000000000000000000000000000000000;hpb=c5451a0a1f2a69ffea5e8b85d05787466f355481;p=goodguy%2Fcinelerra.git diff --git a/cinelerra-5.1/prof2/smap.C b/cinelerra-5.1/prof2/smap.C new file mode 100644 index 00000000..e6887e6b --- /dev/null +++ b/cinelerra-5.1/prof2/smap.C @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +#include +#include +#define HAVE_DECL_BASENAME 1 +#include + +// install binutils-dev +// c++ -Wall -I/usr/include/libiberty -g smap.C -llzma -liberty + +typedef uint64_t addr_t; + +class smap_t; + +class smap_t { + static void demangle(const char *cp, char *bp, int n) { + const char *dp = cplus_demangle(cp, DMGL_PARAMS+DMGL_ANSI); + strncpy(bp, (dp ? dp : cp), n); + } + + class chrbfr { + char *cp; + public: + unsigned char *ptr() { return (unsigned char *)cp; } + operator char*() { return cp; } + chrbfr(int n) { cp = new char[n]; } + ~chrbfr() { delete [] cp; } + }; + Elf64_Ehdr elf; + FILE *sfp; + char *shdrs, *strtbl; + addr_t adr_plt; + int is_rela; + size_t plt_sz; char *plts; + size_t rel_sz; char *rels; + size_t sym_sz, sym_entsize; + size_t dyn_sz, dyn_entsize; + char *symstr, *symtbl; + char *dynstr, *dyntbl; + addr_t vofs, pofs; + int init(); + void finit(); + char *unxz(unsigned char *ibfr, size_t isz, size_t &out); + void splt(); + int sect(int num); + + int rdtbl(char *tbl, off_t ofs, int sz) { + if( fseek(sfp, ofs, SEEK_SET) ) return -1; + if( fread(tbl, sz, 1, sfp) != 1 ) return -1; + return 0; + } + int ldtbl(char *&tbl, off_t ofs, int sz) { + if( !rdtbl(tbl=new char[sz], ofs, sz) ) return 0; + delete [] tbl; tbl = 0; return -1; + } +public: + int symbols(); + + smap_t(FILE *fp) { + sfp = fp; + shdrs = 0; strtbl = 0; + adr_plt = 0; is_rela = -1; + plt_sz = 0; plts = 0; + rel_sz = 0; rels = 0; + sym_sz = 0; sym_entsize = 0; + dyn_sz = 0; dyn_entsize = 0; + symstr = 0; symtbl = 0; + dynstr = 0; dyntbl = 0; + vofs = 0; pofs = 0; + } + ~smap_t() { + delete [] shdrs; delete [] strtbl; + delete [] plts; delete [] rels; + delete [] symstr; delete [] symtbl; + delete [] dynstr; delete [] dyntbl; + } +}; + + +char *smap_t:: +unxz(unsigned char *ibfr, size_t isz, size_t &out) +{ + size_t in = 0, lmt = ~0, osz = 8*isz; + unsigned char *obfr = new unsigned char[osz]; + out = 0; + for(;;) { + int err = lzma_stream_buffer_decode(&lmt,0,0, + ibfr,&in,isz, obfr,&out,osz); + if( !err ) return (char *)obfr; + if( err != LZMA_BUF_ERROR ) break; + size_t nsz = 2*osz; + unsigned char *nbfr = new unsigned char[nsz]; + memcpy(nbfr, obfr, osz); + delete [] obfr; obfr = nbfr; + osz = nsz; + } + delete [] obfr; + return 0; +} + +int smap_t:: +sect(int num) +{ + Elf64_Shdr *shdr = (Elf64_Shdr *)(shdrs + num * elf.e_shentsize); + switch( shdr->sh_type ) { + case SHT_REL: + case SHT_RELA: { + if( !strtbl ) return 0; + const char *tp = strtbl + shdr->sh_name; + is_rela = shdr->sh_type == SHT_RELA ? 1 : 0; + if( strcmp(tp, is_rela ? ".rela.plt" : ".rel.plt") ) return 0; + int n = shdr->sh_entsize; + int esz = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel); + if( n < esz ) return -1; + if( (rel_sz = shdr->sh_size) <= 0 ) return -1; + return ldtbl(rels, shdr->sh_offset, rel_sz); + } + case SHT_PROGBITS: { + if( !strtbl ) return 0; + const char *tp = strtbl + shdr->sh_name; + if( !strcmp(tp, ".plt") ) { + if( (plt_sz = shdr->sh_size) <= 0 ) return -1; + adr_plt = shdr->sh_addr; + return ldtbl(plts, shdr->sh_offset, plt_sz); + } + if( !strcmp(tp, ".gnu_debugdata") ) { + size_t isz = shdr->sh_size, out = 0; + if( !isz ) return -1; + chrbfr ibfr(isz); + if( rdtbl(ibfr, shdr->sh_offset, isz) ) return -1; + char *obfr = unxz(ibfr.ptr(), isz, out); + int ret = -1; + if( obfr && out > 0 ) { + FILE *fp = fmemopen(obfr, out, "r"); + smap_t dmap(fp); + ret = dmap.symbols(); + fclose(fp); + } + delete [] obfr; + return ret; + } + return 0; + } + case SHT_SYMTAB: + case SHT_DYNSYM: { + size_t &esz = shdr->sh_type == SHT_SYMTAB ? sym_entsize : dyn_entsize; + esz = shdr->sh_entsize; + if( esz < sizeof(Elf64_Sym) ) return -1; + int strtab = shdr->sh_link; + if( strtab >= elf.e_shnum ) return -1; + Elf64_Shdr *strhdr = (Elf64_Shdr *)(shdrs + strtab * elf.e_shentsize); + int ssz = strhdr->sh_size; + if( ssz <= 0 ) return -1; + char *&str = shdr->sh_type == SHT_SYMTAB ? symstr : dynstr; + if( ldtbl(str, strhdr->sh_offset, ssz) ) return -1; + size_t &syz = shdr->sh_type == SHT_SYMTAB ? sym_sz : dyn_sz; + char *&tbl = shdr->sh_type == SHT_SYMTAB ? symtbl : dyntbl; + if( ldtbl(tbl, shdr->sh_offset, syz=shdr->sh_size) ) return -1; + int nsy = syz / esz, nsyms = 0; + /**/ printf("\n[section %3d] contains [%d] symbols @ 0x%016lx\n", num, nsy, pofs); + for( int i=0; ist_name, snm, sizeof(snm)); + int bind = ELF64_ST_BIND(sym->st_info); + switch( bind ) { + case STB_LOCAL: break; + case STB_GLOBAL: break; + case STB_WEAK: break; + default: continue; + } + int type = ELF32_ST_TYPE(sym->st_info); + switch( type ) { + case STT_FUNC: break; +/**/ case STT_OBJECT: break; // for r_debug + default: continue; + } + int ndx = sym->st_shndx; + if( ndx == SHN_UNDEF ) continue; + if( ndx >= SHN_LORESERVE ) continue; + addr_t adr = sym->st_value - pofs; + /**/ int tch = (type == STT_FUNC ? "tTW": "dDW")[bind]; + /**/ printf("%016lx %c %s\n", adr, tch, snm); + ++nsyms; + } + return nsyms; + } + default: + break; + } + return 0; +} + +int smap_t:: +init() +{ + if( fread(&elf, sizeof(elf), 1, sfp) != 1 || + memcmp(elf.e_ident, ELFMAG, SELFMAG) != 0 ) return -1; + // scan region map + int psz = elf.e_phentsize, pct = elf.e_phnum; + if( psz < (int) sizeof(Elf64_Phdr) || pct < 1 ) return -1; + if( fseek(sfp, elf.e_phoff, SEEK_SET) ) return -1; + chrbfr pbfr(psz); + Elf64_Phdr *phdr = (Elf64_Phdr *) pbfr.ptr(); + while( --pct >= 0 ) { + if( fread(pbfr, psz, 1, sfp) != 1 ) break; + if( phdr->p_type == PT_LOAD && phdr->p_offset == 0 ) { + vofs = phdr->p_vaddr; + pofs = phdr->p_paddr; + break; + } + } + // scan sections + int n = elf.e_shnum, esz = elf.e_shentsize; + if( n <= 0 || esz < (int)sizeof(Elf64_Shdr) ) return -1; + if( ldtbl(shdrs, elf.e_shoff, n*esz) ) return -1; + // load strtab + int sndx = elf.e_shstrndx; + if( sndx >= n ) return -1; + Elf64_Shdr *stbl = (Elf64_Shdr *)(shdrs + sndx * elf.e_shentsize); + return ldtbl(strtbl, stbl->sh_offset, stbl->sh_size); +} + +void smap_t:: +finit() +{ + delete [] strtbl; strtbl = 0; + delete [] shdrs; shdrs = 0; +} + +void smap_t:: +splt() +{ + if( !plts || !rels ) return; + if( !dynstr || !dyntbl ) return; + if( is_rela < 0 ) return; + int rel_entsize = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel); + int plt_entsize = 0x10; + unsigned char *bp = (unsigned char *)plts; + for( uint64_t plt_ofs=plt_entsize ; plt_ofsr_offset : rp->r_offset; + info = is_rela ? rap->r_info : rp->r_info; + addend = is_rela ? rap->r_addend : 0; + if( addr == ofs ) found = 1; + } + if( !found ) continue; + int sndx = ELF64_R_SYM(info); + uint64_t dyn_ofs = sndx * dyn_entsize; + if( dyn_ofs >= dyn_sz ) continue; + Elf64_Sym *sym = (Elf64_Sym *)(dyntbl + dyn_ofs); + const char *snm = dynstr + sym->st_name; + string pnm(snm); pnm += "@plt"; + if( addend ) { + char adn[64]; int op = addend>=0 ? '+' : '-'; + snprintf(adn,sizeof(adn),"%c%ld",op,addend>=0 ? addend : -addend); + pnm += adn; + } + addr_t adr = adr_plt + plt_ofs - pofs; + /**/ printf("%016lx %c %s\n", adr, 't', pnm.c_str()); + } +} + +int smap_t:: +symbols() +{ + if( init() >= 0 ) { + int n = elf.e_shnum; + for( int i=0; i