forgot relative patch qualification for tiff patches
[goodguy/cinelerra.git] / cinelerra-5.1 / prof2 / smap.C
1 #include<stdio.h>
2 #include<stdint.h>
3 #include<stdlib.h>
4 #include<string.h>
5 #include<unistd.h>
6 #include<fcntl.h>
7
8 #include<string>
9 using namespace std;
10
11 #include<elf.h>
12 #include<lzma.h>
13 #define HAVE_DECL_BASENAME 1
14 #include<demangle.h>
15
16 // install binutils-dev
17 // c++ -Wall -I/usr/include/libiberty -g smap.C -llzma -liberty
18
19 typedef uint64_t addr_t;
20
21 class smap_t;
22
23 class smap_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);
27   }
28
29   class chrbfr {
30     char *cp;
31   public:
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; }
36   };
37   Elf64_Ehdr elf;
38   FILE *sfp;
39   char *shdrs, *strtbl;
40   addr_t adr_plt;
41   int is_rela;
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;
48   addr_t vofs, pofs;
49   int init();
50   void finit();
51   char *unxz(unsigned char *ibfr, size_t isz, size_t &out);
52   void splt();
53   int sect(int num);
54
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;
58     return 0;
59   }
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;
63   }
64 public:
65   int symbols();
66
67   smap_t(FILE *fp) {
68     sfp = fp;
69     shdrs = 0;   strtbl = 0;
70     adr_plt = 0; is_rela = -1;
71     plt_sz = 0;  plts = 0;
72     rel_sz = 0;  rels = 0;
73     sym_sz = 0;  sym_entsize = 0;
74     dyn_sz = 0;  dyn_entsize = 0;
75     symstr = 0;  symtbl = 0;
76     dynstr = 0;  dyntbl = 0;
77     vofs = 0;    pofs = 0;
78   }
79   ~smap_t() {
80     delete [] shdrs;  delete [] strtbl;
81     delete [] plts;   delete [] rels;
82     delete [] symstr; delete [] symtbl;
83     delete [] dynstr; delete [] dyntbl;
84   }
85 };
86
87
88 char *smap_t::
89 unxz(unsigned char *ibfr, size_t isz, size_t &out)
90 {
91   size_t in = 0, lmt = ~0, osz = 8*isz;
92   unsigned char *obfr = new unsigned char[osz];
93   out = 0;
94   for(;;) {
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;
99     size_t nsz = 2*osz;
100     unsigned char *nbfr = new unsigned char[nsz];
101     memcpy(nbfr, obfr, osz);
102     delete [] obfr;  obfr = nbfr;
103     osz = nsz;
104   }
105   delete [] obfr;
106   return 0;
107 }
108
109 int smap_t::
110 sect(int num)
111 {
112   Elf64_Shdr *shdr = (Elf64_Shdr *)(shdrs + num * elf.e_shentsize);
113   switch( shdr->sh_type ) {
114   case SHT_REL:
115   case SHT_RELA: {
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);
125   }  
126   case SHT_PROGBITS: {
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);
133     }
134     if( !strcmp(tp, ".gnu_debugdata") ) {
135       size_t isz = shdr->sh_size, out = 0;
136       if( !isz ) return -1;
137       chrbfr ibfr(isz);
138       if( rdtbl(ibfr, shdr->sh_offset, isz) ) return -1;
139       char *obfr = unxz(ibfr.ptr(), isz, out);
140       int ret = -1;
141       if( obfr && out > 0 ) {
142         FILE *fp = fmemopen(obfr, out, "r");
143         smap_t dmap(fp);
144         ret = dmap.symbols();
145         fclose(fp);
146       }
147       delete [] obfr;
148       return ret;
149     }
150     return 0;
151   }
152   case SHT_SYMTAB:
153   case SHT_DYNSYM: {
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);
171       char snm[512];
172       demangle(str + sym->st_name, snm, sizeof(snm));
173       int bind = ELF64_ST_BIND(sym->st_info);
174       switch( bind ) {
175       case STB_LOCAL:   break;
176       case STB_GLOBAL:  break;
177       case STB_WEAK:    break;
178       default: continue;
179       }
180       int type = ELF32_ST_TYPE(sym->st_info);
181       switch( type ) {
182       case STT_FUNC:    break;
183 /**/  case STT_OBJECT:  break;  // for r_debug
184       default: continue;
185       }
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);
192       ++nsyms;
193     }
194     return nsyms;
195   }
196   default:
197     break;
198   }
199   return 0;
200 }
201
202 int smap_t::
203 init()
204 {
205   if( fread(&elf, sizeof(elf), 1, sfp) != 1 ||
206       memcmp(elf.e_ident, ELFMAG, SELFMAG) != 0 ) return -1;
207   // scan region map
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;
211   chrbfr pbfr(psz);
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;
218       break;
219     }
220   }
221   // scan sections
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;
225   // load strtab
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);
230 }
231
232 void smap_t::
233 finit()
234 {
235   delete [] strtbl; strtbl = 0;
236   delete [] shdrs;  shdrs = 0;
237 }
238
239 void smap_t::
240 splt()
241 {
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;
252     addr_t ofs = 0;
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;
264     }
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";
272     if( addend ) {
273       char adn[64]; int op = addend>=0 ? '+' : '-';
274       snprintf(adn,sizeof(adn),"%c%ld",op,addend>=0 ? addend : -addend);
275       pnm += adn;
276     }
277     addr_t adr = adr_plt + plt_ofs - pofs;
278     /**/ printf("%016lx %c %s\n", adr, 't', pnm.c_str());
279   }
280 }
281
282 int smap_t::
283 symbols()
284 {
285   if( init() >= 0 ) {
286     int n = elf.e_shnum;
287     for( int i=0; i<n; ++i ) sect(i);
288     splt();
289   }
290   return 0;
291 }
292
293
294 int main(int ac, char **av)
295 {
296   smap_t smap(stdin);
297   smap.symbols();
298   return 0;
299 }
300