13 #define HAVE_DECL_BASENAME 1
16 // install binutils-dev
17 // c++ -Wall -I/usr/include/libiberty -g smap.C -llzma -liberty
19 typedef uint64_t addr_t;
24 static void demangle(const char *cp, char *bp, int n) {
25 const char *dp = cplus_demangle(cp, DMGL_PARAMS+DMGL_ANSI);
26 strncpy(bp, (dp ? dp : cp), n);
32 unsigned char *ptr() { return (unsigned char *)cp; }
33 operator char*() { return cp; }
34 chrbfr(int n) { cp = new char[n]; }
35 ~chrbfr() { delete [] cp; }
42 size_t plt_sz; char *plts;
43 size_t rel_sz; char *rels;
44 size_t sym_sz, sym_entsize;
45 size_t dyn_sz, dyn_entsize;
46 char *symstr, *symtbl;
47 char *dynstr, *dyntbl;
51 char *unxz(unsigned char *ibfr, size_t isz, size_t &out);
55 int rdtbl(char *tbl, off_t ofs, int sz) {
56 if( fseek(sfp, ofs, SEEK_SET) ) return -1;
57 if( fread(tbl, sz, 1, sfp) != 1 ) return -1;
60 int ldtbl(char *&tbl, off_t ofs, int sz) {
61 if( !rdtbl(tbl=new char[sz], ofs, sz) ) return 0;
62 delete [] tbl; tbl = 0; return -1;
69 shdrs = 0; strtbl = 0;
70 adr_plt = 0; is_rela = -1;
73 sym_sz = 0; sym_entsize = 0;
74 dyn_sz = 0; dyn_entsize = 0;
75 symstr = 0; symtbl = 0;
76 dynstr = 0; dyntbl = 0;
80 delete [] shdrs; delete [] strtbl;
81 delete [] plts; delete [] rels;
82 delete [] symstr; delete [] symtbl;
83 delete [] dynstr; delete [] dyntbl;
89 unxz(unsigned char *ibfr, size_t isz, size_t &out)
91 size_t in = 0, lmt = ~0, osz = 8*isz;
92 unsigned char *obfr = new unsigned char[osz];
95 int err = lzma_stream_buffer_decode(&lmt,0,0,
96 ibfr,&in,isz, obfr,&out,osz);
97 if( !err ) return (char *)obfr;
98 if( err != LZMA_BUF_ERROR ) break;
100 unsigned char *nbfr = new unsigned char[nsz];
101 memcpy(nbfr, obfr, osz);
102 delete [] obfr; obfr = nbfr;
112 Elf64_Shdr *shdr = (Elf64_Shdr *)(shdrs + num * elf.e_shentsize);
113 switch( shdr->sh_type ) {
116 if( !strtbl ) return 0;
117 const char *tp = strtbl + shdr->sh_name;
118 is_rela = shdr->sh_type == SHT_RELA ? 1 : 0;
119 if( strcmp(tp, is_rela ? ".rela.plt" : ".rel.plt") ) return 0;
120 int n = shdr->sh_entsize;
121 int esz = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
122 if( n < esz ) return -1;
123 if( (rel_sz = shdr->sh_size) <= 0 ) return -1;
124 return ldtbl(rels, shdr->sh_offset, rel_sz);
127 if( !strtbl ) return 0;
128 const char *tp = strtbl + shdr->sh_name;
129 if( !strcmp(tp, ".plt") ) {
130 if( (plt_sz = shdr->sh_size) <= 0 ) return -1;
131 adr_plt = shdr->sh_addr;
132 return ldtbl(plts, shdr->sh_offset, plt_sz);
134 if( !strcmp(tp, ".gnu_debugdata") ) {
135 size_t isz = shdr->sh_size, out = 0;
136 if( !isz ) return -1;
138 if( rdtbl(ibfr, shdr->sh_offset, isz) ) return -1;
139 char *obfr = unxz(ibfr.ptr(), isz, out);
141 if( obfr && out > 0 ) {
142 FILE *fp = fmemopen(obfr, out, "r");
144 ret = dmap.symbols();
154 size_t &esz = shdr->sh_type == SHT_SYMTAB ? sym_entsize : dyn_entsize;
155 esz = shdr->sh_entsize;
156 if( esz < sizeof(Elf64_Sym) ) return -1;
157 int strtab = shdr->sh_link;
158 if( strtab >= elf.e_shnum ) return -1;
159 Elf64_Shdr *strhdr = (Elf64_Shdr *)(shdrs + strtab * elf.e_shentsize);
160 int ssz = strhdr->sh_size;
161 if( ssz <= 0 ) return -1;
162 char *&str = shdr->sh_type == SHT_SYMTAB ? symstr : dynstr;
163 if( ldtbl(str, strhdr->sh_offset, ssz) ) return -1;
164 size_t &syz = shdr->sh_type == SHT_SYMTAB ? sym_sz : dyn_sz;
165 char *&tbl = shdr->sh_type == SHT_SYMTAB ? symtbl : dyntbl;
166 if( ldtbl(tbl, shdr->sh_offset, syz=shdr->sh_size) ) return -1;
167 int nsy = syz / esz, nsyms = 0;
168 /**/ printf("\n[section %3d] contains [%d] symbols @ 0x%016lx\n", num, nsy, pofs);
169 for( int i=0; i<nsy; ++i ) {
170 Elf64_Sym *sym = (Elf64_Sym *)(tbl + esz*i);
172 demangle(str + sym->st_name, snm, sizeof(snm));
173 int bind = ELF64_ST_BIND(sym->st_info);
175 case STB_LOCAL: break;
176 case STB_GLOBAL: break;
177 case STB_WEAK: break;
180 int type = ELF32_ST_TYPE(sym->st_info);
182 case STT_FUNC: break;
183 /**/ case STT_OBJECT: break; // for r_debug
186 int ndx = sym->st_shndx;
187 if( ndx == SHN_UNDEF ) continue;
188 if( ndx >= SHN_LORESERVE ) continue;
189 addr_t adr = sym->st_value - pofs;
190 /**/ int tch = (type == STT_FUNC ? "tTW": "dDW")[bind];
191 /**/ printf("%016lx %c %s\n", adr, tch, snm);
205 if( fread(&elf, sizeof(elf), 1, sfp) != 1 ||
206 memcmp(elf.e_ident, ELFMAG, SELFMAG) != 0 ) return -1;
208 int psz = elf.e_phentsize, pct = elf.e_phnum;
209 if( psz < (int) sizeof(Elf64_Phdr) || pct < 1 ) return -1;
210 if( fseek(sfp, elf.e_phoff, SEEK_SET) ) return -1;
212 Elf64_Phdr *phdr = (Elf64_Phdr *) pbfr.ptr();
213 while( --pct >= 0 ) {
214 if( fread(pbfr, psz, 1, sfp) != 1 ) break;
215 if( phdr->p_type == PT_LOAD && phdr->p_offset == 0 ) {
216 vofs = phdr->p_vaddr;
217 pofs = phdr->p_paddr;
222 int n = elf.e_shnum, esz = elf.e_shentsize;
223 if( n <= 0 || esz < (int)sizeof(Elf64_Shdr) ) return -1;
224 if( ldtbl(shdrs, elf.e_shoff, n*esz) ) return -1;
226 int sndx = elf.e_shstrndx;
227 if( sndx >= n ) return -1;
228 Elf64_Shdr *stbl = (Elf64_Shdr *)(shdrs + sndx * elf.e_shentsize);
229 return ldtbl(strtbl, stbl->sh_offset, stbl->sh_size);
235 delete [] strtbl; strtbl = 0;
236 delete [] shdrs; shdrs = 0;
242 if( !plts || !rels ) return;
243 if( !dynstr || !dyntbl ) return;
244 if( is_rela < 0 ) return;
245 int rel_entsize = is_rela ? sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
246 int plt_entsize = 0x10;
247 unsigned char *bp = (unsigned char *)plts;
248 for( uint64_t plt_ofs=plt_entsize ; plt_ofs<plt_sz; plt_ofs+=plt_entsize ) {
249 unsigned char *cp = bp + plt_ofs;
250 if( *cp++ != 0xff ) continue; // opcode jmp rel ind
251 if( *cp++ != 0x25 ) continue;
253 for( int k=0; k<32; k+=8 ) { addr_t by=*cp++; ofs |= by<<k; }
254 ofs += (cp - bp) + adr_plt;
255 uint64_t info = 0; addr_t addr = 0; int64_t addend = 0;
256 unsigned char *dp = (unsigned char *)rels; int found = 0;
257 for( unsigned rel_ofs=0; !found && rel_ofs<rel_sz; rel_ofs+=rel_entsize ) {
258 Elf64_Rel *rp = (Elf64_Rel *)(dp + rel_ofs);
259 Elf64_Rela *rap = (Elf64_Rela *)rp;
260 addr = is_rela ? rap->r_offset : rp->r_offset;
261 info = is_rela ? rap->r_info : rp->r_info;
262 addend = is_rela ? rap->r_addend : 0;
263 if( addr == ofs ) found = 1;
265 if( !found ) continue;
266 int sndx = ELF64_R_SYM(info);
267 uint64_t dyn_ofs = sndx * dyn_entsize;
268 if( dyn_ofs >= dyn_sz ) continue;
269 Elf64_Sym *sym = (Elf64_Sym *)(dyntbl + dyn_ofs);
270 const char *snm = dynstr + sym->st_name;
271 string pnm(snm); pnm += "@plt";
273 char adn[64]; int op = addend>=0 ? '+' : '-';
274 snprintf(adn,sizeof(adn),"%c%ld",op,addend>=0 ? addend : -addend);
277 addr_t adr = adr_plt + plt_ofs - pofs;
278 /**/ printf("%016lx %c %s\n", adr, 't', pnm.c_str());
287 for( int i=0; i<n; ++i ) sect(i);
294 int main(int ac, char **av)