File ltrace-ppc64le_git10.patch of Package ltrace
--- libltrace.c.ori
+++ libltrace.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2009 Juan Cespedes
*
* This program is free software; you can redistribute it and/or
@@ -136,9 +136,9 @@ ltrace_init(int argc, char **argv) {
if (command) {
/* Check that the binary ABI is supported before
* calling execute_program. */
- struct ltelf lte = {};
- open_elf(<e, command);
- do_close_elf(<e);
+ struct ltelf lte;
+ ltelf_init(<e, command);
+ ltelf_destroy(<e);
pid_t pid = execute_program(command, argv);
struct Process *proc = open_program(command, pid);
--- ltrace-elf.c.ori
+++ ltrace-elf.c
@@ -318,8 +318,9 @@ need_data(Elf_Data *data, GElf_Xword offset, GElf_Xword size)
#undef DEF_READER
int
-open_elf(struct ltelf *lte, const char *filename)
+ltelf_init(struct ltelf *lte, const char *filename)
{
+ memset(lte, 0, sizeof *lte);
lte->fd = open(filename, O_RDONLY);
if (lte->fd == -1)
return 1;
@@ -369,9 +370,20 @@ open_elf(struct ltelf *lte, const char *filename)
exit(EXIT_FAILURE);
}
+ VECT_INIT(<e->plt_relocs, GElf_Rela);
+
return 0;
}
+void
+ltelf_destroy(struct ltelf *lte)
+{
+ debug(DEBUG_FUNCTION, "close_elf()");
+ elf_end(lte->elf);
+ close(lte->fd);
+ VECT_DESTROY(<e->plt_relocs, GElf_Rela, NULL, NULL);
+}
+
static void
read_symbol_table(struct ltelf *lte, const char *filename,
Elf_Scn *scn, GElf_Shdr *shdr, const char *name,
@@ -409,13 +421,86 @@ read_symbol_table(struct ltelf *lte, const char *filename,
}
static int
-do_init_elf(struct ltelf *lte, const char *filename)
+rel_to_rela(struct ltelf *lte, const GElf_Rel *rel, GElf_Rela *rela)
+{
+ rela->r_offset = rel->r_offset;
+ rela->r_info = rel->r_info;
+
+ Elf_Scn *sec;
+ GElf_Shdr shdr;
+ if (elf_get_section_covering(lte, rel->r_offset, &sec, &shdr) < 0
+ || sec == NULL)
+ return -1;
+
+ Elf_Data *data = elf_loaddata(sec, &shdr);
+ if (data == NULL)
+ return -1;
+
+ GElf_Xword offset = rel->r_offset - shdr.sh_addr - data->d_off;
+ uint64_t value;
+ if (lte->ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ uint32_t tmp;
+ if (elf_read_u32(data, offset, &tmp) < 0)
+ return -1;
+ value = tmp;
+ } else if (elf_read_u64(data, offset, &value) < 0) {
+ return -1;
+ }
+
+ rela->r_addend = value;
+ return 0;
+}
+
+int
+read_relplt(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
+ struct vect *rela_vec)
+{
+ if (vect_reserve_additional(rela_vec, lte->ehdr.e_shnum) < 0)
+ return -1;
+
+ Elf_Data *relplt = elf_loaddata(scn, shdr);
+ if (relplt == NULL) {
+ fprintf(stderr, "Couldn't load .rel*.plt data.\n");
+ return -1;
+ }
+
+ if ((shdr->sh_size % shdr->sh_entsize) != 0) {
+ fprintf(stderr, ".rel*.plt size (%" PRIx64 "d) not a multiple "
+ "of its sh_entsize (%" PRIx64 "d).\n",
+ shdr->sh_size, shdr->sh_entsize);
+ return -1;
+ }
+
+ GElf_Xword relplt_count = shdr->sh_size / shdr->sh_entsize;
+ GElf_Xword i;
+ for (i = 0; i < relplt_count; ++i) {
+ GElf_Rela rela;
+ if (relplt->d_type == ELF_T_REL) {
+ GElf_Rel rel;
+ if (gelf_getrel(relplt, i, &rel) == NULL
+ || rel_to_rela(lte, &rel, &rela) < 0)
+ return -1;
+
+ } else if (gelf_getrela(relplt, i, &rela) == NULL) {
+ return -1;
+ }
+
+ if (VECT_PUSHBACK(rela_vec, &rela) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ltelf_read_elf(struct ltelf *lte, const char *filename)
{
int i;
GElf_Addr relplt_addr = 0;
GElf_Addr soname_offset = 0;
+ GElf_Xword relplt_size = 0;
- debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
+ debug(DEBUG_FUNCTION, "ltelf_read_elf(filename=%s)", filename);
debug(1, "Reading ELF from %s...", filename);
for (i = 1; i < lte->ehdr.e_shnum; ++i) {
@@ -474,7 +559,7 @@ do_init_elf(struct ltelf *lte, const char *filename)
if (dyn.d_tag == DT_JMPREL)
relplt_addr = dyn.d_un.d_ptr;
else if (dyn.d_tag == DT_PLTRELSZ)
- lte->relplt_size = dyn.d_un.d_val;
+ relplt_size = dyn.d_un.d_val;
else if (dyn.d_tag == DT_SONAME)
soname_offset = dyn.d_un.d_val;
}
@@ -507,14 +592,9 @@ do_init_elf(struct ltelf *lte, const char *filename)
if (!relplt_addr || !lte->plt_addr) {
debug(1, "%s has no PLT relocations", filename);
- lte->relplt = NULL;
- lte->relplt_count = 0;
- } else if (lte->relplt_size == 0) {
+ } else if (relplt_size == 0) {
debug(1, "%s has unknown PLT size", filename);
- lte->relplt = NULL;
- lte->relplt_count = 0;
} else {
-
for (i = 1; i < lte->ehdr.e_shnum; ++i) {
Elf_Scn *scn;
GElf_Shdr shdr;
@@ -527,12 +607,9 @@ do_init_elf(struct ltelf *lte, const char *filename)
exit(EXIT_FAILURE);
}
if (shdr.sh_addr == relplt_addr
- && shdr.sh_size == lte->relplt_size) {
- lte->relplt = elf_getdata(scn, NULL);
- lte->relplt_count =
- shdr.sh_size / shdr.sh_entsize;
- if (lte->relplt == NULL
- || elf_getdata(scn, lte->relplt) != NULL) {
+ && shdr.sh_size == relplt_size) {
+ if (read_relplt(lte, scn, &shdr,
+ <e->plt_relocs) < 0) {
fprintf(stderr, "Couldn't get .rel*.plt"
" data from \"%s\": %s\n",
filename, elf_errmsg(-1));
@@ -548,9 +625,9 @@ do_init_elf(struct ltelf *lte, const char *filename)
filename);
exit(EXIT_FAILURE);
}
-
- debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
}
+ debug(1, "%s %zd PLT relocations", filename,
+ vect_size(<e->plt_relocs));
if (soname_offset != 0)
lte->soname = lte->dynstr + soname_offset;
@@ -558,51 +635,13 @@ do_init_elf(struct ltelf *lte, const char *filename)
return 0;
}
-void
-do_close_elf(struct ltelf *lte)
-{
- debug(DEBUG_FUNCTION, "do_close_elf()");
- arch_elf_destroy(lte);
- elf_end(lte->elf);
- close(lte->fd);
-}
-
-int
-elf_get_sym_info(struct ltelf *lte, const char *filename,
- size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
-{
- int i = sym_index;
- GElf_Rel rel;
- void *ret;
-
- if (lte->relplt->d_type == ELF_T_REL) {
- ret = gelf_getrel(lte->relplt, i, &rel);
- rela->r_offset = rel.r_offset;
- rela->r_info = rel.r_info;
- rela->r_addend = 0;
- } else {
- ret = gelf_getrela(lte->relplt, i, rela);
- }
-
- if (ret == NULL
- || ELF64_R_SYM(rela->r_info) >= lte->dynsym_count
- || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela->r_info),
- sym) == NULL) {
- fprintf(stderr,
- "Couldn't get relocation from \"%s\": %s\n",
- filename, elf_errmsg(-1));
- exit(EXIT_FAILURE);
- }
-
- return 0;
-}
-
#ifndef ARCH_HAVE_GET_SYMINFO
int
arch_get_sym_info(struct ltelf *lte, const char *filename,
size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
{
- return elf_get_sym_info(lte, filename, sym_index, rela, sym);
+ return gelf_getsym(lte->dynsym,
+ ELF64_R_SYM(rela->r_info), sym) != NULL ? 0 : -1;
}
#endif
@@ -649,12 +688,13 @@ populate_plt(struct Process *proc, const char *filename,
struct ltelf *lte, struct library *lib,
int latent_plts)
{
+ size_t count = vect_size(<e->plt_relocs);
size_t i;
- for (i = 0; i < lte->relplt_count; ++i) {
- GElf_Rela rela;
+ for (i = 0; i < count; ++i) {
+ GElf_Rela *rela = VECT_ELEMENT(<e->plt_relocs, GElf_Rela, i);
GElf_Sym sym;
- if (arch_get_sym_info(lte, filename, i, &rela, &sym) < 0)
+ if (arch_get_sym_info(lte, filename, i, rela, &sym) < 0)
continue; /* Skip this entry. */
char const *name = lte->dynstr + sym.st_name;
@@ -664,14 +704,14 @@ populate_plt(struct Process *proc, const char *filename,
struct library_symbol *libsym = NULL;
switch (arch_elf_add_plt_entry(proc, lte, name,
- &rela, i, &libsym)) {
+ rela, i, &libsym)) {
case plt_fail:
return -1;
case plt_default:
/* Add default entry to the beginning of LIBSYM. */
if (default_elf_add_plt_entry(proc, lte, name,
- &rela, i, &libsym) < 0)
+ rela, i, &libsym) < 0)
return -1;
/* fall-through */
case plt_ok:
@@ -951,8 +991,8 @@ static int
read_module(struct library *lib, struct Process *proc,
const char *filename, GElf_Addr bias, int main)
{
- struct ltelf lte = {};
- if (open_elf(<e, filename) < 0)
+ struct ltelf lte;
+ if (ltelf_init(<e, filename) < 0)
return -1;
/* XXX When we abstract ABI into a module, this should instead
@@ -960,8 +1000,8 @@ read_module(struct library *lib, struct Process *proc,
*
* proc->abi = arch_get_abi(lte.ehdr);
*
- * The code in open_elf needs to be replaced by this logic.
- * Be warned that libltrace.c calls open_elf as well to
+ * The code in ltelf_init needs to be replaced by this logic.
+ * Be warned that libltrace.c calls ltelf_init as well to
* determine whether ABI is supported. This is to get
* reasonable error messages when trying to run 64-bit binary
* with 32-bit ltrace. It is desirable to preserve this. */
@@ -976,6 +1016,8 @@ read_module(struct library *lib, struct Process *proc,
if (process_get_entry(proc, &entry, NULL) < 0) {
fprintf(stderr, "Couldn't find entry of PIE %s\n",
filename);
+ fail:
+ ltelf_destroy(<e);
return -1;
}
/* XXX The double cast should be removed when
@@ -1000,19 +1042,18 @@ read_module(struct library *lib, struct Process *proc,
fprintf(stderr,
"Couldn't determine base address of %s\n",
filename);
- return -1;
+ goto fail;
}
}
- if (do_init_elf(<e, filename) < 0)
- return -1;
+ if (ltelf_read_elf(<e, filename) < 0)
+ goto fail;
if (arch_elf_init(<e, lib) < 0) {
fprintf(stderr, "Backend initialization failed.\n");
- return -1;
+ goto fail;
}
- int status = 0;
if (lib == NULL)
goto fail;
@@ -1078,13 +1119,9 @@ read_module(struct library *lib, struct Process *proc,
symtabs, exports) < 0)
goto fail;
-done:
- do_close_elf(<e);
- return status;
-
-fail:
- status = -1;
- goto done;
+ arch_elf_destroy(<e);
+ ltelf_destroy(<e);
+ return 0;
}
int
--- ltrace-elf.h.ori
+++ ltrace-elf.h
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <callback.h>
#include "sysdep.h"
+#include "vect.h"
struct Process;
struct library;
@@ -49,9 +50,11 @@ struct ltelf {
GElf_Addr plt_addr;
GElf_Word plt_flags;
size_t plt_size;
- Elf_Data *relplt;
Elf_Data *plt_data;
- size_t relplt_count;
+
+ /* Vector of GElf_Rela with PLT relocations. */
+ struct vect plt_relocs;
+
Elf_Data *symtab;
const char *strtab;
const char *soname;
@@ -61,15 +64,14 @@ struct ltelf {
size_t opd_size;
GElf_Addr dyn_addr;
size_t dyn_sz;
- size_t relplt_size;
GElf_Addr bias;
GElf_Addr entry_addr;
GElf_Addr base_addr;
struct arch_ltelf_data arch;
};
-int open_elf(struct ltelf *lte, const char *filename);
-void do_close_elf(struct ltelf *lte);
+int ltelf_init(struct ltelf *lte, const char *filename);
+void ltelf_destroy(struct ltelf *lte);
/* XXX is it possible to put breakpoints in VDSO and VSYSCALL
* pseudo-libraries? For now we assume that all libraries can be
@@ -92,11 +94,6 @@ int default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
const char *a_name, GElf_Rela *rela, size_t ndx,
struct library_symbol **ret);
-/* The base implementation of backend.h (arch_get_sym_info).
- * See backend.h for details. */
-int elf_get_sym_info(struct ltelf *lte, const char *filename,
- size_t sym_index, GElf_Rela *rela, GElf_Sym *sym);
-
Elf_Data *elf_loaddata(Elf_Scn *scn, GElf_Shdr *shdr);
int elf_get_section_covering(struct ltelf *lte, GElf_Addr addr,
Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr);
--- sysdeps/linux-gnu/mipsel/plt.c.ori
+++ sysdeps/linux-gnu/mipsel/plt.c
@@ -158,8 +158,9 @@ int
{
const char *name;
- if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
- return elf_get_sym_info(lte, filename, sym_index, rela, sym);
+ if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
+ return gelf_getsym(lte->dynsym, ELF64_R_SYM(rela->r_info),
+ sym) != NULL ? 0 : -1;
}
/* Fixup the offset. */