aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/perf_counter/util/symbol.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-06-02 23:54:33 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-03 03:58:52 -0400
commit8ce998d6693bd02ab3b74ee1cc303ecb1fa9b514 (patch)
tree425ed52012c706d6b7465f5c319e9f9891edc701 /Documentation/perf_counter/util/symbol.c
parenta32881066e58346f2901afe0ebdfbf0c562877e5 (diff)
perf_counter tools: Cover PLT symbols too
PLT, the Program Linking Table, is used with the dynamic linker to allow PIC code in executables and shared objects to figure out where functions are in other shared objects. It is one of the sources of unknown/unresolved symbols - this patch does what binutils figures out when you ask it to disassembly. (objdump -S) Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: John Kacur <jkacur@redhat.com> Cc: Stephane Eranian <eranian@googlemail.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter/util/symbol.c')
-rw-r--r--Documentation/perf_counter/util/symbol.c143
1 files changed, 138 insertions, 5 deletions
diff --git a/Documentation/perf_counter/util/symbol.c b/Documentation/perf_counter/util/symbol.c
index 039931fcb1b5..d52a1ae5342a 100644
--- a/Documentation/perf_counter/util/symbol.c
+++ b/Documentation/perf_counter/util/symbol.c
@@ -258,6 +258,117 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
258 return sec; 258 return sec;
259} 259}
260 260
261#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
262 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
263 idx < nr_entries; \
264 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
265
266#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
267 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
268 idx < nr_entries; \
269 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
270
271static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
272 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
273 GElf_Shdr *shdr_dynsym,
274 size_t dynsym_idx)
275{
276 uint32_t nr_rel_entries, idx;
277 GElf_Sym sym;
278 __u64 plt_offset;
279 GElf_Shdr shdr_plt;
280 struct symbol *f;
281 GElf_Shdr shdr_rel_plt;
282 Elf_Data *reldata, *syms, *symstrs;
283 Elf_Scn *scn_plt_rel, *scn_symstrs;
284 char sympltname[1024];
285 int nr = 0, symidx;
286
287 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
288 ".rela.plt", NULL);
289 if (scn_plt_rel == NULL) {
290 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
291 ".rel.plt", NULL);
292 if (scn_plt_rel == NULL)
293 return 0;
294 }
295
296 if (shdr_rel_plt.sh_link != dynsym_idx)
297 return 0;
298
299 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
300 return 0;
301
302 /*
303 * Fetch the relocation section to find the indexes to the GOT
304 * and the symbols in the .dynsym they refer to.
305 */
306 reldata = elf_getdata(scn_plt_rel, NULL);
307 if (reldata == NULL)
308 return -1;
309
310 syms = elf_getdata(scn_dynsym, NULL);
311 if (syms == NULL)
312 return -1;
313
314 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
315 if (scn_symstrs == NULL)
316 return -1;
317
318 symstrs = elf_getdata(scn_symstrs, NULL);
319 if (symstrs == NULL)
320 return -1;
321
322 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
323 plt_offset = shdr_plt.sh_offset;
324
325 if (shdr_rel_plt.sh_type == SHT_RELA) {
326 GElf_Rela pos_mem, *pos;
327
328 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
329 nr_rel_entries) {
330 symidx = GELF_R_SYM(pos->r_info);
331 plt_offset += shdr_plt.sh_entsize;
332 gelf_getsym(syms, symidx, &sym);
333 snprintf(sympltname, sizeof(sympltname),
334 "%s@plt", elf_sym__name(&sym, symstrs));
335
336 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
337 sympltname, self->sym_priv_size);
338 if (!f)
339 return -1;
340
341 dso__insert_symbol(self, f);
342 ++nr;
343 }
344 } else if (shdr_rel_plt.sh_type == SHT_REL) {
345 GElf_Rel pos_mem, *pos;
346 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
347 nr_rel_entries) {
348 symidx = GELF_R_SYM(pos->r_info);
349 plt_offset += shdr_plt.sh_entsize;
350 gelf_getsym(syms, symidx, &sym);
351 snprintf(sympltname, sizeof(sympltname),
352 "%s@plt", elf_sym__name(&sym, symstrs));
353
354 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
355 sympltname, self->sym_priv_size);
356 if (!f)
357 return -1;
358
359 dso__insert_symbol(self, f);
360 ++nr;
361 }
362 } else {
363 /*
364 * TODO: There are still one more shdr_rel_plt.sh_type
365 * I have to investigate, but probably should be ignored.
366 */
367 }
368
369 return nr;
370}
371
261static int dso__load_sym(struct dso *self, int fd, const char *name, 372static int dso__load_sym(struct dso *self, int fd, const char *name,
262 symbol_filter_t filter) 373 symbol_filter_t filter)
263{ 374{
@@ -269,8 +380,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
269 GElf_Shdr shdr; 380 GElf_Shdr shdr;
270 Elf_Data *syms; 381 Elf_Data *syms;
271 GElf_Sym sym; 382 GElf_Sym sym;
272 Elf_Scn *sec; 383 Elf_Scn *sec, *sec_dynsym;
273 Elf *elf; 384 Elf *elf;
385 size_t dynsym_idx;
274 int nr = 0; 386 int nr = 0;
275 387
276 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 388 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
@@ -285,12 +397,33 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
285 goto out_elf_end; 397 goto out_elf_end;
286 } 398 }
287 399
400 /*
401 * We need to check if we have a .dynsym, so that we can handle the
402 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
403 * .dynsym or .symtab)
404 */
405 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
406 ".dynsym", &dynsym_idx);
407 if (sec_dynsym != NULL) {
408 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
409 sec_dynsym, &shdr,
410 dynsym_idx);
411 if (nr < 0)
412 goto out_elf_end;
413 }
414
415 /*
416 * But if we have a full .symtab (that is a superset of .dynsym) we
417 * should add the symbols not in the .dynsyn
418 */
288 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 419 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
289 if (sec == NULL) 420 if (sec == NULL) {
290 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 421 if (sec_dynsym == NULL)
422 goto out_elf_end;
291 423
292 if (sec == NULL) 424 sec = sec_dynsym;
293 goto out_elf_end; 425 gelf_getshdr(sec, &shdr);
426 }
294 427
295 syms = elf_getdata(sec, NULL); 428 syms = elf_getdata(sec, NULL);
296 if (syms == NULL) 429 if (syms == NULL)