Dear maintainer,
This is an update to my previous nmudiff where I removed patches related to arm arch. Hope that answer the bug#744752 content. Regards. diff -Nru ltrace-0.7.3/debian/changelog ltrace-0.7.3/debian/changelog --- ltrace-0.7.3/debian/changelog 2016-09-21 13:15:35.000000000 +0200 +++ ltrace-0.7.3/debian/changelog 2017-01-27 12:42:02.000000000 +0100 @@ -1,3 +1,16 @@ +ltrace (0.7.3-6.1) unstable; urgency=medium + + * Non-maintainer upload. + * Closes: #744752 + * Support for arch ppc64el and mandatory updates + d/control add ppc64le and update debhelper versions + d/compat update version + d/watch: add file + d/lintian-overrides: hardening, spelling-error-in-manpage, + no-upstream-changelog, copyright-refers-to-symlink-license + + -- Thierry Fauck <tfa...@free.fr> Wed, 15 Dec 2016 13:15:35 +0200 + ltrace (0.7.3-6) unstable; urgency=medium * Fixed compilation error in amd64: readdir_r is deprecated (closes: #837011) diff -Nru ltrace-0.7.3/debian/compat ltrace-0.7.3/debian/compat --- ltrace-0.7.3/debian/compat 2012-11-10 13:43:48.000000000 +0100 +++ ltrace-0.7.3/debian/compat 2016-12-15 19:34:46.000000000 +0100 @@ -1 +1 @@ -5 +10 diff -Nru ltrace-0.7.3/debian/control ltrace-0.7.3/debian/control --- ltrace-0.7.3/debian/control 2016-09-21 13:15:35.000000000 +0200 +++ ltrace-0.7.3/debian/control 2016-12-15 19:38:17.000000000 +0100 @@ -3,10 +3,11 @@ Priority: optional Maintainer: Juan Cespedes <cespe...@debian.org> Standards-Version: 3.9.8 -Build-Depends: cdbs (>= 0.4.23-1.1), debhelper (>= 7), autotools-dev, libiberty-dev, libelf-dev, libselinux1-dev +Build-Depends: cdbs (>= 0.4.23-1.1), debhelper (>= 9), autotools-dev, libiberty-dev, libelf-dev, libselinux1-dev +Homepage: https://www.ltrace.org Package: ltrace -Architecture: alpha amd64 arm armeb armel armhf ia64 i386 mips mipsel powerpc powerpcspe ppc64 s390 s390x sparc +Architecture: alpha amd64 arm armeb armel armhf ia64 i386 mips mipsel powerpc powerpcspe ppc64 ppc64el s390 s390x sparc Depends: ${shlibs:Depends}, ${misc:Depends} Description: Tracks runtime library calls in dynamically linked programs ltrace is a debugging program which runs a specified command until it diff -Nru ltrace-0.7.3/debian/copyright ltrace-0.7.3/debian/copyright --- ltrace-0.7.3/debian/copyright 2015-07-03 17:20:13.000000000 +0200 +++ ltrace-0.7.3/debian/copyright 2017-01-05 09:58:40.000000000 +0100 @@ -1,4 +1,4 @@ -This is the Debian GNU/Linux's prepackaged version of the +i-This is the Debian GNU/Linux's prepackaged version of the Dynamic Library Tracer ``ltrace''. It was downloaded from http://www.ltrace.org/ @@ -37,3 +37,4 @@ or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'. You can also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + diff -Nru ltrace-0.7.3/debian/lintian-overrides ltrace-0.7.3/debian/lintian-overrides --- ltrace-0.7.3/debian/lintian-overrides 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/lintian-overrides 2016-12-15 19:55:30.000000000 +0100 @@ -0,0 +1,3 @@ +# ltrace: copyright-refers-to-symlink-license usr/share/common-licenses/GPL +ltrace: no-upstream-changelog +ltrace: spelling-error-in-manpage usr/share/man/man1/ltrace.1.gz recieved received diff -Nru ltrace-0.7.3/debian/patches/add_elf_can_read_next_5c37171a.patch ltrace-0.7.3/debian/patches/add_elf_can_read_next_5c37171a.patch --- ltrace-0.7.3/debian/patches/add_elf_can_read_next_5c37171a.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/add_elf_can_read_next_5c37171a.patch 2016-12-04 23:23:05.000000000 +0100 @@ -0,0 +1,57 @@ +From 5c37171a18bddfbc716d4f3da8b008a844eea4f7 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Tue, 5 Feb 2013 01:52:37 +0100 +Subject: Add elf_can_read_next + +--- + ltrace-elf.c | 10 +++++----- + ltrace-elf.h | 3 +++ + 2 files changed, 8 insertions(+), 5 deletions(-) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -202,23 +202,23 @@ elf_get_section_named(struct ltelf *lte, + &name_p, &data); + } + +-static int +-need_data(Elf_Data *data, GElf_Xword offset, GElf_Xword size) ++int ++elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword size) + { + assert(data != NULL); + if (data->d_size < size || offset > data->d_size - size) { + debug(1, "Not enough data to read %"PRId64"-byte value" + " at offset %"PRId64".", size, offset); +- return -1; ++ return 0; + } +- return 0; ++ return 1; + } + + #define DEF_READER(NAME, SIZE) \ + int \ + NAME(Elf_Data *data, GElf_Xword offset, uint##SIZE##_t *retp) \ + { \ +- if (need_data(data, offset, SIZE / 8) < 0) \ ++ if (!elf_can_read_next(data, offset, SIZE / 8)) \ + return -1; \ + \ + if (data->d_buf == NULL) /* NODATA section */ { \ +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -116,6 +116,9 @@ int elf_read_next_u16(Elf_Data *data, GE + int elf_read_next_u32(Elf_Data *data, GElf_Xword *offset, uint32_t *retp); + int elf_read_next_u64(Elf_Data *data, GElf_Xword *offset, uint64_t *retp); + ++/* Return whether there's AMOUNT more bytes after OFFSET in DATA. */ ++int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount); ++ + #if __WORDSIZE == 32 + #define PRI_ELF_ADDR PRIx32 + #define GELF_ADDR_CAST(x) (void *)(uint32_t)(x) diff -Nru ltrace-0.7.3/debian/patches/add_elf_each_symbol_7a29f9e7.patch ltrace-0.7.3/debian/patches/add_elf_each_symbol_7a29f9e7.patch --- ltrace-0.7.3/debian/patches/add_elf_each_symbol_7a29f9e7.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/add_elf_each_symbol_7a29f9e7.patch 2016-12-04 23:23:05.000000000 +0100 @@ -0,0 +1,111 @@ +From 7a29f9e7a2bd5849886519eb82e9c043d24c6a40 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Mon, 14 Oct 2013 20:04:09 +0200 +Subject: Add elf_each_symbol + +--- + ltrace-elf.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ltrace-elf.h | 12 +++++++++++ + 2 files changed, 72 insertions(+) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -190,6 +190,66 @@ name_p(Elf_Scn *scn, GElf_Shdr *shdr, vo + return strcmp(name, data->name) == 0; + } + ++static struct elf_each_symbol_t ++each_symbol_in(Elf_Data *symtab, const char *strtab, size_t count, ++ unsigned i, ++ enum callback_status (*cb)(GElf_Sym *symbol, ++ const char *name, void *data), ++ void *data) ++{ ++ for (; i < count; ++i) { ++ GElf_Sym sym; ++ if (gelf_getsym(symtab, i, &sym) == NULL) ++ return (struct elf_each_symbol_t){ i, -2 }; ++ ++ switch (cb(&sym, strtab + sym.st_name, data)) { ++ case CBS_FAIL: ++ return (struct elf_each_symbol_t){ i, -1 }; ++ case CBS_STOP: ++ return (struct elf_each_symbol_t){ i + 1, 0 }; ++ case CBS_CONT: ++ break; ++ } ++ } ++ ++ return (struct elf_each_symbol_t){ 0, 0 }; ++} ++ ++/* N.B.: gelf_getsym takes integer argument. Since negative values ++ * are invalid as indices, we can use the extra bit to encode which ++ * symbol table we are looking into. ltrace currently doesn't handle ++ * more than two symbol tables anyway, nor does it handle the xindex ++ * stuff. */ ++struct elf_each_symbol_t ++elf_each_symbol(struct ltelf *lte, unsigned start_after, ++ enum callback_status (*cb)(GElf_Sym *symbol, ++ const char *name, void *data), ++ void *data) ++{ ++ unsigned index = start_after == 0 ? 0 : start_after >> 1; ++ ++ /* Go through static symbol table first. */ ++ if ((start_after & 0x1) == 0) { ++ struct elf_each_symbol_t st ++ = each_symbol_in(lte->symtab, lte->strtab, ++ lte->symtab_count, index, cb, data); ++ ++ /* If the iteration stopped prematurely, bail out. */ ++ if (st.restart != 0) ++ return ((struct elf_each_symbol_t) ++ { st.restart << 1, st.status }); ++ } ++ ++ struct elf_each_symbol_t st ++ = each_symbol_in(lte->dynsym, lte->dynstr, lte->dynsym_count, ++ index, cb, data); ++ if (st.restart != 0) ++ return ((struct elf_each_symbol_t) ++ { st.restart << 1 | 0x1, st.status }); ++ ++ return (struct elf_each_symbol_t){ 0, 0 }; ++} ++ + int + elf_get_section_named(struct ltelf *lte, const char *name, + Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr) +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -26,6 +26,7 @@ + + #include <gelf.h> + #include <stdlib.h> ++#include <callback.h> + #include "sysdep.h" + #include "vect.h" + +@@ -101,6 +102,17 @@ int elf_get_section_type(struct ltelf *l + int elf_get_section_named(struct ltelf *lte, const char *name, + Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr); + ++/* Iterate through all symbols in LTE. See callback.h for notes on ++ * iteration interfaces. START_AFTER is 0 in initial call. */ ++struct elf_each_symbol_t { ++ unsigned restart; ++ int status; ++} elf_each_symbol(struct ltelf *lte, unsigned start_after, ++ enum callback_status (*cb)(GElf_Sym *symbol, ++ const char *name, ++ void *data), ++ void *data); ++ + /* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given + * OFFSET, and store it in *RETP. Returns 0 on success or a negative + * value if there's not enough data. */ diff -Nru ltrace-0.7.3/debian/patches/add_elf_read_next_u_439ab5bf.patch ltrace-0.7.3/debian/patches/add_elf_read_next_u_439ab5bf.patch --- ltrace-0.7.3/debian/patches/add_elf_read_next_u_439ab5bf.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/add_elf_read_next_u_439ab5bf.patch 2016-12-04 23:23:05.000000000 +0100 @@ -0,0 +1,58 @@ +From 439ab5bfac8588e52c77e22c96fb397787512d0e Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Tue, 5 Feb 2013 01:50:28 +0100 +Subject: Add elf_read_next_u* + +For stream-like reading of ELF data. +--- + ltrace-elf.c | 18 ++++++++++++++++++ + ltrace-elf.h | 7 +++++++ + 2 files changed, 25 insertions(+) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -242,6 +242,24 @@ DEF_READER(elf_read_u64, 64) + + #undef DEF_READER + ++#define DEF_READER(NAME, SIZE) \ ++ int \ ++ NAME(Elf_Data *data, GElf_Xword *offset, uint##SIZE##_t *retp) \ ++ { \ ++ int rc = elf_read_u##SIZE(data, *offset, retp); \ ++ if (rc < 0) \ ++ return rc; \ ++ *offset += SIZE / 8; \ ++ return 0; \ ++ } ++ ++DEF_READER(elf_read_next_u8, 8) ++DEF_READER(elf_read_next_u16, 16) ++DEF_READER(elf_read_next_u32, 32) ++DEF_READER(elf_read_next_u64, 64) ++ ++#undef DEF_READER ++ + int + ltelf_init(struct ltelf *lte, const char *filename) + { +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -109,6 +109,13 @@ int elf_read_u16(Elf_Data *data, GElf_Xw + int elf_read_u32(Elf_Data *data, GElf_Xword offset, uint32_t *retp); + int elf_read_u64(Elf_Data *data, GElf_Xword offset, uint64_t *retp); + ++/* These are same as above, but update *OFFSET with the width ++ * of read datum. */ ++int elf_read_next_u8(Elf_Data *data, GElf_Xword *offset, uint8_t *retp); ++int elf_read_next_u16(Elf_Data *data, GElf_Xword *offset, uint16_t *retp); ++int elf_read_next_u32(Elf_Data *data, GElf_Xword *offset, uint32_t *retp); ++int elf_read_next_u64(Elf_Data *data, GElf_Xword *offset, uint64_t *retp); ++ + #if __WORDSIZE == 32 + #define PRI_ELF_ADDR PRIx32 + #define GELF_ADDR_CAST(x) (void *)(uint32_t)(x) diff -Nru ltrace-0.7.3/debian/patches/add_elf_read_u8_3c636fb7.patch ltrace-0.7.3/debian/patches/add_elf_read_u8_3c636fb7.patch --- ltrace-0.7.3/debian/patches/add_elf_read_u8_3c636fb7.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/add_elf_read_u8_3c636fb7.patch 2016-12-04 23:23:04.000000000 +0100 @@ -0,0 +1,40 @@ +From 3c636fb789a29cac0c8f7f0982fb17afeee489dc Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Tue, 5 Feb 2013 01:48:54 +0100 +Subject: Add elf_read_u8 + +--- + ltrace-elf.c | 1 + + ltrace-elf.h | 7 ++++--- + 2 files changed, 5 insertions(+), 3 deletions(-) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -235,6 +235,7 @@ need_data(Elf_Data *data, GElf_Xword off + return 0; \ + } + ++DEF_READER(elf_read_u8, 8) + DEF_READER(elf_read_u16, 16) + DEF_READER(elf_read_u32, 32) + DEF_READER(elf_read_u64, 64) +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -101,9 +101,10 @@ int elf_get_section_type(struct ltelf *l + int elf_get_section_named(struct ltelf *lte, const char *name, + Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr); + +-/* Read, respectively, 2, 4, or 8 bytes from Elf data at given OFFSET, +- * and store it in *RETP. Returns 0 on success or a negative value if +- * there's not enough data. */ ++/* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given ++ * OFFSET, and store it in *RETP. Returns 0 on success or a negative ++ * value if there's not enough data. */ ++int elf_read_u8(Elf_Data *data, GElf_Xword offset, uint8_t *retp); + int elf_read_u16(Elf_Data *data, GElf_Xword offset, uint16_t *retp); + int elf_read_u32(Elf_Data *data, GElf_Xword offset, uint32_t *retp); + int elf_read_u64(Elf_Data *data, GElf_Xword offset, uint64_t *retp); diff -Nru ltrace-0.7.3/debian/patches/add_irelative_tracing_b420a226.patch ltrace-0.7.3/debian/patches/add_irelative_tracing_b420a226.patch --- ltrace-0.7.3/debian/patches/add_irelative_tracing_b420a226.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/add_irelative_tracing_b420a226.patch 2016-12-04 23:23:04.000000000 +0100 @@ -0,0 +1,229 @@ +From b420a226cd2fc5d6028adcaf236c512a1f1fb437 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Tue, 15 Oct 2013 10:46:28 +0200 +Subject: Add support for tracing of IRELATIVE PLT entries + +- Because the IRELATIVE entries have no associated symbol name, we + need to allow arch_elf_add_plt_entry to override the name. This is + done by that callback returning PLT_OK and returning the new symbol + via libsym-chain return argument. Filtering is postponed until we + have that symbol, and the filter is applied to the whole returned + chain. + +- Add linux_elf_add_plt_entry_irelative to support proper naming of + IRELATIVE PLT entries. This needs to be called from arch backend, + as the numbers of IRELATIVE relocations differ per-architecture. +--- + ltrace-elf.c | 43 +++++++++++++++++++++-------- + sysdeps/linux-gnu/trace.c | 68 +++++++++++++++++++++++++++++++++++++++++++--- + sysdeps/linux-gnu/trace.h | 18 ++++++++++++ + 3 files changed, 115 insertions(+), 14 deletions(-) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -539,6 +539,24 @@ mark_chain_latent(struct library_symbol + } + } + ++static void ++filter_symbol_chain(struct filter *filter, ++ struct library_symbol **libsymp, struct library *lib) ++{ ++ assert(libsymp != NULL); ++ struct library_symbol **ptr = libsymp; ++ while (*ptr != NULL) { ++ if (filter_matches_symbol(filter, (*ptr)->name, lib)) { ++ ptr = &(*ptr)->next; ++ } else { ++ struct library_symbol *sym = *ptr; ++ *ptr = (*ptr)->next; ++ library_symbol_destroy(sym); ++ free(sym); ++ } ++ } ++} ++ + static int + populate_plt(struct Process *proc, const char *filename, + struct ltelf *lte, struct library *lib, +@@ -554,30 +572,34 @@ populate_plt(struct Process *proc, const + + char const *name = lte->dynstr + sym.st_name; + +- /* If the symbol wasn't matched, reject it, unless we +- * need to keep latent PLT breakpoints for tracing +- * exports. */ + int matched = filter_matches_symbol(options.plt_filter, + name, lib); +- if (!matched && !latent_plts) +- continue; +- + struct library_symbol *libsym = NULL; + switch (arch_elf_add_plt_entry(proc, lte, name, + &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) +- /* fall-through */ +- case plt_fail: + return -1; +- /* fall-through */ + case plt_ok: ++ /* If we didn't match the PLT entry up there, ++ * filter the chain to only include the ++ * matching symbols (but include all if we are ++ * adding latent symbols). This is to allow ++ * arch_elf_add_plt_entry to override the PLT ++ * symbol's name. */ ++ if (!matched && !latent_plts) ++ filter_symbol_chain(options.plt_filter, ++ &libsym, lib); + if (libsym != NULL) { + /* If we are adding those symbols just + * for tracing exports, mark them all + * latent. */ +- if (!matched) ++ if (!matched && latent_plts) + mark_chain_latent(libsym); + library_add_symbol(lib, libsym); + } +@@ -657,7 +679,6 @@ populate_this_symtab(struct Process *pro + continue; + } + +- /* XXX support IFUNC as well. */ + if (GELF_ST_TYPE(sym.st_info) != STT_FUNC + || sym.st_value == 0 + || sym.st_shndx == STN_UNDEF) +Index: b/sysdeps/linux-gnu/trace.c +=================================================================== +--- a/sysdeps/linux-gnu/trace.c ++++ b/sysdeps/linux-gnu/trace.c +@@ -24,25 +24,29 @@ + #include "config.h" + + #include <asm/unistd.h> +-#include <sys/types.h> +-#include <sys/wait.h> + #include <assert.h> + #include <errno.h> ++#include <gelf.h> ++#include <inttypes.h> ++#include <stdbool.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> ++#include <sys/types.h> ++#include <sys/wait.h> + #include <unistd.h> + + #ifdef HAVE_LIBSELINUX + # include <selinux/selinux.h> + #endif + +-#include "linux-gnu/trace.h" + #include "linux-gnu/trace-defs.h" ++#include "linux-gnu/trace.h" + #include "backend.h" + #include "breakpoint.h" + #include "debug.h" + #include "events.h" ++#include "ltrace-elf.h" + #include "options.h" + #include "proc.h" + #include "ptrace.h" +@@ -1212,3 +1216,61 @@ umovebytes(Process *proc, void *addr, vo + + return bytes_read; + } ++ ++struct irelative_name_data_t { ++ GElf_Addr addr; ++ const char *found_name; ++}; ++ ++static enum callback_status ++irelative_name_cb(GElf_Sym *symbol, const char *name, void *d) ++{ ++ struct irelative_name_data_t *data = d; ++ ++ if (symbol->st_value == data->addr) { ++ bool is_ifunc = false; ++#ifdef STT_GNU_IFUNC ++ is_ifunc = GELF_ST_TYPE(symbol->st_info) == STT_GNU_IFUNC; ++#endif ++ data->found_name = name; ++ ++ /* Keep looking, unless we found the actual IFUNC ++ * symbol. What we matched may have been a symbol ++ * denoting the resolver function, which would have ++ * the same address. */ ++ return CBS_STOP_IF(is_ifunc); ++ } ++ ++ return CBS_CONT; ++} ++ ++enum plt_status ++linux_elf_add_plt_entry_irelative(struct Process *proc, struct ltelf *lte, ++ GElf_Rela *rela, size_t ndx, ++ struct library_symbol **ret) ++ ++{ ++ struct irelative_name_data_t data = { rela->r_addend, NULL }; ++ if (rela->r_addend != 0 ++ && elf_each_symbol(lte, 0, ++ irelative_name_cb, &data).status < 0) ++ return -1; ++ ++ const char *name; ++ if (data.found_name != NULL) { ++ name = data.found_name; ++ } else { ++#define NAME "IREL." ++ /* NAME\0 + 0x + digits. */ ++ char *tmp_name = alloca(sizeof NAME + 2 + 16); ++ sprintf(tmp_name, NAME "%#" PRIx64, ++ (uint64_t)rela->r_addend); ++ name = tmp_name; ++#undef NAME ++ } ++ ++ if (default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret) < 0) ++ return PLT_FAIL; ++ ++ return PLT_OK; ++} +Index: b/sysdeps/linux-gnu/trace.h +=================================================================== +--- a/sysdeps/linux-gnu/trace.h ++++ b/sysdeps/linux-gnu/trace.h +@@ -118,4 +118,22 @@ int process_install_stopping_handler + void linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self); + void linux_ptrace_disable_and_continue(struct process_stopping_handler *self); + ++/* When main binary needs to call an IFUNC function defined in the ++ * binary itself, a PLT entry is set up so that dynamic linker can get ++ * involved and resolve the symbol. But unlike other PLT relocation, ++ * this one can't rely on symbol table being available. So it doesn't ++ * reference the symbol by its name, but by its address, and ++ * correspondingly, has another type. When arch backend wishes to ++ * support these IRELATIVE relocations, it should override ++ * arch_elf_add_plt_entry and dispatch to this function for IRELATIVE ++ * relocations. ++ * ++ * This function behaves as arch_elf_add_plt_entry, except that it ++ * doesn't take name for a parameter, but instead looks up the name in ++ * symbol tables in LTE. */ ++enum plt_status linux_elf_add_plt_entry_irelative(struct Process *proc, ++ struct ltelf *lte, ++ GElf_Rela *rela, size_t ndx, ++ struct library_symbol **ret); ++ + #endif /* _LTRACE_LINUX_TRACE_H_ */ diff -Nru ltrace-0.7.3/debian/patches/Add-missing-unistd.h ltrace-0.7.3/debian/patches/Add-missing-unistd.h --- ltrace-0.7.3/debian/patches/Add-missing-unistd.h 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/Add-missing-unistd.h 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,51 @@ +Description: Add missing unistd.h include file to testsuite + Add missing unistd.h include file to testsuite + . + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1398143 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1547152 + +--- + +--- ltrace-0.7.3.orig/testsuite/ltrace.main/signals.c ++++ ltrace-0.7.3/testsuite/ltrace.main/signals.c +@@ -5,6 +5,7 @@ + #include<stdio.h> + #include<signal.h> + #include <sys/types.h> ++#include <unistd.h> + + #define LOOP 7 + +--- ltrace-0.7.3.orig/testsuite/ltrace.minor/time-record.c ++++ ltrace-0.7.3/testsuite/ltrace.minor/time-record.c +@@ -5,6 +5,7 @@ + This file was written by Yao Qi <qi...@cn.ibm.com>. */ + #include <stdio.h> + #include <time.h> ++#include <unistd.h> + + #define SLEEP_COUNT 2 + #define NANOSLEEP_COUNT 50 +--- ltrace-0.7.3.orig/testsuite/ltrace.minor/trace-fork.c ++++ ltrace-0.7.3/testsuite/ltrace.minor/trace-fork.c +@@ -6,6 +6,7 @@ + + #include <stdio.h> + #include <sys/types.h> ++#include <unistd.h> + + void + child () +--- ltrace-0.7.3.orig/testsuite/ltrace.torture/signals.c ++++ ltrace-0.7.3/testsuite/ltrace.torture/signals.c +@@ -5,6 +5,7 @@ + #include<stdio.h> + #include<signal.h> + #include <sys/types.h> ++#include <unistd.h> + + #define LOOP 20 + diff -Nru ltrace-0.7.3/debian/patches/dont_ltelf_destroy_if_init_fails_0ba3c5ee.patch ltrace-0.7.3/debian/patches/dont_ltelf_destroy_if_init_fails_0ba3c5ee.patch --- ltrace-0.7.3/debian/patches/dont_ltelf_destroy_if_init_fails_0ba3c5ee.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/dont_ltelf_destroy_if_init_fails_0ba3c5ee.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,30 @@ +From 0ba3c5eee259b77e3883e40c4d0cd2fab5b03ff3 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Mon, 11 Nov 2013 02:27:08 +0100 +Subject: In ltrace_init, don't call ltelf_destroy if ltelf_init fails + +--- + libltrace.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +Index: b/libltrace.c +=================================================================== +--- a/libltrace.c ++++ b/libltrace.c +@@ -136,9 +136,13 @@ ltrace_init(int argc, char **argv) { + if (command) { + /* Check that the binary ABI is supported before + * calling execute_program. */ +- struct ltelf lte; +- ltelf_init(<e, command); +- ltelf_destroy(<e); ++ { ++ struct ltelf lte; ++ if (ltelf_init(<e, command) == 0) ++ ltelf_destroy(<e); ++ else ++ exit(EXIT_FAILURE); ++ } + + pid_t pid = execute_program(command, argv); + struct Process *proc = open_program(command, pid); diff -Nru ltrace-0.7.3/debian/patches/elf_load_dynamic_entry_4f2f66e6.patch ltrace-0.7.3/debian/patches/elf_load_dynamic_entry_4f2f66e6.patch --- ltrace-0.7.3/debian/patches/elf_load_dynamic_entry_4f2f66e6.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/elf_load_dynamic_entry_4f2f66e6.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,153 @@ +From 4f2f66e6abc7fedf3a5d04fab7cc00e5f82b37cf Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Mon, 4 Nov 2013 22:45:34 -0500 +Subject: Move load_dynamic_entry from PPC backend to ltrace-elf.c/.h + +--- + ltrace-elf.c | 32 +++++++++++++++++++++++++++++++ + ltrace-elf.h | 4 +++ + sysdeps/linux-gnu/ppc/plt.c | 45 ++++++-------------------------------------- + 3 files changed, 43 insertions(+), 38 deletions(-) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -527,6 +527,38 @@ read_relplt(struct ltelf *lte, Elf_Scn * + return 0; + } + ++int ++elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep) ++{ ++ Elf_Scn *scn; ++ GElf_Shdr shdr; ++ if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0 ++ || scn == NULL) { ++ fail: ++ fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n", ++ elf_errmsg(-1)); ++ return -1; ++ } ++ ++ Elf_Data *data = elf_loaddata(scn, &shdr); ++ if (data == NULL) ++ goto fail; ++ ++ size_t j; ++ for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { ++ GElf_Dyn dyn; ++ if (gelf_getdyn(data, j, &dyn) == NULL) ++ goto fail; ++ ++ if(dyn.d_tag == tag) { ++ *valuep = dyn.d_un.d_ptr; ++ return 0; ++ } ++ } ++ ++ return -1; ++} ++ + static int + ltelf_read_elf(struct ltelf *lte, const char *filename) + { +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -113,6 +113,10 @@ struct elf_each_symbol_t { + void *data), + void *data); + ++/* Read a given DT_ TAG from LTE. Value is returned in *VALUEP. ++ * Returns 0 on success or a negative value on failure. */ ++int elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep); ++ + /* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given + * OFFSET, and store it in *RETP. Returns 0 on success or a negative + * value if there's not enough data. */ +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -441,38 +441,6 @@ get_glink_vma(struct ltelf *lte, GElf_Ad + } + + static int +-load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep) +-{ +- Elf_Scn *scn; +- GElf_Shdr shdr; +- if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0 +- || scn == NULL) { +- fail: +- fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n", +- elf_errmsg(-1)); +- return -1; +- } +- +- Elf_Data *data = elf_loaddata(scn, &shdr); +- if (data == NULL) +- goto fail; +- +- size_t j; +- for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { +- GElf_Dyn dyn; +- if (gelf_getdyn(data, j, &dyn) == NULL) +- goto fail; +- +- if(dyn.d_tag == tag) { +- *valuep = dyn.d_un.d_ptr; +- return 0; +- } +- } +- +- return -1; +-} +- +-static int + nonzero_data(Elf_Data *data) + { + /* We are not supposed to get here if there's no PLT. */ +@@ -520,7 +488,7 @@ arch_elf_init(struct ltelf *lte, struct + + if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) { + GElf_Addr ppcgot; +- if (load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) { ++ if (elf_load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) { + fprintf(stderr, "couldn't find DT_PPC_GOT\n"); + return -1; + } +@@ -533,7 +501,8 @@ arch_elf_init(struct ltelf *lte, struct + + } else if (lte->ehdr.e_machine == EM_PPC64) { + GElf_Addr glink_vma; +- if (load_dynamic_entry(lte, DT_PPC64_GLINK, &glink_vma) < 0) { ++ if (elf_load_dynamic_entry(lte, DT_PPC64_GLINK, ++ &glink_vma) < 0) { + fprintf(stderr, "couldn't find DT_PPC64_GLINK\n"); + return -1; + } +@@ -543,8 +512,8 @@ arch_elf_init(struct ltelf *lte, struct + + } else { + /* By exhaustion--PPC32 BSS. */ +- if (load_dynamic_entry(lte, DT_PLTGOT, +- &lib->arch.pltgot_addr) < 0) { ++ if (elf_load_dynamic_entry(lte, DT_PLTGOT, ++ &lib->arch.pltgot_addr) < 0) { + fprintf(stderr, "couldn't find DT_PLTGOT\n"); + return -1; + } +@@ -639,8 +608,8 @@ arch_elf_init(struct ltelf *lte, struct + Elf_Scn *rela_sec; + GElf_Shdr rela_shdr; + if (lte->ehdr.e_machine == EM_PPC64 +- && load_dynamic_entry(lte, DT_RELA, &rela) == 0 +- && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0 ++ && elf_load_dynamic_entry(lte, DT_RELA, &rela) == 0 ++ && elf_load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0 + && elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0 + && rela_sec != NULL) { + diff -Nru ltrace-0.7.3/debian/patches/elf_read_uleb128_184779e4.patch ltrace-0.7.3/debian/patches/elf_read_uleb128_184779e4.patch --- ltrace-0.7.3/debian/patches/elf_read_uleb128_184779e4.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/elf_read_uleb128_184779e4.patch 2016-12-04 23:23:05.000000000 +0100 @@ -0,0 +1,75 @@ +From 184779e4e8a42f2e9e7f3cee4bf4eb31e8c84ee4 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Tue, 5 Feb 2013 01:52:05 +0100 +Subject: Add elf_read_{,next_}uleb128 + +--- + ltrace-elf.c | 32 ++++++++++++++++++++++++++++++++ + ltrace-elf.h | 5 +++++ + 2 files changed, 37 insertions(+) + +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -321,6 +321,38 @@ DEF_READER(elf_read_next_u64, 64) + #undef DEF_READER + + int ++elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp) ++{ ++ uint64_t result = 0; ++ int shift = 0; ++ int size = 8 * sizeof result; ++ ++ while (1) { ++ uint8_t byte; ++ if (elf_read_next_u8(data, offset, &byte) < 0) ++ return -1; ++ ++ uint8_t payload = byte & 0x7f; ++ result |= (uint64_t)payload << shift; ++ shift += 7; ++ if (shift > size && byte != 0x1) ++ return -1; ++ if ((byte & 0x80) == 0) ++ break; ++ } ++ ++ if (retp != NULL) ++ *retp = result; ++ return 0; ++} ++ ++int ++elf_read_uleb128(Elf_Data *data, GElf_Xword offset, uint64_t *retp) ++{ ++ return elf_read_next_uleb128(data, &offset, retp); ++} ++ ++int + ltelf_init(struct ltelf *lte, const char *filename) + { + memset(lte, 0, sizeof *lte); +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -121,12 +121,17 @@ int elf_read_u16(Elf_Data *data, GElf_Xw + int elf_read_u32(Elf_Data *data, GElf_Xword offset, uint32_t *retp); + int elf_read_u64(Elf_Data *data, GElf_Xword offset, uint64_t *retp); + ++/* Read at most 64-bit quantity recorded in an ULEB128 variable-length ++ * encoding. */ ++int elf_read_uleb128(Elf_Data *data, GElf_Xword offset, uint64_t *retp); ++ + /* These are same as above, but update *OFFSET with the width + * of read datum. */ + int elf_read_next_u8(Elf_Data *data, GElf_Xword *offset, uint8_t *retp); + int elf_read_next_u16(Elf_Data *data, GElf_Xword *offset, uint16_t *retp); + int elf_read_next_u32(Elf_Data *data, GElf_Xword *offset, uint32_t *retp); + int elf_read_next_u64(Elf_Data *data, GElf_Xword *offset, uint64_t *retp); ++int elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp); + + /* Return whether there's AMOUNT more bytes after OFFSET in DATA. */ + int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount); diff -Nru ltrace-0.7.3/debian/patches/find_irelative_b061bae3.patch ltrace-0.7.3/debian/patches/find_irelative_b061bae3.patch --- ltrace-0.7.3/debian/patches/find_irelative_b061bae3.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/find_irelative_b061bae3.patch 2016-12-04 23:23:04.000000000 +0100 @@ -0,0 +1,71 @@ +From b061bae322edd4894f14ea2aea6baec36d32eda8 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Fri, 25 Oct 2013 23:50:18 +0200 +Subject: Split linux_elf_find_irelative_name out of + linux_elf_add_plt_entry_irelative + +--- + sysdeps/linux-gnu/trace.c | 23 ++++++++++++++--------- + sysdeps/linux-gnu/trace.h | 6 ++++++ + 2 files changed, 20 insertions(+), 9 deletions(-) + +Index: b/sysdeps/linux-gnu/trace.c +=================================================================== +--- a/sysdeps/linux-gnu/trace.c ++++ b/sysdeps/linux-gnu/trace.c +@@ -1243,17 +1243,14 @@ irelative_name_cb(GElf_Sym *symbol, cons + return CBS_CONT; + } + +-enum plt_status +-linux_elf_add_plt_entry_irelative(struct Process *proc, struct ltelf *lte, +- GElf_Rela *rela, size_t ndx, +- struct library_symbol **ret) +- ++char * ++linux_elf_find_irelative_name(struct ltelf *lte, GElf_Rela *rela) + { + struct irelative_name_data_t data = { rela->r_addend, NULL }; + if (rela->r_addend != 0 + && elf_each_symbol(lte, 0, + irelative_name_cb, &data).status < 0) +- return -1; ++ return NULL; + + const char *name; + if (data.found_name != NULL) { +@@ -1268,8 +1265,16 @@ linux_elf_add_plt_entry_irelative(struct + #undef NAME + } + +- if (default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret) < 0) +- return PLT_FAIL; ++ return strdup(name); ++} + +- return PLT_OK; ++enum plt_status ++linux_elf_add_plt_entry_irelative(struct Process *proc, struct ltelf *lte, ++ GElf_Rela *rela, size_t ndx, ++ struct library_symbol **ret) ++{ ++ char *name = linux_elf_find_irelative_name(lte, rela); ++ int i = default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret); ++ free(name); ++ return i < 0 ? plt_fail : plt_ok; + } +Index: b/sysdeps/linux-gnu/trace.h +=================================================================== +--- a/sysdeps/linux-gnu/trace.h ++++ b/sysdeps/linux-gnu/trace.h +@@ -136,4 +136,10 @@ enum plt_status linux_elf_add_plt_entry_ + GElf_Rela *rela, size_t ndx, + struct library_symbol **ret); + ++/* Service routine of the above. Determines a name corresponding to ++ * RELA, or invents a new one. Returns NULL on failures, otherwise it ++ * returns a malloc'd pointer that the caller is responsible for ++ * freeing. */ ++char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Rela *rela); ++ + #endif /* _LTRACE_LINUX_TRACE_H_ */ diff -Nru ltrace-0.7.3/debian/patches/free-of-unitialised-libsym ltrace-0.7.3/debian/patches/free-of-unitialised-libsym --- ltrace-0.7.3/debian/patches/free-of-unitialised-libsym 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/free-of-unitialised-libsym 2016-12-14 16:36:07.000000000 +0100 @@ -0,0 +1,19 @@ +Description: free + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> + +--- +Last-Update: 2016-12-05 + +--- ltrace-0.7.3.orig/sysdeps/linux-gnu/ppc/plt.c ++++ ltrace-0.7.3/sysdeps/linux-gnu/ppc/plt.c +@@ -778,7 +778,7 @@ arch_elf_add_plt_entry(struct Process *p + strerror(errno)); + fail: + free(name); +- free(libsym); ++ // free(libsym); + return plt_fail; + } + diff -Nru ltrace-0.7.3/debian/patches/include-stdio.h-missing ltrace-0.7.3/debian/patches/include-stdio.h-missing --- ltrace-0.7.3/debian/patches/include-stdio.h-missing 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/include-stdio.h-missing 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,17 @@ +Description: include stdio.h missing + . + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> + +--- +--- ltrace-0.7.3.orig/testsuite/ltrace.main/filters.exp ++++ ltrace-0.7.3/testsuite/ltrace.main/filters.exp +@@ -22,6 +22,7 @@ set libfilt1 [ltraceCompile libfilt1.so + }]] + + set libfilt2 [ltraceCompile libfilt2.so [ltraceSource c { ++ #include <stdio.h> + void func2(void) { puts("func2"); } + }]] + diff -Nru ltrace-0.7.3/debian/patches/initialize_libsym ltrace-0.7.3/debian/patches/initialize_libsym --- ltrace-0.7.3/debian/patches/initialize_libsym 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/initialize_libsym 2016-12-14 16:36:31.000000000 +0100 @@ -0,0 +1,36 @@ +Description: Initialize libsym early in plt.c to help the compiler. + + GCC 4.4.7 isn't smart enough to realize own_libsym will always be zero + when it sees the goto done which might jump over the initialization of + libsym. And so will produce a warning like: + + cc1: warnings being treated as errors + trace.c: In function âifunc_ret_hitâ: + trace.c:1433: error: âlibsymâ may be used uninitialized in this function + + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> + +--- +Last-Update: 2016-12-05 + +--- ltrace-0.7.3.orig/sysdeps/linux-gnu/ppc/plt.c ++++ ltrace-0.7.3/sysdeps/linux-gnu/ppc/plt.c +@@ -698,6 +698,7 @@ arch_elf_add_plt_entry(struct Process *p + const char *a_name, GElf_Rela *rela, size_t ndx, + struct library_symbol **ret) + { ++ struct library_symbol *libsym = NULL; + if (lte->ehdr.e_machine == EM_PPC) { + if (lte->arch.secure_plt) + return plt_default; +@@ -772,7 +773,7 @@ arch_elf_add_plt_entry(struct Process *p + if (rc < 0 && !lte->arch.elfv2_abi) + goto fail; + +- struct library_symbol *libsym = malloc(sizeof(*libsym)); ++ libsym = malloc(sizeof(*libsym)); + if (libsym == NULL) { + fprintf(stderr, "allocation for .plt slot: %s\n", + strerror(errno)); diff -Nru ltrace-0.7.3/debian/patches/jmp_irel.patch ltrace-0.7.3/debian/patches/jmp_irel.patch --- ltrace-0.7.3/debian/patches/jmp_irel.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/jmp_irel.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,449 @@ +From 73b85aadbf377541ac336914e5ff8ec521226a97 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Wed, 30 Oct 2013 00:10:29 +0100 +Subject: Support tracing P_PPC64_JMP_IREL slots + +--- + callback.h | 3 + sysdeps/linux-gnu/ppc/arch.h | 12 ++ + sysdeps/linux-gnu/ppc/plt.c | 234 ++++++++++++++++++++++++++++++++++--------- + 3 files changed, 201 insertions(+), 48 deletions(-) + +Index: b/sysdeps/linux-gnu/ppc/arch.h +=================================================================== +--- a/sysdeps/linux-gnu/ppc/arch.h ++++ b/sysdeps/linux-gnu/ppc/arch.h +@@ -56,6 +56,9 @@ struct arch_ltelf_data { + GElf_Addr opd_base; + GElf_Xword opd_size; + int secure_plt; ++ ++ Elf_Data *reladyn; ++ size_t reladyn_count; + }; + + #define ARCH_HAVE_LIBRARY_DATA +@@ -79,6 +82,10 @@ enum ppc64_plt_type { + * corresponding PLT entry. The original is now saved in + * RESOLVED_VALUE. */ + PPC_PLT_RESOLVED, ++ ++ /* Very similar to PPC_PLT_UNRESOLVED, but for JMP_IREL ++ * slots. */ ++ PPC_PLT_IRELATIVE, + }; + + #define ARCH_HAVE_LIBRARY_SYMBOL_DATA +@@ -92,7 +99,10 @@ struct arch_library_symbol_data { + + #define ARCH_HAVE_BREAKPOINT_DATA + struct arch_breakpoint_data { +- /* We need this just for arch_breakpoint_init. */ ++ /* This is where we hide symbol for IRELATIVE breakpoint for ++ * the first time that it hits. This is NULL for normal ++ * breakpoints. */ ++ struct library_symbol *irel_libsym; + }; + + #define ARCH_HAVE_PROCESS_DATA +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -25,6 +25,7 @@ + #include <errno.h> + #include <inttypes.h> + #include <assert.h> ++#include <stdbool.h> + #include <string.h> + + #include "proc.h" +@@ -34,6 +35,8 @@ + #include "breakpoint.h" + #include "linux-gnu/trace.h" + #include "backend.h" ++#include "vect.h" ++#include "trace.h" + + /* There are two PLT types on 32-bit PPC: old-style, BSS PLT, and + * new-style "secure" PLT. We can tell one from the other by the +@@ -104,6 +107,21 @@ + * through half the dynamic linker, we just let the thread run and hit + * this breakpoint. When it hits, we know the PLT entry was resolved. + * ++ * Another twist comes from tracing slots corresponding to ++ * R_PPC64_JMP_IREL relocations. These have no dedicated PLT entry. ++ * The calls are done directly from stubs, and the .plt entry ++ * (actually .iplt entry, these live in a special section) is resolved ++ * in advance before the binary starts. Because there's no PLT entry, ++ * we put the PLT breakpoints directly to the IFUNC resolver code, and ++ * then would like them to behave like ordinary PLT slots, including ++ * catching the point where these get resolved to unresolve them. So ++ * for the first call (which is the actual resolver call), we pretend ++ * that this breakpoint is artificial and has no associated symbol, ++ * and turn it on fully only after the first hit. Ideally we would ++ * trace that first call as well, but then the stepper, which tries to ++ * catch the point where the slot is resolved, would hit the return ++ * breakpoint and that's not currently handled well. ++ * + * XXX TODO If we have hardware watch point, we might put a read watch + * on .plt slot, and discover the offenders this way. I don't know + * the details, but I assume at most a handful (like, one or two, if +@@ -177,10 +195,48 @@ mark_as_resolved(struct library_symbol * + libsym->arch.resolved_value = value; + } + ++static void ++ppc32_delayed_symbol(struct library_symbol *libsym) ++{ ++ /* arch_dynlink_done is called on attach as well. In that ++ * case some slots will have been resolved already. ++ * Unresolved PLT looks like this: ++ * ++ * <sleep@plt>: li r11,0 ++ * <sleep@plt+4>: b "resolve" ++ * ++ * "resolve" is another address in PLTGOT (the same block that ++ * all the PLT slots are it). When resolved, it looks either ++ * this way: ++ * ++ * <sleep@plt>: b 0xfea88d0 <sleep> ++ * ++ * Which is easy to detect. It can also look this way: ++ * ++ * <sleep@plt>: li r11,0 ++ * <sleep@plt+4>: b "dispatch" ++ * ++ * The "dispatch" address lies in PLTGOT as well. In current ++ * GNU toolchain, "dispatch" address is the same as PLTGOT ++ * address. We rely on this to figure out whether the address ++ * is resolved or not. */ ++ ++ uint32_t insn1 = libsym->arch.resolved_value >> 32; ++ uint32_t insn2 = (uint32_t) libsym->arch.resolved_value; ++ if ((insn1 & BRANCH_MASK) == B_INSN ++ || ((insn2 & BRANCH_MASK) == B_INSN ++ /* XXX double cast */ ++ && (ppc_branch_dest(libsym->enter_addr + 4, insn2) ++ == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr))) ++ { ++ mark_as_resolved(libsym, libsym->arch.resolved_value); ++ } ++} ++ + void + arch_dynlink_done(struct Process *proc) + { +- /* On PPC32 with BSS PLT, we need to enable delayed symbols. */ ++ /* We may need to activate delayed symbols. */ + struct library_symbol *libsym = NULL; + while ((libsym = proc_each_symbol(proc, libsym, + library_symbol_delayed_cb, NULL))) { +@@ -193,47 +249,37 @@ arch_dynlink_done(struct Process *proc) + return; + } + +- /* arch_dynlink_done is called on attach as well. In +- * that case some slots will have been resolved +- * already. Unresolved PLT looks like this: +- * +- * <sleep@plt>: li r11,0 +- * <sleep@plt+4>: b "resolve" +- * +- * "resolve" is another address in PLTGOT (the same +- * block that all the PLT slots are it). When +- * resolved, it looks either this way: +- * +- * <sleep@plt>: b 0xfea88d0 <sleep> +- * +- * Which is easy to detect. It can also look this +- * way: +- * +- * <sleep@plt>: li r11,0 +- * <sleep@plt+4>: b "dispatch" +- * +- * The "dispatch" address lies in PLTGOT as well. In +- * current GNU toolchain, "dispatch" address is the +- * same as PLTGOT address. We rely on this to figure +- * out whether the address is resolved or not. */ +- uint32_t insn1 = libsym->arch.resolved_value >> 32; +- uint32_t insn2 = (uint32_t)libsym->arch.resolved_value; +- if ((insn1 & BRANCH_MASK) == B_INSN +- || ((insn2 & BRANCH_MASK) == B_INSN +- /* XXX double cast */ +- && (ppc_branch_dest(libsym->enter_addr + 4, insn2) +- == (void*)(long)libsym->lib->arch.pltgot_addr))) +- mark_as_resolved(libsym, libsym->arch.resolved_value); ++ if (proc->e_machine == EM_PPC) ++ ppc32_delayed_symbol(libsym); + ++ fprintf(stderr, "activating %s\n", libsym->name); + if (proc_activate_delayed_symbol(proc, libsym) < 0) + return; + +- /* XXX double cast */ +- libsym->arch.plt_slot_addr +- = (GElf_Addr)(uintptr_t)libsym->enter_addr; ++ if (proc->e_machine == EM_PPC) ++ /* XXX double cast */ ++ libsym->arch.plt_slot_addr ++ = (GElf_Addr) (uintptr_t) libsym->enter_addr; + } + } + ++static bool ++reloc_is_irelative(int machine, GElf_Rela *rela) ++{ ++ bool irelative = false; ++ if (machine == EM_PPC64) { ++#ifdef R_PPC64_JMP_IREL ++ irelative = GELF_R_TYPE(rela->r_info) == R_PPC64_JMP_IREL; ++#endif ++ } else { ++ assert(machine == EM_PPC); ++#ifdef R_PPC_IRELATIVE ++ irelative = GELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE; ++#endif ++ } ++ return irelative; ++} ++ + GElf_Addr + arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) + { +@@ -244,10 +290,28 @@ arch_plt_sym_val(struct ltelf *lte, size + } else if (lte->ehdr.e_machine == EM_PPC) { + return rela->r_offset; + ++ /* Beyond this point, we are on PPC64, but don't have stub ++ * symbols. */ ++ ++ } else if (reloc_is_irelative(lte->ehdr.e_machine, rela)) { ++ ++ /* Put JMP_IREL breakpoint to resolver, since there's ++ * no dedicated PLT entry. */ ++ ++ assert(rela->r_addend != 0); ++ /* XXX double cast */ ++ arch_addr_t res_addr = (arch_addr_t) (uintptr_t) rela->r_addend; ++ if (arch_translate_address(lte, res_addr, &res_addr) < 0) { ++ fprintf(stderr, "Couldn't OPD-translate IRELATIVE " ++ "resolver address.\n"); ++ return 0; ++ } ++ /* XXX double cast */ ++ return (GElf_Addr) (uintptr_t) res_addr; ++ + } else { +- /* If we get here, we don't have stub symbols. In +- * that case we put brakpoints to PLT entries the same +- * as the PPC32 secure PLT case does. */ ++ /* We put brakpoints to PLT entries the same as the ++ * PPC32 secure PLT case does. */ + assert(lte->arch.plt_stub_vma != 0); + return lte->arch.plt_stub_vma + PPC64_PLT_STUB_SIZE * ndx; + } +@@ -425,6 +489,15 @@ nonzero_data(Elf_Data *data) + return 0; + } + ++static enum callback_status ++reloc_copy_if_irelative(GElf_Rela *rela, void *data) ++{ ++ struct ltelf *lte = data; ++ ++ return CBS_STOP_IF(reloc_is_irelative(lte->ehdr.e_machine, rela) ++ && VECT_PUSHBACK(<e->plt_relocs, rela) < 0); ++} ++ + int + arch_elf_init(struct ltelf *lte, struct library *lib) + { +@@ -453,8 +526,7 @@ arch_elf_init(struct ltelf *lte, struct + } + GElf_Addr glink_vma = get_glink_vma(lte, ppcgot, lte->plt_data); + +- assert(lte->relplt_size % 12 == 0); +- size_t count = lte->relplt_size / 12; // size of RELA entry ++ size_t count = vect_size(<e->plt_relocs); + lte->arch.plt_stub_vma = glink_vma + - (GElf_Addr)count * PPC_PLT_STUB_SIZE; + debug(1, "stub_vma is %#" PRIx64, lte->arch.plt_stub_vma); +@@ -556,6 +628,35 @@ arch_elf_init(struct ltelf *lte, struct + } + } + ++ /* On PPC64, IRELATIVE relocations actually relocate .iplt ++ * section, and as such are stored in .rela.dyn (where all ++ * non-PLT relocations are stored) instead of .rela.plt. Add ++ * these to lte->plt_relocs. */ ++ extern int read_relplt(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr, ++ struct vect *ret); ++ ++ GElf_Addr rela, relasz; ++ Elf_Scn *rela_sec; ++ GElf_Shdr rela_shdr; ++ if (lte->ehdr.e_machine == EM_PPC64 ++ && load_dynamic_entry(lte, DT_RELA, &rela) == 0 ++ && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0 ++ && elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0 ++ && rela_sec != NULL) { ++ ++ struct vect v; ++ VECT_INIT(&v, GElf_Rela); ++ int ret = read_relplt(lte, rela_sec, &rela_shdr, &v); ++ if (ret >= 0 ++ && VECT_EACH(&v, GElf_Rela, NULL, ++ reloc_copy_if_irelative, lte) != NULL) ++ ret = -1; ++ ++ VECT_DESTROY(&v, GElf_Rela, NULL, NULL); ++ ++ if (ret < 0) ++ return ret; ++ } + return 0; + } + +@@ -616,6 +717,16 @@ arch_elf_add_plt_entry(struct Process *p + return plt_ok; + } + ++ bool is_irelative = reloc_is_irelative(lte->ehdr.e_machine, rela); ++ char *name; ++ if (is_irelative) ++ name = linux_elf_find_irelative_name(lte, rela); ++ else ++ name = strdup(a_name); ++ ++ if (name == NULL) ++ return plt_fail; ++ + /* PPC64. If we have stubs, we return a chain of breakpoint + * sites, one for each stub that corresponds to this PLT + * entry. */ +@@ -623,7 +734,7 @@ arch_elf_add_plt_entry(struct Process *p + struct library_symbol **symp; + for (symp = <e->arch.stubs; *symp != NULL; ) { + struct library_symbol *sym = *symp; +- if (strcmp(sym->name, a_name) != 0) { ++ if (strcmp(sym->name, name) != 0) { + symp = &(*symp)->next; + continue; + } +@@ -636,6 +747,7 @@ arch_elf_add_plt_entry(struct Process *p + + if (chain != NULL) { + *ret = chain; ++ free(name); + return plt_ok; + } + +@@ -652,12 +764,13 @@ arch_elf_add_plt_entry(struct Process *p + || plt_slot_addr < lte->plt_addr + lte->plt_size); + + GElf_Addr plt_slot_value; +- if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) ++ if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) { ++ free(name); + return plt_fail; ++ } + +- char *name = strdup(a_name); + struct library_symbol *libsym = malloc(sizeof(*libsym)); +- if (name == NULL || libsym == NULL) { ++ if (libsym == NULL) { + fprintf(stderr, "allocation for .plt slot: %s\n", + strerror(errno)); + fail: +@@ -669,12 +782,13 @@ arch_elf_add_plt_entry(struct Process *p + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + if (library_symbol_init(libsym, +- (arch_addr_t)(uintptr_t)plt_entry_addr, ++ (arch_addr_t) (uintptr_t) plt_entry_addr, + name, 1, LS_TOPLT_EXEC) < 0) + goto fail; + libsym->arch.plt_slot_addr = plt_slot_addr; + +- if (plt_slot_value == plt_entry_addr || plt_slot_value == 0) { ++ if (! is_irelative ++ && (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) { + libsym->arch.type = PPC_PLT_UNRESOLVED; + libsym->arch.resolved_value = plt_entry_addr; + +@@ -692,7 +806,13 @@ arch_elf_add_plt_entry(struct Process *p + library_symbol_destroy(libsym); + goto fail; + } +- mark_as_resolved(libsym, plt_slot_value); ++ ++ if (! is_irelative) { ++ mark_as_resolved(libsym, plt_slot_value); ++ } else { ++ libsym->arch.type = PPC_PLT_IRELATIVE; ++ libsym->arch.resolved_value = plt_entry_addr; ++ } + } + + *ret = libsym; +@@ -839,6 +959,15 @@ jump_to_entry_point(struct Process *proc + static void + ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc) + { ++ /* If this is a first call through IREL breakpoint, enable the ++ * symbol so that it doesn't look like an artificial ++ * breakpoint anymore. */ ++ if (bp->libsym == NULL) { ++ assert(bp->arch.irel_libsym != NULL); ++ bp->libsym = bp->arch.irel_libsym; ++ bp->arch.irel_libsym = NULL; ++ } ++ + switch (bp->libsym->arch.type) { + struct Process *leader; + void (*on_all_stopped)(struct process_stopping_handler *); +@@ -851,6 +980,7 @@ ppc_plt_bp_continue(struct breakpoint *b + assert(bp->libsym->lib->arch.bss_plt_prelinked == 0); + /* Fall through. */ + ++ case PPC_PLT_IRELATIVE: + case PPC_PLT_UNRESOLVED: + on_all_stopped = NULL; + keep_stepping_p = NULL; +@@ -977,6 +1107,8 @@ arch_library_symbol_clone(struct library + int + arch_breakpoint_init(struct Process *proc, struct breakpoint *bp) + { ++ bp->arch.irel_libsym = NULL; ++ + /* Artificial and entry-point breakpoints are plain. */ + if (bp->libsym == NULL || bp->libsym->plt_type != LS_TOPLT_EXEC) + return 0; +@@ -996,6 +1128,14 @@ arch_breakpoint_init(struct Process *pro + .on_retract = ppc_plt_bp_retract, + }; + breakpoint_set_callbacks(bp, &cbs); ++ ++ /* For JMP_IREL breakpoints, make the breakpoint look ++ * artificial by hiding the symbol. */ ++ if (bp->libsym->arch.type == PPC_PLT_IRELATIVE) { ++ bp->arch.irel_libsym = bp->libsym; ++ bp->libsym = NULL; ++ } ++ + return 0; + } + +Index: b/callback.h +=================================================================== +--- a/callback.h ++++ b/callback.h +@@ -47,4 +47,7 @@ enum callback_status { + * and return error. */ + }; + ++#define CBS_STOP_IF(X) ((X) ? CBS_STOP : CBS_CONT) ++#define CBS_CONT_IF(X) ((X) ? CBS_CONT : CBS_STOP) ++ + #endif /* _CALLBACK_H_ */ diff -Nru ltrace-0.7.3/debian/patches/keep_plt_reloc_in_vector_673ff510.patch ltrace-0.7.3/debian/patches/keep_plt_reloc_in_vector_673ff510.patch --- ltrace-0.7.3/debian/patches/keep_plt_reloc_in_vector_673ff510.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/keep_plt_reloc_in_vector_673ff510.patch 2016-12-04 23:23:04.000000000 +0100 @@ -0,0 +1,450 @@ +From 673ff510953b65b844a58478aa434120f457c014 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Fri, 25 Oct 2013 23:45:39 +0200 +Subject: Keep PLT relocations in a vector + +- That means we have to copy them out of ELF ahead of time instead of + referencing them from inside ELF on demand. But this way we can keep + one grand vector of all PLT-like relocations. On PPC, this makes + a difference: some PLT-like relocations (R_PPC64_JMP_IREL in + particular) are stored in .rela.dyn, not .rela.plt. +--- + libltrace.c | 8 - + ltrace-elf.c | 195 +++++++++++++++++++++++++------------------ + ltrace-elf.h | 17 +-- + sysdeps/linux-gnu/mips/plt.c | 3 + 4 files changed, 129 insertions(+), 94 deletions(-) + +Index: b/libltrace.c +=================================================================== +--- a/libltrace.c ++++ b/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); +Index: b/ltrace-elf.c +=================================================================== +--- a/ltrace-elf.c ++++ b/ltrace-elf.c +@@ -242,8 +242,9 @@ DEF_READER(elf_read_u64, 64) + #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; +@@ -293,9 +294,20 @@ open_elf(struct ltelf *lte, const char * + 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, +@@ -333,13 +345,86 @@ read_symbol_table(struct ltelf *lte, con + } + + 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) { +@@ -398,7 +483,7 @@ do_init_elf(struct ltelf *lte, const cha + 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; + } +@@ -431,14 +516,9 @@ do_init_elf(struct ltelf *lte, const cha + + 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; +@@ -451,12 +531,9 @@ do_init_elf(struct ltelf *lte, const cha + 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)); +@@ -472,9 +549,9 @@ do_init_elf(struct ltelf *lte, const cha + 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; +@@ -482,51 +559,13 @@ do_init_elf(struct ltelf *lte, const cha + 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 + +@@ -544,12 +583,13 @@ populate_plt(struct Process *proc, const + 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)) + continue; /* Skip this entry. */ + + char const *name = lte->dynstr + sym.st_name; +@@ -558,14 +598,14 @@ populate_plt(struct Process *proc, const + name, lib); + 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; + case plt_ok: + /* If we didn't match the PLT entry up there, +@@ -826,8 +866,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 +@@ -835,8 +875,8 @@ read_module(struct library *lib, struct + * + * 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. */ +@@ -851,6 +891,8 @@ read_module(struct library *lib, struct + 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 +@@ -875,19 +917,18 @@ read_module(struct library *lib, struct + 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; + +@@ -953,13 +994,9 @@ read_module(struct library *lib, struct + 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 +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -27,6 +27,7 @@ + #include <gelf.h> + #include <stdlib.h> + #include "sysdep.h" ++#include "vect.h" + + struct Process; + struct library; +@@ -48,9 +49,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; +@@ -60,15 +63,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 +@@ -91,11 +93,6 @@ int default_elf_add_plt_entry(struct Pro + 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); +Index: b/sysdeps/linux-gnu/mips/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/mips/plt.c ++++ b/sysdeps/linux-gnu/mips/plt.c +@@ -159,7 +159,8 @@ arch_get_sym_info(struct ltelf *lte, con + const char *name; + + if (mips_elf_is_cpic(lte->ehdr.e_flags)) { +- 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; + } + + /* Fixup the offset. */ diff -Nru ltrace-0.7.3/debian/patches/More-testsuite-typo ltrace-0.7.3/debian/patches/More-testsuite-typo --- ltrace-0.7.3/debian/patches/More-testsuite-typo 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/More-testsuite-typo 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,29 @@ +Description: Fix testsuite typo and include + . + . + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> + +--- + +--- ltrace-0.7.3.orig/testsuite/ltrace.main/parameters.c ++++ ltrace-0.7.3/testsuite/ltrace.main/parameters.c +@@ -17,6 +17,7 @@ void func_intptr_ret(int *i); + int func_strlen(char*); + void func_strfixed(char*); + void func_ppp(int***); ++void func_string(char*); + void func_stringp(char**); + void func_short(short, short); + void func_ushort(unsigned short, unsigned short); +--- ltrace-0.7.3.orig/testsuite/ltrace.minor/trace-fork.c ++++ ltrace-0.7.3/testsuite/ltrace.minor/trace-fork.c +@@ -7,6 +7,7 @@ + #include <stdio.h> + #include <sys/types.h> + #include <unistd.h> ++#include <wait.h> + + void + child () diff -Nru ltrace-0.7.3/debian/patches/Move-get_hfa_type-from-IA64-backend-to-type.c-name-i.patch ltrace-0.7.3/debian/patches/Move-get_hfa_type-from-IA64-backend-to-type.c-name-i.patch --- ltrace-0.7.3/debian/patches/Move-get_hfa_type-from-IA64-backend-to-type.c-name-i.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/Move-get_hfa_type-from-IA64-backend-to-type.c-name-i.patch 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,163 @@ +Author: Petr Machata <pmach...@apm-mustang-ev2-02.ml3.eng.bos.redhat.com> +Description: Move get_hfa_type from IA64 backend to type.c, name it type_get_hfa_type +Applied-Upstream: http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=982cbca34b2b49a158086ff5f43eb9bba89edead +Last-Update: 2014-03-13 + +Index: ltrace/sysdeps/linux-gnu/ia64/fetch.c +=================================================================== +--- ltrace.orig/sysdeps/linux-gnu/ia64/fetch.c 2014-03-12 16:13:44.075726000 -0600 ++++ ltrace/sysdeps/linux-gnu/ia64/fetch.c 2014-03-13 09:32:30.504762084 -0600 +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Steve Fink + * Copyright (C) 2006 Ian Wienand +@@ -249,37 +249,6 @@ + return 0; + } + +-static enum arg_type +-get_hfa_type(struct arg_type_info *info, size_t *countp) +-{ +- size_t n = type_aggregate_size(info); +- if (n == (size_t)-1) +- return ARGTYPE_VOID; +- +- enum arg_type type = ARGTYPE_VOID; +- *countp = 0; +- +- while (n-- > 0) { +- struct arg_type_info *emt = type_element(info, n); +- +- enum arg_type emt_type = emt->type; +- size_t emt_count = 1; +- if (emt_type == ARGTYPE_STRUCT || emt_type == ARGTYPE_ARRAY) +- emt_type = get_hfa_type(emt, &emt_count); +- +- if (type == ARGTYPE_VOID) { +- if (emt_type != ARGTYPE_FLOAT +- && emt_type != ARGTYPE_DOUBLE) +- return ARGTYPE_VOID; +- type = emt_type; +- } +- if (emt_type != type) +- return ARGTYPE_VOID; +- *countp += emt_count; +- } +- return type; +-} +- + static int + allocate_hfa(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, +@@ -380,10 +349,11 @@ + * floating-point registers, beginning with f8. */ + if (info->type == ARGTYPE_STRUCT || info->type == ARGTYPE_ARRAY) { + size_t hfa_size; +- enum arg_type hfa_type = get_hfa_type(info, &hfa_size); +- if (hfa_type != ARGTYPE_VOID && hfa_size <= 8) ++ struct arg_type_info *hfa_info ++ = type_get_hfa_type(info, &hfa_size); ++ if (hfa_info != NULL && hfa_size <= 8) + return allocate_hfa(ctx, proc, info, valuep, +- hfa_type, hfa_size); ++ hfa_info->type, hfa_size); + } + + /* Integers and pointers are passed in r8. 128-bit integers +@@ -409,7 +379,7 @@ + struct arg_type_info *info, struct value *valuep) + { + switch (info->type) { +- enum arg_type hfa_type; ++ struct arg_type_info *hfa_info; + size_t hfa_size; + + case ARGTYPE_VOID: +@@ -421,10 +391,10 @@ + return allocate_float(ctx, proc, info, valuep, 1); + + case ARGTYPE_STRUCT: +- hfa_type = get_hfa_type(info, &hfa_size); +- if (hfa_type != ARGTYPE_VOID) ++ hfa_info = type_get_hfa_type(info, &hfa_size); ++ if (hfa_info != NULL) + return allocate_hfa(ctx, proc, info, valuep, +- hfa_type, hfa_size); ++ hfa_info->type, hfa_size); + /* Fall through. */ + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: +Index: ltrace/type.c +=================================================================== +--- ltrace.orig/type.c 2014-03-12 16:13:44.075726000 -0600 ++++ ltrace/type.c 2014-03-13 09:32:30.504762084 -0600 +@@ -568,3 +568,39 @@ + } + abort(); + } ++ ++struct arg_type_info * ++type_get_hfa_type(struct arg_type_info *info, size_t *countp) ++{ ++ assert(info != NULL); ++ if (info->type != ARGTYPE_STRUCT ++ && info->type != ARGTYPE_ARRAY) ++ return NULL; ++ ++ size_t n = type_aggregate_size(info); ++ if (n == (size_t)-1) ++ return NULL; ++ ++ struct arg_type_info *ret = NULL; ++ *countp = 0; ++ ++ while (n-- > 0) { ++ struct arg_type_info *emt = type_element(info, n); ++ ++ size_t emt_count = 1; ++ if (emt->type == ARGTYPE_STRUCT || emt->type == ARGTYPE_ARRAY) ++ emt = type_get_hfa_type(emt, &emt_count); ++ if (emt == NULL) ++ return NULL; ++ if (ret == NULL) { ++ if (emt->type != ARGTYPE_FLOAT ++ && emt->type != ARGTYPE_DOUBLE) ++ return NULL; ++ ret = emt; ++ } ++ if (emt->type != ret->type) ++ return NULL; ++ *countp += emt_count; ++ } ++ return ret; ++} +Index: ltrace/type.h +=================================================================== +--- ltrace.orig/type.h 2014-03-12 16:13:44.075726000 -0600 ++++ ltrace/type.h 2014-03-13 09:32:30.504762084 -0600 +@@ -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) 1997-2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or +@@ -142,4 +142,13 @@ + * type. */ + struct arg_type_info *type_get_fp_equivalent(struct arg_type_info *info); + ++/* If INFO is homogeneous floating-point aggregate, return the ++ * corresponding floating point type, and set *COUNTP to number of ++ * fields of the structure. Otherwise return NULL. INFO is a HFA if ++ * it's an aggregate whose each field is either a HFA, or a ++ * floating-point type. */ ++struct arg_type_info *type_get_hfa_type(struct arg_type_info *info, ++ size_t *countp); ++ ++ + #endif /* TYPE_H */ diff -Nru ltrace-0.7.3/debian/patches/on_install_breakpoint_56134ff5.patch ltrace-0.7.3/debian/patches/on_install_breakpoint_56134ff5.patch --- ltrace-0.7.3/debian/patches/on_install_breakpoint_56134ff5.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/on_install_breakpoint_56134ff5.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,78 @@ +From 56134ff5442bee4e128b189bb86cfc97dcb6f60a Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Fri, 10 Jan 2014 20:05:15 +0100 +Subject: Add a new per-breakpoint callback on_install + +--- + breakpoint.h | 9 ++++++++- + breakpoints.c | 11 ++++++++++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +Index: b/breakpoint.h +=================================================================== +--- a/breakpoint.h ++++ b/breakpoint.h +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc. + * Copyright (C) 2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or +@@ -48,6 +48,7 @@ struct breakpoint; + struct bp_callbacks { + void (*on_hit)(struct breakpoint *bp, struct Process *proc); + void (*on_continue)(struct breakpoint *bp, struct Process *proc); ++ void (*on_install)(struct breakpoint *bp, struct Process *proc); + void (*on_retract)(struct breakpoint *bp, struct Process *proc); + }; + +@@ -67,6 +68,12 @@ void breakpoint_on_hit(struct breakpoint + * continue_after_breakpoint. */ + void breakpoint_on_continue(struct breakpoint *bp, struct Process *proc); + ++/* Call ON_INSTALL handler of BP, if any is set. This should be ++ * called after the breakpoint is enabled for the first time, not ++ * every time it's enabled (such as after stepping over a site of a ++ * temporarily disabled breakpoint). */ ++void breakpoint_on_install(struct breakpoint *bp, struct Process *proc); ++ + /* Call on-retract handler of BP, if any is set. This should be + * called before the breakpoints are destroyed. The reason for a + * separate interface is that breakpoint_destroy has to be callable +Index: b/breakpoints.c +=================================================================== +--- a/breakpoints.c ++++ b/breakpoints.c +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2006,2007,2011,2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2006,2007,2011,2012,2013,2014 Petr Machata, Red Hat Inc. + * Copyright (C) 2009 Juan Cespedes + * Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand +@@ -78,6 +78,14 @@ breakpoint_on_continue(struct breakpoint + } + + void ++breakpoint_on_install(struct breakpoint *bp, struct Process *proc) ++{ ++ assert(bp != NULL); ++ if (bp->cbs != NULL && bp->cbs->on_install != NULL) ++ (bp->cbs->on_install)(bp, proc); ++} ++ ++void + breakpoint_on_retract(struct breakpoint *bp, struct Process *proc) + { + assert(bp != NULL); +@@ -181,6 +189,7 @@ breakpoint_turn_on(struct breakpoint *bp + if (bp->enabled == 1) { + assert(proc->pid != 0); + enable_breakpoint(proc, bp); ++ breakpoint_on_install(bp, proc); + } + return 0; + } diff -Nru ltrace-0.7.3/debian/patches/ppc64el.diff ltrace-0.7.3/debian/patches/ppc64el.diff --- ltrace-0.7.3/debian/patches/ppc64el.diff 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc64el.diff 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,705 @@ +From eea4ad2cce289753aaa35b4e0258a76d8f8f367c Mon Sep 17 00:00:00 2001 +From: Thierry Fauck <thie...@linux.vnet.ibm.com> +Date: Tue, 13 May 2014 07:48:24 -0400 +Subject: [PATCH] Support for powerpc64 arch ppc64el + +Signed-off-by: Thierry Fauck <thie...@linux.vnet.ibm.com> + + Add support for ppc64le proc and ELF ABIv2. + Provides support for irelative and wchar +--- + configure.ac | 4 + ltrace-elf.h | 1 + sysdeps/linux-gnu/ppc/arch.h | 35 +++++- + sysdeps/linux-gnu/ppc/fetch.c | 244 ++++++++++++++++++++++++++++++++++++++---- + sysdeps/linux-gnu/ppc/plt.c | 51 +++++++- + sysdeps/linux-gnu/ppc/trace.c | 10 + + 6 files changed, 309 insertions(+), 36 deletions(-) + +Index: b/ltrace-elf.h +=================================================================== +--- a/ltrace-elf.h ++++ b/ltrace-elf.h +@@ -136,6 +136,7 @@ int elf_read_next_uleb128(Elf_Data *data + /* Return whether there's AMOUNT more bytes after OFFSET in DATA. */ + int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount); + ++void delete_symbol_chain(struct library_symbol *); + #if __WORDSIZE == 32 + #define PRI_ELF_ADDR PRIx32 + #define GELF_ADDR_CAST(x) (void *)(uint32_t)(x) +Index: b/sysdeps/linux-gnu/ppc/arch.h +=================================================================== +--- a/sysdeps/linux-gnu/ppc/arch.h ++++ b/sysdeps/linux-gnu/ppc/arch.h +@@ -23,8 +23,8 @@ + #define LTRACE_PPC_ARCH_H + + #include <gelf.h> ++#include <stdbool.h> + +-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } + #define BREAKPOINT_LENGTH 4 + #define DECR_PC_AFTER_BREAK 0 + +@@ -34,15 +34,39 @@ + #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target. + #define LT_ELFCLASS2 ELFCLASS64 + #define LT_ELF_MACHINE2 EM_PPC64 +-#define ARCH_SUPPORTS_OPD +-#endif ++ ++# ifdef __LITTLE_ENDIAN__ ++# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f } ++# define ARCH_ENDIAN_LITTLE ++# else ++# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } ++# define ARCH_SUPPORTS_OPD ++# define ARCH_ENDIAN_BIG ++# endif ++ ++# if _CALL_ELF != 2 ++# define ARCH_SUPPORTS_OPD ++# define STACK_FRAME_OVERHEAD 112 ++# ifndef EF_PPC64_ABI ++# define EF_PPC64_ABI 3 ++# endif ++# else /* _CALL_ELF == 2 ABIv2 */ ++# define STACK_FRAME_OVERHEAD 32 ++# endif /* CALL_ELF */ ++ ++#else ++#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } ++#define ARCH_ENDIAN_BIG ++# ifndef EF_PPC64_ABI ++# define EF_PPC64_ABI 3 ++# endif ++#endif /* __powerpc64__ */ + + #define ARCH_HAVE_ATOMIC_SINGLESTEP + #define ARCH_HAVE_ADD_PLT_ENTRY + #define ARCH_HAVE_TRANSLATE_ADDRESS + #define ARCH_HAVE_DYNLINK_DONE + #define ARCH_HAVE_FETCH_ARG +-#define ARCH_ENDIAN_BIG + #define ARCH_HAVE_SIZEOF + #define ARCH_HAVE_ALIGNOF + +@@ -55,7 +79,8 @@ struct arch_ltelf_data { + Elf_Data *opd_data; + GElf_Addr opd_base; + GElf_Xword opd_size; +- int secure_plt; ++ bool secure_plt : 1; ++ bool elfv2_abi : 1; + + Elf_Data *reladyn; + size_t reladyn_count; +Index: b/sysdeps/linux-gnu/ppc/fetch.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/fetch.c ++++ b/sysdeps/linux-gnu/ppc/fetch.c +@@ -30,9 +30,11 @@ + #include "ptrace.h" + #include "proc.h" + #include "value.h" ++#include "ltrace-elf.h" + + static int allocate_gpr(struct fetch_context *ctx, struct Process *proc, +- struct arg_type_info *info, struct value *valuep); ++ struct arg_type_info *info, struct value *valuep, ++ size_t off, bool is_hfa_type); + + /* Floating point registers have the same width on 32-bit as well as + * 64-bit PPC, but <ucontext.h> presents a different API depending on +@@ -62,7 +64,10 @@ struct fetch_context { + gregs64_t r64; + } regs; + struct fpregs_t fpregs; +- ++ int vgreg; ++ int struct_size; ++ int struct_hfa_size; ++ int struct_hfa_count; + }; + + static int +@@ -74,7 +79,8 @@ fetch_context_init(struct Process *proc, + if (proc->e_machine == EM_PPC) + context->stack_pointer = proc->stack_pointer + 8; + else +- context->stack_pointer = proc->stack_pointer + 112; ++ context->stack_pointer = proc->stack_pointer ++ + STACK_FRAME_OVERHEAD; + + /* When ltrace is 64-bit, we might use PTRACE_GETREGS to + * obtain 64-bit as well as 32-bit registers. But if we do it +@@ -118,6 +124,11 @@ arch_fetch_arg_init(enum tof type, struc + return NULL; + } + ++ context->vgreg = context->greg; ++ context->struct_size = 0; ++ context->struct_hfa_size = 0; ++ context->struct_hfa_count = 0; ++ + /* Aggregates or unions of any length, and character strings + * of length longer than 8 bytes, will be returned in a + * storage buffer allocated by the caller. The caller will +@@ -125,8 +136,20 @@ arch_fetch_arg_init(enum tof type, struc + * in r3, causing the first explicit argument to be passed in + * r4. */ + context->ret_struct = ret_info->type == ARGTYPE_STRUCT; +- if (context->ret_struct) ++ if (context->ret_struct) { ++#if _CALL_ELF == 2 ++ /* if R3 points to stack, parameters will be in R4. */ ++ uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid, ++ proc->stack_pointer, 0); ++ if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer) ++ && (context->regs.r64[3] < pstack_end)) { ++ context->greg++; ++ context->stack_pointer += 8; ++ } ++#else + context->greg++; ++#endif ++ } + + return context; + } +@@ -144,7 +167,8 @@ arch_fetch_arg_clone(struct Process *pro + + static int + allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, +- struct arg_type_info *info, struct value *valuep) ++ struct arg_type_info *info, struct value *valuep, ++ bool is_hfa_type) + { + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) +@@ -154,7 +178,14 @@ allocate_stack_slot(struct fetch_context + size_t off = 0; + if (proc->e_machine == EM_PPC && a < 4) + a = 4; ++#if _CALL_ELF == 2 ++ else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type) ++ a = 4; ++ else ++ a = 8; ++#else + else if (proc->e_machine == EM_PPC64 && a < 8) ++#endif + a = 8; + + /* XXX Remove the two double casts when arch_addr_t +@@ -164,7 +195,7 @@ allocate_stack_slot(struct fetch_context + + if (valuep != NULL) + value_in_inferior(valuep, ctx->stack_pointer + off); +- ctx->stack_pointer += sz; ++ ctx->stack_pointer += a; + + return 0; + } +@@ -216,19 +247,34 @@ align_small_int(unsigned char *buf, size + + static int + allocate_gpr(struct fetch_context *ctx, struct Process *proc, +- struct arg_type_info *info, struct value *valuep) ++ struct arg_type_info *info, struct value *valuep, ++ size_t off, bool is_hfa_type) + { + if (ctx->greg > 10) +- return allocate_stack_slot(ctx, proc, info, valuep); ++ return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type); + +- int reg_num = ctx->greg++; +- if (valuep == NULL) +- return 0; ++ int reg_num = ctx->greg; + + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + assert(sz == 1 || sz == 2 || sz == 4 || sz == 8); ++#if _CALL_ELF == 2 ++ /* Consume the stack slot corresponding to this arg. */ ++ if ((sz + off) >= 8) ++ ctx->greg++; ++ ++ if (is_hfa_type) ++ ctx->stack_pointer += sz; ++ else ++ ctx->stack_pointer += 8; ++#else ++ ctx->greg++; ++#endif ++ ++ if (valuep == NULL) ++ return 0; ++ + if (value_reserve(valuep, sz) == NULL) + return -1; + +@@ -240,13 +286,14 @@ allocate_gpr(struct fetch_context *ctx, + u.i64 = read_gpr(ctx, proc, reg_num); + if (proc->e_machine == EM_PPC) + align_small_int(u.buf, 8, sz); +- memcpy(value_get_raw_data(valuep), u.buf, sz); ++ memcpy(value_get_raw_data(valuep), u.buf + off, sz); + return 0; + } + + static int + allocate_float(struct fetch_context *ctx, struct Process *proc, +- struct arg_type_info *info, struct value *valuep) ++ struct arg_type_info *info, struct value *valuep, ++ size_t off, bool is_hfa_type) + { + int pool = proc->e_machine == EM_PPC64 ? 13 : 8; + if (ctx->freg <= pool) { +@@ -257,8 +304,12 @@ allocate_float(struct fetch_context *ctx + } u = { .d = ctx->fpregs.fpregs[ctx->freg] }; + + ctx->freg++; ++ ++ if (!is_hfa_type) ++ ctx->vgreg++; ++ + if (proc->e_machine == EM_PPC64) +- allocate_gpr(ctx, proc, info, NULL); ++ allocate_gpr(ctx, proc, info, NULL, off, is_hfa_type); + + size_t sz = sizeof(double); + if (info->type == ARGTYPE_FLOAT) { +@@ -272,9 +323,129 @@ allocate_float(struct fetch_context *ctx + memcpy(value_get_raw_data(valuep), u.buf, sz); + return 0; + } +- return allocate_stack_slot(ctx, proc, info, valuep); ++ return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type); + } + ++#if _CALL_ELF == 2 ++static int ++allocate_hfa(struct fetch_context *ctx, struct Process *proc, ++ struct arg_type_info *info, struct value *valuep, ++ enum arg_type hfa_type, size_t hfa_count) ++{ ++ size_t sz = type_sizeof(proc, info); ++ if (sz == (size_t)-1) ++ return -1; ++ ++ ctx->struct_hfa_size += sz; ++ ++ /* There are two changes regarding structure return types: ++ * * heterogeneous float/vector structs are returned ++ * in (multiple) FP/vector registers, ++ * instead of via implicit reference. ++ * * small structs (up to 16 bytes) are return ++ * in one or two GPRs, instead of via implicit reference. ++ * ++ * Other structures (larger than 16 bytes, not heterogeneous) ++ * are still returned via implicit reference (i.e. a pointer ++ * to memory where to return the struct being passed in r3). ++ * Of course, whether or not an implicit reference pointer ++ * is present will shift the remaining arguments, ++ * so you need to get this right for ELFv2 in order ++ * to get the arguments correct. ++ * If an actual parameter is known to correspond to an HFA ++ * formal parameter, each element is passed in the next ++ * available floating-point argument register starting at fp1 ++ * until the fp13. The remaining elements of the aggregate are ++ * passed on the stack. */ ++ size_t slot_off = 0; ++ ++ unsigned char *buf = value_reserve(valuep, sz); ++ if (buf == NULL) ++ return -1; ++ ++ struct arg_type_info *hfa_info = type_get_simple(hfa_type); ++ size_t hfa_sz = type_sizeof(proc, hfa_info); ++ ++ if (hfa_count > 8) ++ ctx->struct_hfa_count += hfa_count; ++ ++ while (hfa_count > 0 && ctx->freg <= 13) { ++ int rc; ++ struct value tmp; ++ ++ value_init(&tmp, proc, NULL, hfa_info, 0); ++ ++ /* Hetereogeneous struct - get value on GPR or stack. */ ++ if (((hfa_type == ARGTYPE_FLOAT ++ || hfa_type == ARGTYPE_DOUBLE) ++ && hfa_count <= 8)) ++ rc = allocate_float(ctx, proc, hfa_info, &tmp, ++ slot_off, true); ++ else ++ rc = allocate_gpr(ctx, proc, hfa_info, &tmp, ++ slot_off, true); ++ ++ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz); ++ ++ slot_off += hfa_sz; ++ buf += hfa_sz; ++ hfa_count--; ++ if (slot_off == 8) { ++ slot_off = 0; ++ ctx->vgreg++; ++ } ++ ++ value_destroy(&tmp); ++ if (rc < 0) ++ return -1; ++ } ++ if (hfa_count == 0) ++ return 0; ++ ++ /* if no remaining FP, GPR corresponding to slot is used ++ * Mostly it is in part of r10. */ ++ if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) { ++ while (ctx->vgreg <= 10) { ++ struct value tmp; ++ value_init(&tmp, proc, NULL, hfa_info, 0); ++ union { ++ uint64_t i64; ++ unsigned char buf[0]; ++ } u; ++ ++ u.i64 = read_gpr(ctx, proc, ctx->vgreg); ++ ++ memcpy(buf, u.buf + slot_off, hfa_sz); ++ slot_off += hfa_sz; ++ buf += hfa_sz; ++ hfa_count--; ++ ctx->stack_pointer += hfa_sz; ++ if (slot_off >= 8 ) { ++ slot_off = 0; ++ ctx->vgreg++; ++ } ++ value_destroy(&tmp); ++ } ++ } ++ ++ if (hfa_count == 0) ++ return 0; ++ ++ /* Remaining values are on stack */ ++ while (hfa_count) { ++ struct value tmp; ++ value_init(&tmp, proc, NULL, hfa_info, 0); ++ ++ value_in_inferior(&tmp, ctx->stack_pointer); ++ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz); ++ ctx->stack_pointer += hfa_sz; ++ buf += hfa_sz; ++ hfa_count--; ++ } ++ return 0; ++} ++#endif ++ + static int + allocate_argument(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +@@ -287,13 +458,25 @@ allocate_argument(struct fetch_context * + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: +- return allocate_float(ctx, proc, info, valuep); ++ return allocate_float(ctx, proc, info, valuep, ++ 8 - type_sizeof(proc,info), false); + + case ARGTYPE_STRUCT: + if (proc->e_machine == EM_PPC) { + if (value_pass_by_reference(valuep) < 0) + return -1; + } else { ++#if _CALL_ELF == 2 ++ struct arg_type_info *hfa_info; ++ size_t hfa_size; ++ hfa_info = type_get_hfa_type(info, &hfa_size); ++ if (hfa_info != NULL ) { ++ size_t sz = type_sizeof(proc, info); ++ ctx->struct_size += sz; ++ return allocate_hfa(ctx, proc, info, valuep, ++ hfa_info->type, hfa_size); ++ } ++#endif + /* PPC64: Fixed size aggregates and unions passed by + * value are mapped to as many doublewords of the + * parameter save area as the value uses in memory. +@@ -326,6 +509,10 @@ allocate_argument(struct fetch_context * + size_t sz = type_sizeof(proc, valuep->type); + if (sz == (size_t)-1) + return -1; ++ ++ if (ctx->ret_struct) ++ ctx->struct_size += sz; ++ + size_t slots = (sz + width - 1) / width; /* Round up. */ + unsigned char *buf = value_reserve(valuep, slots * width); + if (buf == NULL) +@@ -346,9 +533,11 @@ allocate_argument(struct fetch_context * + struct arg_type_info *fp_info + = type_get_fp_equivalent(valuep->type); + if (fp_info != NULL) +- rc = allocate_float(ctx, proc, fp_info, &val); ++ rc = allocate_float(ctx, proc, fp_info, &val, ++ 8-type_sizeof(proc,info), false); + else +- rc = allocate_gpr(ctx, proc, long_info, &val); ++ rc = allocate_gpr(ctx, proc, long_info, &val, ++ 0, false); + + if (rc >= 0) { + memcpy(ptr, value_get_data(&val, NULL), width); +@@ -363,6 +552,7 @@ allocate_argument(struct fetch_context * + return rc; + } + ++#ifndef __LITTLE_ENDIAN__ + /* Small values need post-processing. */ + if (sz < width) { + switch (info->type) { +@@ -394,6 +584,7 @@ allocate_argument(struct fetch_context * + break; + } + } ++#endif + + return 0; + } +@@ -411,7 +602,22 @@ arch_fetch_retval(struct fetch_context * + struct Process *proc, struct arg_type_info *info, + struct value *valuep) + { ++ if (fetch_context_init(proc, ctx) < 0) ++ return -1; ++ ++#if _CALL_ELF == 2 ++ void *ptr = (void *)(ctx->regs.r64[1]+32); ++ uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0); ++ ++ if (ctx->ret_struct ++ && ((ctx->struct_size > 64 ++ || ctx->struct_hfa_count > 8 ++ || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56) ++ || (ctx->regs.r64[3] == ctx->regs.r64[1]+32) ++ || (ctx->regs.r64[3] == val )))) { ++#else + if (ctx->ret_struct) { ++#endif + assert(info->type == ARGTYPE_STRUCT); + + uint64_t addr = read_gpr(ctx, proc, 3); +@@ -424,8 +630,6 @@ arch_fetch_retval(struct fetch_context * + return 0; + } + +- if (fetch_context_init(proc, ctx) < 0) +- return -1; + return allocate_argument(ctx, proc, info, valuep); + } + +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -131,7 +131,11 @@ + */ + + #define PPC_PLT_STUB_SIZE 16 +-#define PPC64_PLT_STUB_SIZE 8 //xxx ++#if _CALL_ELF != 2 ++#define PPC64_PLT_STUB_SIZE 8 ++#else ++#define PPC64_PLT_STUB_SIZE 4 ++#endif + + static inline int + host_powerpc64() +@@ -226,8 +230,13 @@ ppc32_delayed_symbol(struct library_symb + if ((insn1 & BRANCH_MASK) == B_INSN + || ((insn2 & BRANCH_MASK) == B_INSN + /* XXX double cast */ +- && (ppc_branch_dest(libsym->enter_addr + 4, insn2) +- == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr))) ++#ifdef __LITTLE_ENDIAN__ ++ && (ppc_branch_dest(libsym->enter_addr + 4, insn1) ++ == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr))) ++#else ++ && (ppc_branch_dest(libsym->enter_addr + 4, insn2) ++ == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr))) ++#endif + { + mark_as_resolved(libsym, libsym->arch.resolved_value); + } +@@ -246,7 +255,7 @@ arch_dynlink_done(struct Process *proc) + "couldn't read PLT value for %s(%p): %s\n", + libsym->name, libsym->enter_addr, + strerror(errno)); +- return; ++ return; + } + + if (proc->e_machine == EM_PPC) +@@ -326,6 +335,7 @@ arch_translate_address_dyn(struct Proces + arch_addr_t addr, arch_addr_t *ret) + { + if (proc->e_machine == EM_PPC64) { ++#if _CALL_ELF != 2 + uint64_t value; + if (read_target_8(proc, addr, &value) < 0) { + fprintf(stderr, +@@ -337,6 +347,7 @@ arch_translate_address_dyn(struct Proces + * arch_addr_t becomes integral type. */ + *ret = (arch_addr_t)(uintptr_t)value; + return 0; ++#endif + } + + *ret = addr; +@@ -347,7 +358,8 @@ int + arch_translate_address(struct ltelf *lte, + arch_addr_t addr, arch_addr_t *ret) + { +- if (lte->ehdr.e_machine == EM_PPC64) { ++ if (lte->ehdr.e_machine == EM_PPC64 ++ && !lte->arch.elfv2_abi) { + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + GElf_Xword offset +@@ -501,7 +513,16 @@ reloc_copy_if_irelative(GElf_Rela *rela, + int + arch_elf_init(struct ltelf *lte, struct library *lib) + { ++ ++ /* Check for ABIv2 in ELF header processor specific flag. */ ++#ifndef EF_PPC64_ABI ++ assert (! (lte->ehdr.e_flags & 3 ) == 2) ++#else ++ lte->arch.elfv2_abi=((lte->ehdr.e_flags & EF_PPC64_ABI) == 2) ; ++#endif ++ + if (lte->ehdr.e_machine == EM_PPC64 ++ && !lte->arch.elfv2_abi + && load_opd_data(lte, lib) < 0) + return -1; + +@@ -670,7 +691,7 @@ read_plt_slot_value(struct Process *proc + uint64_t l; + /* XXX double cast. */ + if (read_target_8(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) { +- fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n", ++ debug(DEBUG_EVENT, "ptrace .plt slot value @%#" PRIx64": %s", + addr, strerror(errno)); + return -1; + } +@@ -687,7 +708,7 @@ unresolve_plt_slot(struct Process *proc, + * pointers intact. Hence the only adjustment that we need to + * do is to IP. */ + if (ptrace(PTRACE_POKETEXT, proc->pid, addr, value) < 0) { +- fprintf(stderr, "failed to unresolve .plt slot: %s\n", ++ debug(DEBUG_EVENT, "failed to unresolve .plt slot: %s", + strerror(errno)); + return -1; + } +@@ -763,10 +784,14 @@ arch_elf_add_plt_entry(struct Process *p + assert(plt_slot_addr >= lte->plt_addr + || plt_slot_addr < lte->plt_addr + lte->plt_size); + ++ /* Should avoid to do read if dynamic linker hasn't run yet ++ * or allow -1 a valid return code. */ + GElf_Addr plt_slot_value; + if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) { +- free(name); +- return plt_fail; ++ if (!lte->arch.elfv2_abi) ++ goto fail; ++ else ++ return PPC_PLT_UNRESOLVED; + } + + struct library_symbol *libsym = malloc(sizeof(*libsym)); +@@ -1007,8 +1032,12 @@ ppc_plt_bp_continue(struct breakpoint *b + return; + } + ++#if _CALL_ELF == 2 ++ continue_after_breakpoint(proc, bp); ++#else + jump_to_entry_point(proc, bp); + continue_process(proc->pid); ++#endif + return; + + case PPC64_PLT_STUB: +@@ -1084,7 +1113,11 @@ arch_library_symbol_init(struct library_ + /* We set type explicitly in the code above, where we have the + * necessary context. This is for calls from ltrace-elf.c and + * such. */ ++#if _CALL_ELF == 2 ++ libsym->arch.type = PPC_PLT_UNRESOLVED; ++#else + libsym->arch.type = PPC_DEFAULT; ++#endif + return 0; + } + +Index: b/sysdeps/linux-gnu/ppc/trace.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/trace.c ++++ b/sysdeps/linux-gnu/ppc/trace.c +@@ -63,9 +63,15 @@ syscall_p(Process *proc, int status, int + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + long pc = (long)get_instruction_pointer(proc); ++#ifndef __LITTLE_ENDIAN__ + int insn = + (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), + 0); ++#else ++ int insn = ++ (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(int), ++ 0); ++#endif + + if (insn == SYSCALL_INSN) { + *sysnum = +@@ -128,7 +134,11 @@ arch_atomic_singlestep(struct Process *p + return -1; + uint32_t insn; + #ifdef __powerpc64__ ++# ifdef __LITTLE_ENDIAN__ ++ insn = (uint32_t) l; ++# else + insn = l >> 32; ++# endif + #else + insn = l; + #endif +Index: b/configure.ac +=================================================================== +--- a/configure.ac ++++ b/configure.ac +@@ -42,7 +42,7 @@ case "${host_cpu}" in + arm*|sa110) HOST_CPU="arm" ;; + cris*) HOST_CPU="cris" ;; + mips*) HOST_CPU="mips" ;; +- powerpc|powerpc64) HOST_CPU="ppc" ;; ++ powerpc|powerpc64|powerpc64le) HOST_CPU="ppc" ;; + sun4u|sparc64) HOST_CPU="sparc" ;; + s390x) HOST_CPU="s390" ;; + i?86|x86_64) HOST_CPU="x86" ;; +@@ -167,7 +167,7 @@ if test x"$enable_libunwind" = xyes; the + arm*|sa110) UNWIND_ARCH="arm" ;; + i?86) UNWIND_ARCH="x86" ;; + powerpc) UNWIND_ARCH="ppc32" ;; +- powerpc64) UNWIND_ARCH="ppc64" ;; ++ powerpc64|powerpc64le) UNWIND_ARCH="ppc64" ;; + mips*) UNWIND_ARCH="mips" ;; + *) UNWIND_ARCH="${host_cpu}" ;; + esac diff -Nru ltrace-0.7.3/debian/patches/ppc64el_p3 ltrace-0.7.3/debian/patches/ppc64el_p3 --- ltrace-0.7.3/debian/patches/ppc64el_p3 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc64el_p3 2016-12-14 16:36:20.000000000 +0100 @@ -0,0 +1,92 @@ +Description: More patches for ppc64le support + Required patches for ppc64le support - including hfa and float + Disable test of intermediate spawned functions + . +Author: Thierry Fauck <tfa...@free.fr> + +--- +Last-Update: 2016-12-12 + +--- ltrace-0.7.3.orig/sysdeps/linux-gnu/ppc/fetch.c ++++ ltrace-0.7.3/sysdeps/linux-gnu/ppc/fetch.c +@@ -220,7 +220,7 @@ allocate_stack_slot(struct fetch_context + + if (valuep != NULL) + value_in_inferior(valuep, ctx->stack_pointer + off); +- ctx->stack_pointer += a; ++ ctx->stack_pointer += sz; + + return 0; + } +@@ -318,8 +318,8 @@ allocate_gpr(struct fetch_context *ctx, + + static int + allocate_float(struct fetch_context *ctx, struct Process *proc, +- struct arg_type_info *info, struct value *valuep, +- size_t off, bool is_hfa_type) ++ struct arg_type_info *info, struct value *valuep, ++ size_t off, bool is_hfa_type) + { + int pool = proc->e_machine == EM_PPC64 ? 13 : 8; + if (ctx->freg <= pool) { +@@ -391,7 +391,7 @@ allocate_hfa(struct fetch_context *ctx, + struct arg_type_info *hfa_info = type_get_simple(hfa_type); + size_t hfa_sz = type_sizeof(proc, hfa_info); + +- while (hfa_count > 0 && ctx->freg <= 13) { ++ while (hfa_count > 0 && ctx->freg <= 14) { + struct value tmp; + value_init(&tmp, proc, NULL, hfa_info, 0); + int rc = allocate_float(ctx, proc, hfa_info, +@@ -416,7 +416,7 @@ allocate_hfa(struct fetch_context *ctx, + + /* if no remaining FP, GPR corresponding to slot is used + * Mostly it is in part of r10. */ +- if (ctx->vgreg == 10) { ++ if (ctx->greg <= 10) { + while (ctx->vgreg <= 10) { + struct value tmp; + value_init(&tmp, proc, NULL, hfa_info, 0); +@@ -609,7 +609,11 @@ arch_fetch_retval(struct fetch_context * + if (ctx->ret_struct) { + assert(info->type == ARGTYPE_STRUCT); + +- uint64_t addr = read_gpr(ctx, proc, 3); ++ uint64_t addr; ++ if ( ppc64_call_elf_abi != 2 || ctx->regs.r32[1] == 0 ) ++ addr = read_gpr(ctx, proc, 3); ++ else ++ addr = read_gpr(ctx, proc, 4); + value_init(valuep, proc, NULL, info, 0); + + valuep->where = VAL_LOC_INFERIOR; +--- ltrace-0.7.3.orig/sysdeps/linux-gnu/ppc/plt.c ++++ ltrace-0.7.3/sysdeps/linux-gnu/ppc/plt.c +@@ -882,7 +882,7 @@ cb_keep_stepping_p(struct process_stoppi + /* In UNRESOLVED state, the RESOLVED_VALUE in fact contains + * the PLT entry value. */ + if (value == libsym->arch.resolved_value) +- return CBS_CONT; ++ return CBS_STOP; + + debug(DEBUG_PROCESS, "pid=%d PLT got resolved to value %#"PRIx64, + proc->pid, value); +--- ltrace-0.7.3.orig/testsuite/ltrace.main/branch_func.exp ++++ ltrace-0.7.3/testsuite/ltrace.main/branch_func.exp +@@ -46,12 +46,12 @@ if [regexp {ELF from incompatible archit + } + + set pattern "func1(.*unfinished" +-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 ++#ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 + set pattern "func2(.*unfinished" +-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 ++#ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 + set pattern "func3(.*)" + ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 + set pattern "func2.resumed" +-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 ++#ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 + set pattern "func1.resumed" +-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 ++#ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100 diff -Nru ltrace-0.7.3/debian/patches/ppc64-fork.patch ltrace-0.7.3/debian/patches/ppc64-fork.patch --- ltrace-0.7.3/debian/patches/ppc64-fork.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc64-fork.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,49 @@ +From 35742523e3daa0e59de0c1c3fdd8e5ff52891967 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Thu, 9 Jan 2014 23:41:50 +0100 +Subject: [PATCH] Fix a problem in tracing across fork on PPC64 + +In order to avoid single-stepping through large portions of the +dynamic linker, ltrace remembers at which address the instruction that +resolved a PLT slot is. It then puts a breakpoint to this address so +that it can fast-forward to that address next time it needs to catch a +PLT slot being resolved. + +When a process is cloned, the pointer to this breakpoint is simply +copied over to the new process, instead of being looked up in the new +process structures. This patches fixes this. +--- + sysdeps/linux-gnu/ppc/plt.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Paul Gilliam + * +@@ -1201,6 +1201,18 @@ int + arch_process_clone(struct Process *retp, struct Process *proc) + { + retp->arch = proc->arch; ++ ++ if (retp->arch.dl_plt_update_bp != NULL) { ++ /* Point it to the corresponding breakpoint in RETP. ++ * It must be there, this part of PROC has already ++ * been cloned to RETP. */ ++ retp->arch.dl_plt_update_bp ++ = address2bpstruct(retp, ++ retp->arch.dl_plt_update_bp->addr); ++ ++ assert(retp->arch.dl_plt_update_bp != NULL); ++ } ++ + return 0; + } + diff -Nru ltrace-0.7.3/debian/patches/ppc64le-fixes.patch ltrace-0.7.3/debian/patches/ppc64le-fixes.patch --- ltrace-0.7.3/debian/patches/ppc64le-fixes.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc64le-fixes.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,461 @@ +From: Petr Machata <pmach...@redhat.com> +Subject: Miscellaneous ppc64el fixes +Last-Update: 2016-04-06 + +This is a backport of the following upstream commits: + - [35a9677d] fix bugs in fetch backend of powerpc64le + - [a46c07fc] Fix coding style in PowerPC's arch.h + - [44789e1e] PowerPC: convert ELFv2 conditionals from preprocessor to + plain conditions. + +It was taken from the fedoraproject pkgs ltrace repository: +ihttp://pkgs.fedoraproject.org/cgit/rpms/ltrace.git/commit/?id=fe527c31efcc51d1cdedd15269c2f807503099c5 + +The original changelog in fedora spec mentioned: + +""" +# Support for ppc64le, backported from upstream. +# http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=eea4ad2cce289753aaa35b4e0258a76d8f8f367c +# https://bugzilla.redhat.com/show_bug.cgi?id=1125601 +Patch13: ltrace-0.7.91-ppc64le-support.patch +# 35a9677dc9dcb7909ebd28f30200474d7e8b660f, +# 437d2377119036346f4dbd93039c847b4cc9d0be, +# eb3993420734f091cde9a6053ca6b4edcf9ae334 +Patch14: ltrace-0.7.91-ppc64le-fixes.patch +""" + +This is Patch14; aka ltrace-0.7.91-ppc64le-fixes.patch + +It was refreshed (backported, if you will) for applying on 0.7.3 by: +Mathieu Trudel-Lapierre <mathieu.trudel-lapie...@canonical.com> + +It is attributed to Petr Machata since there were no origin markings on the +original patch and he did the commit. If that's not correct, we can fix the +attribution when someone speaks up. + +--- + sysdeps/linux-gnu/ppc/arch.h | 41 +++++--- + sysdeps/linux-gnu/ppc/fetch.c | 197 +++++++++++++++++++----------------------- + 2 files changed, 118 insertions(+), 120 deletions(-) + +Index: b/sysdeps/linux-gnu/ppc/arch.h +=================================================================== +--- a/sysdeps/linux-gnu/ppc/arch.h ++++ b/sysdeps/linux-gnu/ppc/arch.h +@@ -32,36 +32,45 @@ + #define LT_ELF_MACHINE EM_PPC + + #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target. +-#define LT_ELFCLASS2 ELFCLASS64 +-#define LT_ELF_MACHINE2 EM_PPC64 ++# define LT_ELFCLASS2 ELFCLASS64 ++# define LT_ELF_MACHINE2 EM_PPC64 + + # ifdef __LITTLE_ENDIAN__ +-# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f } +-# define ARCH_ENDIAN_LITTLE ++# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f } ++# define ARCH_ENDIAN_LITTLE + # else +-# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } +-# define ARCH_SUPPORTS_OPD +-# define ARCH_ENDIAN_BIG ++# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } ++# define ARCH_SUPPORTS_OPD ++# define ARCH_ENDIAN_BIG + # endif + +-# if _CALL_ELF != 2 +-# define ARCH_SUPPORTS_OPD +-# define STACK_FRAME_OVERHEAD 112 ++# if !defined(_CALL_ELF) || _CALL_ELF < 2 ++# define ARCH_SUPPORTS_OPD ++# define STACK_FRAME_OVERHEAD 112 + # ifndef EF_PPC64_ABI +-# define EF_PPC64_ABI 3 ++# define EF_PPC64_ABI 3 + # endif +-# else /* _CALL_ELF == 2 ABIv2 */ +-# define STACK_FRAME_OVERHEAD 32 ++# elif _CALL_ELF == 2 /* ELFv2 ABI */ ++# define STACK_FRAME_OVERHEAD 32 ++# else ++# error Unsupported PowerPC64 ABI. + # endif /* CALL_ELF */ + + #else +-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } +-#define ARCH_ENDIAN_BIG ++# define STACK_FRAME_OVERHEAD 112 ++# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } ++# define ARCH_ENDIAN_BIG + # ifndef EF_PPC64_ABI +-# define EF_PPC64_ABI 3 ++# define EF_PPC64_ABI 3 + # endif + #endif /* __powerpc64__ */ + ++#ifdef _CALL_ELF ++enum { ppc64_call_elf_abi = _CALL_ELF }; ++#else ++enum { ppc64_call_elf_abi = 0 }; ++#endif ++ + #define ARCH_HAVE_ATOMIC_SINGLESTEP + #define ARCH_HAVE_ADD_PLT_ENTRY + #define ARCH_HAVE_TRANSLATE_ADDRESS +Index: b/sysdeps/linux-gnu/ppc/fetch.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/fetch.c ++++ b/sysdeps/linux-gnu/ppc/fetch.c +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2012 Petr Machata, Red Hat Inc. ++ * Copyright (C) 2012, 2014 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as +@@ -23,6 +23,7 @@ + #include <stdlib.h> + #include <string.h> + #include <sys/ucontext.h> ++#include <stdio.h> + + #include "backend.h" + #include "fetch.h" +@@ -57,7 +58,7 @@ struct fetch_context { + arch_addr_t stack_pointer; + int greg; + int freg; +- int ret_struct; ++ bool ret_struct; + + union { + gregs32_t r32; +@@ -65,11 +66,29 @@ struct fetch_context { + } regs; + struct fpregs_t fpregs; + int vgreg; +- int struct_size; +- int struct_hfa_size; +- int struct_hfa_count; + }; + ++static bool ++is_eligible_hfa(struct arg_type_info *info, ++ struct arg_type_info **hfa_infop, size_t *hfa_countp) ++{ ++ size_t hfa_count; ++ struct arg_type_info *hfa_info = type_get_hfa_type(info, &hfa_count); ++ ++ if (hfa_info != NULL && hfa_count <= 8 ++ && (hfa_info->type == ARGTYPE_FLOAT ++ || hfa_info->type == ARGTYPE_DOUBLE)) { ++ ++ if (hfa_infop != NULL) ++ *hfa_infop = hfa_info; ++ if (hfa_countp != NULL) ++ *hfa_countp = hfa_count; ++ return true; ++ } ++ ++ return false; ++} ++ + static int + fetch_context_init(struct Process *proc, struct fetch_context *context) + { +@@ -125,30 +144,37 @@ arch_fetch_arg_init(enum tof type, struc + } + + context->vgreg = context->greg; +- context->struct_size = 0; +- context->struct_hfa_size = 0; +- context->struct_hfa_count = 0; + + /* Aggregates or unions of any length, and character strings + * of length longer than 8 bytes, will be returned in a + * storage buffer allocated by the caller. The caller will + * pass the address of this buffer as a hidden first argument + * in r3, causing the first explicit argument to be passed in +- * r4. */ +- context->ret_struct = ret_info->type == ARGTYPE_STRUCT; +- if (context->ret_struct) { +-#if _CALL_ELF == 2 +- /* if R3 points to stack, parameters will be in R4. */ +- uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid, +- proc->stack_pointer, 0); +- if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer) +- && (context->regs.r64[3] < pstack_end)) { ++ * r4. ++ */ ++ ++ context->ret_struct = false; ++ ++ if (ppc64_call_elf_abi == 2) { ++ /* With ELFv2 ABI, aggregates that consist ++ * (recursively) only of members of the same ++ * floating-point or vector type, are passed in a ++ * series of floating-point resp. vector registers. ++ * Additionally, when returning any aggregate of up to ++ * 16 bytes, general-purpose registers are used. */ ++ ++ if (ret_info->type == ARGTYPE_STRUCT ++ && ! is_eligible_hfa(ret_info, NULL, NULL) ++ && type_sizeof(proc, ret_info) > 16) { ++ ++ context->ret_struct = true; + context->greg++; + context->stack_pointer += 8; + } +-#else ++ ++ } else if (ret_info->type == ARGTYPE_STRUCT) { ++ context->ret_struct = true; + context->greg++; +-#endif + } + + return context; +@@ -176,17 +202,16 @@ allocate_stack_slot(struct fetch_context + + size_t a = type_alignof(proc, info); + size_t off = 0; +- if (proc->e_machine == EM_PPC && a < 4) +- a = 4; +-#if _CALL_ELF == 2 +- else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type) ++ if (proc->e_machine == EM_PPC && a < 4) { + a = 4; +- else +- a = 8; +-#else +- else if (proc->e_machine == EM_PPC64 && a < 8) +-#endif ++ } else if (ppc64_call_elf_abi == 2) { ++ if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type) { ++ a = 4; ++ } else ++ a = 8; ++ } else if (proc->e_machine == EM_PPC64 && a < 8) { + a = 8; ++ } + + /* XXX Remove the two double casts when arch_addr_t + * becomes integral type. */ +@@ -259,18 +284,19 @@ allocate_gpr(struct fetch_context *ctx, + if (sz == (size_t)-1) + return -1; + assert(sz == 1 || sz == 2 || sz == 4 || sz == 8); +-#if _CALL_ELF == 2 +- /* Consume the stack slot corresponding to this arg. */ +- if ((sz + off) >= 8) +- ctx->greg++; + +- if (is_hfa_type) +- ctx->stack_pointer += sz; +- else +- ctx->stack_pointer += 8; +-#else +- ctx->greg++; +-#endif ++ if (ppc64_call_elf_abi == 2) { ++ /* Consume the stack slot corresponding to this arg. */ ++ if ((sz + off) >= 8) ++ ctx->greg++; ++ ++ if (is_hfa_type) ++ ctx->stack_pointer += sz; ++ else ++ ctx->stack_pointer += 8; ++ } else { ++ ctx->greg++; ++ } + + if (valuep == NULL) + return 0; +@@ -326,7 +352,6 @@ allocate_float(struct fetch_context *ctx + return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type); + } + +-#if _CALL_ELF == 2 + static int + allocate_hfa(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, +@@ -336,27 +361,27 @@ allocate_hfa(struct fetch_context *ctx, + if (sz == (size_t)-1) + return -1; + +- ctx->struct_hfa_size += sz; +- + /* There are two changes regarding structure return types: +- * * heterogeneous float/vector structs are returned +- * in (multiple) FP/vector registers, +- * instead of via implicit reference. +- * * small structs (up to 16 bytes) are return +- * in one or two GPRs, instead of via implicit reference. ++ * * heterogeneous float/vector structs are returned in ++ * (multiple) FP/vector registers, instead of via implicit ++ * reference. ++ * * small structs (up to 16 bytes) are return in one or two ++ * GPRs, instead of via implicit reference. + * + * Other structures (larger than 16 bytes, not heterogeneous) + * are still returned via implicit reference (i.e. a pointer + * to memory where to return the struct being passed in r3). +- * Of course, whether or not an implicit reference pointer +- * is present will shift the remaining arguments, +- * so you need to get this right for ELFv2 in order +- * to get the arguments correct. ++ * Of course, whether or not an implicit reference pointer is ++ * present will shift the remaining arguments, so you need to ++ * get this right for ELFv2 in order to get the arguments ++ * correct. ++ * + * If an actual parameter is known to correspond to an HFA + * formal parameter, each element is passed in the next + * available floating-point argument register starting at fp1 + * until the fp13. The remaining elements of the aggregate are +- * passed on the stack. */ ++ * passed on the stack. ++ */ + size_t slot_off = 0; + + unsigned char *buf = value_reserve(valuep, sz); +@@ -366,26 +391,17 @@ allocate_hfa(struct fetch_context *ctx, + struct arg_type_info *hfa_info = type_get_simple(hfa_type); + size_t hfa_sz = type_sizeof(proc, hfa_info); + +- if (hfa_count > 8) +- ctx->struct_hfa_count += hfa_count; +- + while (hfa_count > 0 && ctx->freg <= 13) { +- int rc; + struct value tmp; +- + value_init(&tmp, proc, NULL, hfa_info, 0); ++ int rc = allocate_float(ctx, proc, hfa_info, ++ &tmp, slot_off, true); ++ if (rc == 0) ++ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz); ++ value_destroy(&tmp); + +- /* Hetereogeneous struct - get value on GPR or stack. */ +- if (((hfa_type == ARGTYPE_FLOAT +- || hfa_type == ARGTYPE_DOUBLE) +- && hfa_count <= 8)) +- rc = allocate_float(ctx, proc, hfa_info, &tmp, +- slot_off, true); +- else +- rc = allocate_gpr(ctx, proc, hfa_info, &tmp, +- slot_off, true); +- +- memcpy(buf, value_get_data(&tmp, NULL), hfa_sz); ++ if (rc < 0) ++ return -1; + + slot_off += hfa_sz; + buf += hfa_sz; +@@ -394,17 +410,13 @@ allocate_hfa(struct fetch_context *ctx, + slot_off = 0; + ctx->vgreg++; + } +- +- value_destroy(&tmp); +- if (rc < 0) +- return -1; + } + if (hfa_count == 0) + return 0; + + /* if no remaining FP, GPR corresponding to slot is used +- * Mostly it is in part of r10. */ +- if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) { ++ * Mostly it is in part of r10. */ ++ if (ctx->vgreg == 10) { + while (ctx->vgreg <= 10) { + struct value tmp; + value_init(&tmp, proc, NULL, hfa_info, 0); +@@ -428,11 +440,8 @@ allocate_hfa(struct fetch_context *ctx, + } + } + +- if (hfa_count == 0) +- return 0; +- + /* Remaining values are on stack */ +- while (hfa_count) { ++ while (hfa_count > 0) { + struct value tmp; + value_init(&tmp, proc, NULL, hfa_info, 0); + +@@ -444,7 +453,6 @@ allocate_hfa(struct fetch_context *ctx, + } + return 0; + } +-#endif + + static int + allocate_argument(struct fetch_context *ctx, struct Process *proc, +@@ -459,24 +467,20 @@ allocate_argument(struct fetch_context * + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + return allocate_float(ctx, proc, info, valuep, +- 8 - type_sizeof(proc,info), false); ++ 8 - type_sizeof(proc,info), false); + + case ARGTYPE_STRUCT: + if (proc->e_machine == EM_PPC) { + if (value_pass_by_reference(valuep) < 0) + return -1; +- } else { +-#if _CALL_ELF == 2 ++ } else if (ppc64_call_elf_abi == 2) { + struct arg_type_info *hfa_info; +- size_t hfa_size; +- hfa_info = type_get_hfa_type(info, &hfa_size); +- if (hfa_info != NULL ) { +- size_t sz = type_sizeof(proc, info); +- ctx->struct_size += sz; ++ size_t hfa_count; ++ if (is_eligible_hfa(info, &hfa_info, &hfa_count)) { + return allocate_hfa(ctx, proc, info, valuep, +- hfa_info->type, hfa_size); ++ hfa_info->type, hfa_count); + } +-#endif ++ } else { + /* PPC64: Fixed size aggregates and unions passed by + * value are mapped to as many doublewords of the + * parameter save area as the value uses in memory. +@@ -510,9 +514,6 @@ allocate_argument(struct fetch_context * + if (sz == (size_t)-1) + return -1; + +- if (ctx->ret_struct) +- ctx->struct_size += sz; +- + size_t slots = (sz + width - 1) / width; /* Round up. */ + unsigned char *buf = value_reserve(valuep, slots * width); + if (buf == NULL) +@@ -605,19 +606,7 @@ arch_fetch_retval(struct fetch_context * + if (fetch_context_init(proc, ctx) < 0) + return -1; + +-#if _CALL_ELF == 2 +- void *ptr = (void *)(ctx->regs.r64[1]+32); +- uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0); +- +- if (ctx->ret_struct +- && ((ctx->struct_size > 64 +- || ctx->struct_hfa_count > 8 +- || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56) +- || (ctx->regs.r64[3] == ctx->regs.r64[1]+32) +- || (ctx->regs.r64[3] == val )))) { +-#else + if (ctx->ret_struct) { +-#endif + assert(info->type == ARGTYPE_STRUCT); + + uint64_t addr = read_gpr(ctx, proc, 3); diff -Nru ltrace-0.7.3/debian/patches/ppc64-unprelink.patch ltrace-0.7.3/debian/patches/ppc64-unprelink.patch --- ltrace-0.7.3/debian/patches/ppc64-unprelink.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc64-unprelink.patch 2016-12-04 23:23:06.000000000 +0100 @@ -0,0 +1,218 @@ +From a0093ca43cf40d7e5f6cebeb64156062d2de46d9 Mon Sep 17 00:00:00 2001 +From: Petr Machata <pmach...@redhat.com> +Date: Fri, 10 Jan 2014 20:06:51 +0100 +Subject: [PATCH 2/2] Don't crash untraced calls via PLT in prelinked PPC64 + binaries + +In prelinked binaries, ltrace has to unprelinks PLT slots in order to +catch calls done through PLT. This makes the calls done through these +slots invalid, because the special first PLT slot is not initialized, +and dynamic linker SIGSEGVs because of this. Ltrace relies on +arranging breakpoints such that the dynamic linker is not actually +entered, and moves PC around itself to simulate the effects of a call +through PLT. + +Originally, arch_elf_add_plt_entry was called only for symbols that +were actually traced. Later this was changed and it's now called for +all PLT entries, and the resulting candidate list is filtered +afterwards. This gives backends a chance to rename the symbol, as is +useful with IRELATIVE PLT calls, where symbol name may not be +available at all. But the PPC backend was never updated to reflect +this, and unresolved all symbols for which arch_elf_add_plt_entry was +called, thus rendering _all_ PLT slots invalid, even those that +weren't later procted by breakpoints. Thus calls done through any +untraced slots failed. + +This patch fixes this problem by deferring the unprelinking of PLT +slots into the on_install hook of breakpoints. +--- + sysdeps/linux-gnu/ppc/arch.h | 21 ++++++++- + sysdeps/linux-gnu/ppc/plt.c | 94 ++++++++++++++++++++++++++++++++++--------- + 2 files changed, 94 insertions(+), 21 deletions(-) + +Index: b/sysdeps/linux-gnu/ppc/arch.h +=================================================================== +--- a/sysdeps/linux-gnu/ppc/arch.h ++++ b/sysdeps/linux-gnu/ppc/arch.h +@@ -1,6 +1,6 @@ + /* + * This file is part of ltrace. +- * Copyright (C) 2012 Petr Machata ++ * Copyright (C) 2012,2013,2014 Petr Machata + * Copyright (C) 2006 Paul Gilliam + * Copyright (C) 2002,2004 Juan Cespedes + * +@@ -120,12 +120,29 @@ enum ppc64_plt_type { + /* Very similar to PPC_PLT_UNRESOLVED, but for JMP_IREL + * slots. */ + PPC_PLT_IRELATIVE, ++ ++ /* Transitional state before the breakpoint is enabled. */ ++ PPC_PLT_NEED_UNRESOLVE, + }; + + #define ARCH_HAVE_LIBRARY_SYMBOL_DATA ++struct ppc_unresolve_data; + struct arch_library_symbol_data { + enum ppc64_plt_type type; +- GElf_Addr resolved_value; ++ ++ /* State Contents ++ * ++ * PPC_DEFAULT N/A ++ * PPC64_PLT_STUB N/A ++ * PPC_PLT_UNRESOLVED PLT entry address. ++ * PPC_PLT_IRELATIVE Likewise. ++ * PPC_PLT_RESOLVED The original value the slot was resolved to. ++ * PPC_PLT_NEED_UNRESOLVE DATA. ++ */ ++ union { ++ GElf_Addr resolved_value; ++ struct ppc_unresolve_data *data; ++ }; + + /* Address of corresponding slot in .plt. */ + GElf_Addr plt_slot_addr; +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -715,6 +715,14 @@ unresolve_plt_slot(struct Process *proc, + return 0; + } + ++struct ppc_unresolve_data { ++ struct ppc_unresolve_data *self; /* A canary. */ ++ GElf_Addr plt_entry_addr; ++ GElf_Addr plt_slot_addr; ++ GElf_Addr plt_slot_value; ++ bool is_irelative; ++}; ++ + enum plt_status + arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, + const char *a_name, GElf_Rela *rela, size_t ndx, +@@ -816,28 +824,23 @@ arch_elf_add_plt_entry(struct Process *p + && (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) { + libsym->arch.type = PPC_PLT_UNRESOLVED; + libsym->arch.resolved_value = plt_entry_addr; +- + } else { +- /* Unresolve the .plt slot. If the binary was +- * prelinked, this makes the code invalid, because in +- * case of prelinked binary, the dynamic linker +- * doesn't update .plt[0] and .plt[1] with addresses +- * of the resover. But we don't care, we will never +- * need to enter the resolver. That just means that +- * we have to un-un-resolve this back before we +- * detach. */ +- +- if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) { +- library_symbol_destroy(libsym); ++ /* Mark the symbol for later unresolving. We may not ++ * do this right away, as this is called by ltrace ++ * core for all symbols, and only later filtered. We ++ * only unresolve the symbol before the breakpoint is ++ * enabled. */ ++ ++ libsym->arch.type = PPC_PLT_NEED_UNRESOLVE; ++ libsym->arch.data = malloc(sizeof *libsym->arch.data); ++ if (libsym->arch.data == NULL) + goto fail; +- } + +- if (! is_irelative) { +- mark_as_resolved(libsym, plt_slot_value); +- } else { +- libsym->arch.type = PPC_PLT_IRELATIVE; +- libsym->arch.resolved_value = plt_entry_addr; +- } ++ libsym->arch.data->self = libsym->arch.data; ++ libsym->arch.data->plt_entry_addr = plt_entry_addr; ++ libsym->arch.data->plt_slot_addr = plt_slot_addr; ++ libsym->arch.data->plt_slot_value = plt_slot_value; ++ libsym->arch.data->is_irelative = is_irelative; + } + + *ret = libsym; +@@ -1041,6 +1044,7 @@ ppc_plt_bp_continue(struct breakpoint *b + return; + + case PPC64_PLT_STUB: ++ case PPC_PLT_NEED_UNRESOLVE: + /* These should never hit here. */ + break; + } +@@ -1107,6 +1111,52 @@ arch_library_clone(struct library *retp, + { + } + ++static void ++ppc_plt_bp_install(struct breakpoint *bp, struct Process *proc) ++{ ++ /* This should not be an artificial breakpoint. */ ++ struct library_symbol *libsym = bp->libsym; ++ if (libsym == NULL) ++ libsym = bp->arch.irel_libsym; ++ assert(libsym != NULL); ++ ++ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) { ++ /* Unresolve the .plt slot. If the binary was ++ * prelinked, this makes the code invalid, because in ++ * case of prelinked binary, the dynamic linker ++ * doesn't update .plt[0] and .plt[1] with addresses ++ * of the resover. But we don't care, we will never ++ * need to enter the resolver. That just means that ++ * we have to un-un-resolve this back before we ++ * detach. */ ++ ++ struct ppc_unresolve_data *data = libsym->arch.data; ++ libsym->arch.data = NULL; ++ assert(data->self == data); ++ ++ GElf_Addr plt_slot_addr = data->plt_slot_addr; ++ GElf_Addr plt_slot_value = data->plt_slot_value; ++ GElf_Addr plt_entry_addr = data->plt_entry_addr; ++ ++ if (unresolve_plt_slot(proc, plt_slot_addr, ++ plt_entry_addr) == 0) { ++ if (! data->is_irelative) { ++ mark_as_resolved(libsym, plt_slot_value); ++ } else { ++ libsym->arch.type = PPC_PLT_IRELATIVE; ++ libsym->arch.resolved_value = plt_entry_addr; ++ } ++ } else { ++ fprintf(stderr, "Couldn't unresolve %s@%p. Not tracing" ++ " this symbol.\n", ++ breakpoint_name(bp), bp->addr); ++ proc_remove_breakpoint(proc, bp); ++ } ++ ++ free(data); ++ } ++} ++ + int + arch_library_symbol_init(struct library_symbol *libsym) + { +@@ -1124,6 +1174,11 @@ arch_library_symbol_init(struct library_ + void + arch_library_symbol_destroy(struct library_symbol *libsym) + { ++ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) { ++ assert(libsym->arch.data->self == libsym->arch.data); ++ free(libsym->arch.data); ++ libsym->arch.data = NULL; ++ } + } + + int +@@ -1159,6 +1214,7 @@ arch_breakpoint_init(struct Process *pro + static struct bp_callbacks cbs = { + .on_continue = ppc_plt_bp_continue, + .on_retract = ppc_plt_bp_retract, ++ .on_install = ppc_plt_bp_install, + }; + breakpoint_set_callbacks(bp, &cbs); + diff -Nru ltrace-0.7.3/debian/patches/ppc-bias.patch ltrace-0.7.3/debian/patches/ppc-bias.patch --- ltrace-0.7.3/debian/patches/ppc-bias.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ppc-bias.patch 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,134 @@ +From: Petr Machata <pmach...@redhat.com> +Subject: Fix bias handling in PPC backend +Last-Update: 2016-04-06 + +This is a backport of the following upstream commits: + - bf821009: Fix address biasing in PPC backend + - d80c5371: Fix cloning of PPC_PLT_NEED_UNRESOLVE breakpoints + - d8f1287b: Nits + +It was taken from the fedoraproject pkgs ltrace repository: +http://pkgs.fedoraproject.org/cgit/rpms/ltrace.git/commit/?id=5f8efb0257eaa772639d5a4912a6b5e3a709ceab + +The original changelog in fedora spec mentioned: + +""" +# https://bugzilla.redhat.com/show_bug.cgi?id=1171165 +# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=d8f1287b85e2c2b2ae0235809e956f4365e53c45 +# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=d80c5371454383e3f9978622e5578cf02af8c44c +# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=bf82100966deda9c7d26ad085d97c08126a8ae88 +Patch16: ltrace-0.7.91-ppc-bias.patch + +[...] + + * Tue Dec 9 2014 Petr Machata <pmach...@redhat.com> - 0.7.91-11 + - Fix bias handling in PPC backend + - Fix cloning of unresolved breakpoints in PPC backend + (ltrace-0.7.91-ppc-bias.patch) + +""" + +This is Patch16; aka ltrace-0.7.91-ppc-bias.patch + +It was refreshed (backported, if you will) for applying on 0.7.3 by: +Mathieu Trudel-Lapierre <mathieu.trudel-lapie...@canonical.com> + +It is attributed to Petr Machata since there were no origin markings on the +original patch and he did the commit. If that's not correct, we can fix the +attribution when someone speaks up. + +--- + sysdeps/linux-gnu/ppc/plt.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + +Index: b/sysdeps/linux-gnu/ppc/plt.c +=================================================================== +--- a/sysdeps/linux-gnu/ppc/plt.c ++++ b/sysdeps/linux-gnu/ppc/plt.c +@@ -309,14 +309,15 @@ arch_plt_sym_val(struct ltelf *lte, size + + assert(rela->r_addend != 0); + /* XXX double cast */ +- arch_addr_t res_addr = (arch_addr_t) (uintptr_t) rela->r_addend; ++ arch_addr_t res_addr ++ = (arch_addr_t) (uintptr_t) (rela->r_addend + lte->bias); + if (arch_translate_address(lte, res_addr, &res_addr) < 0) { + fprintf(stderr, "Couldn't OPD-translate IRELATIVE " + "resolver address.\n"); + return 0; + } + /* XXX double cast */ +- return (GElf_Addr) (uintptr_t) res_addr; ++ return (GElf_Addr) (uintptr_t) (res_addr - lte->bias); + + } else { + /* We put brakpoints to PLT entries the same as the +@@ -518,7 +519,7 @@ arch_elf_init(struct ltelf *lte, struct + #ifndef EF_PPC64_ABI + assert (! (lte->ehdr.e_flags & 3 ) == 2) + #else +- lte->arch.elfv2_abi=((lte->ehdr.e_flags & EF_PPC64_ABI) == 2) ; ++ lte->arch.elfv2_abi = ((lte->ehdr.e_flags & EF_PPC64_ABI) == 2); + #endif + + if (lte->ehdr.e_machine == EM_PPC64 +@@ -792,15 +793,15 @@ arch_elf_add_plt_entry(struct Process *p + assert(plt_slot_addr >= lte->plt_addr + || plt_slot_addr < lte->plt_addr + lte->plt_size); + ++ plt_entry_addr += lte->bias; ++ plt_slot_addr += lte->bias; ++ + /* Should avoid to do read if dynamic linker hasn't run yet + * or allow -1 a valid return code. */ + GElf_Addr plt_slot_value; +- if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) { +- if (!lte->arch.elfv2_abi) +- goto fail; +- else +- return PPC_PLT_UNRESOLVED; +- } ++ int rc = read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value); ++ if (rc < 0 && !lte->arch.elfv2_abi) ++ goto fail; + + struct library_symbol *libsym = malloc(sizeof(*libsym)); + if (libsym == NULL) { +@@ -820,8 +821,9 @@ arch_elf_add_plt_entry(struct Process *p + goto fail; + libsym->arch.plt_slot_addr = plt_slot_addr; + +- if (! is_irelative +- && (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) { ++ if (rc < 0 || (! is_irelative ++ && (plt_slot_value == plt_entry_addr ++ || plt_slot_value == 0))) { + libsym->arch.type = PPC_PLT_UNRESOLVED; + libsym->arch.resolved_value = plt_entry_addr; + } else { +@@ -1147,8 +1149,8 @@ ppc_plt_bp_install(struct breakpoint *bp + libsym->arch.resolved_value = plt_entry_addr; + } + } else { +- fprintf(stderr, "Couldn't unresolve %s@%p. Not tracing" +- " this symbol.\n", ++ fprintf(stderr, "Couldn't unresolve %s@%p. Will not" ++ " trace this symbol.\n", + breakpoint_name(bp), bp->addr); + proc_remove_breakpoint(proc, bp); + } +@@ -1186,6 +1188,14 @@ arch_library_symbol_clone(struct library + struct library_symbol *libsym) + { + retp->arch = libsym->arch; ++ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) { ++ assert(libsym->arch.data->self == libsym->arch.data); ++ retp->arch.data = malloc(sizeof *retp->arch.data); ++ if (retp->arch.data == NULL) ++ return -1; ++ *retp->arch.data = *libsym->arch.data; ++ retp->arch.data->self = retp->arch.data; ++ } + return 0; + } + diff -Nru ltrace-0.7.3/debian/patches/ptrace.diff ltrace-0.7.3/debian/patches/ptrace.diff --- ltrace-0.7.3/debian/patches/ptrace.diff 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/ptrace.diff 2016-12-04 23:23:04.000000000 +0100 @@ -0,0 +1,68 @@ +Description: try to make PTRACE scope sysctl more discoverable. +Updated: 2014-05-07 + +Index: ltrace-0.7.3/sysdeps/linux-gnu/trace.c +=================================================================== +--- ltrace-0.7.3.orig/sysdeps/linux-gnu/trace.c 2014-05-07 15:17:07.949872643 -0400 ++++ ltrace-0.7.3/sysdeps/linux-gnu/trace.c 2014-05-07 15:24:08.077866134 -0400 +@@ -49,7 +49,7 @@ + #include "type.h" + + void +-trace_fail_warning(pid_t pid) ++trace_fail_warning(pid_t pid, int err) + { + /* This was adapted from GDB. */ + #ifdef HAVE_LIBSELINUX +@@ -66,6 +66,11 @@ + "tracing other processes. You can disable this process attach protection by\n" + "issuing 'setsebool deny_ptrace=0' in the superuser context.\n"); + #endif /* HAVE_LIBSELINUX */ ++ if (err == EPERM) ++ fprintf(stderr, ++ "Could not attach to process. If your uid matches the uid of the target\n" ++ "process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try\n" ++ "again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf\n"); + } + + void +@@ -73,8 +78,9 @@ + { + debug(DEBUG_PROCESS, "trace_me: pid=%d", getpid()); + if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { ++ int errno_save = errno; + perror("PTRACE_TRACEME"); +- trace_fail_warning(getpid()); ++ trace_fail_warning(getpid(), errno_save); + exit(1); + } + } +Index: ltrace-0.7.3/backend.h +=================================================================== +--- ltrace-0.7.3.orig/backend.h 2014-05-07 15:03:16.000000000 -0400 ++++ ltrace-0.7.3/backend.h 2014-05-07 15:25:00.805865317 -0400 +@@ -150,7 +150,7 @@ + + /* Called when trace_me or primary trace_pid fail. This may plug in + * any platform-specific knowledge of why it could be so. */ +-void trace_fail_warning(pid_t pid); ++void trace_fail_warning(pid_t pid, int err); + + /* A pair of functions called to initiate a detachment request when + * ltrace is about to exit. Their job is to undo any effects that +Index: ltrace-0.7.3/proc.c +=================================================================== +--- ltrace-0.7.3.orig/proc.c 2014-05-07 15:03:16.000000000 -0400 ++++ ltrace-0.7.3/proc.c 2014-05-07 15:24:42.881865595 -0400 +@@ -496,9 +496,10 @@ + + /* First, see if we can attach the requested PID itself. */ + if (open_one_pid(pid)) { ++ int errno_save = errno; + fprintf(stderr, "Cannot attach to pid %u: %s\n", + pid, strerror(errno)); +- trace_fail_warning(pid); ++ trace_fail_warning(pid, errno_save); + return; + } + diff -Nru ltrace-0.7.3/debian/patches/secondary-threads-struct-process ltrace-0.7.3/debian/patches/secondary-threads-struct-process --- ltrace-0.7.3/debian/patches/secondary-threads-struct-process 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/secondary-threads-struct-process 2016-12-05 21:51:28.000000000 +0100 @@ -0,0 +1,26 @@ +Description: Initialize struct process.e_machine and .e_class for secondary threads + + commit 8137e804992f15590105a3db29673674971dff7b + Author: Petr Machata <pmach...@redhat.com> + Date: Thu Feb 13 16:02:50 2014 +0100 + + Initialize struct process.e_machine and .e_class for secondary threads + . +--- +--- ltrace-0.7.3.orig/proc.c ++++ ltrace-0.7.3/proc.c +@@ -194,9 +194,11 @@ process_init(struct Process *proc, const + goto fail; + } + +- if (proc->leader != proc) +- return 0; +- if (process_init_main(proc) < 0) { ++ if (proc->leader != proc) { ++ proc->e_machine = proc->leader->e_machine; ++ proc->e_class = proc->leader->e_class; ++ get_arch_dep(proc); ++ } else if (process_init_main(proc) < 0) { + process_bare_destroy(proc, 0); + goto fail; + } diff -Nru ltrace-0.7.3/debian/patches/series ltrace-0.7.3/debian/patches/series --- ltrace-0.7.3/debian/patches/series 2016-09-21 13:15:35.000000000 +0200 +++ ltrace-0.7.3/debian/patches/series 2017-01-27 12:41:21.000000000 +0100 @@ -6,3 +6,31 @@ 06-unexpected-breakpoint gcc-5.diff deprecated-readdir_r.diff +ptrace.diff +add_irelative_tracing_b420a226.patch +find_irelative_b061bae3.patch +keep_plt_reloc_in_vector_673ff510.patch +add_elf_read_u8_3c636fb7.patch +add_elf_read_next_u_439ab5bf.patch +add_elf_can_read_next_5c37171a.patch +add_elf_each_symbol_7a29f9e7.patch +elf_read_uleb128_184779e4.patch +jmp_irel.patch +elf_load_dynamic_entry_4f2f66e6.patch +dont_ltelf_destroy_if_init_fails_0ba3c5ee.patch +ppc64el.diff +ppc64le-fixes.patch +ppc64-fork.patch +on_install_breakpoint_56134ff5.patch +ppc64-unprelink.patch +ppc-bias.patch +Move-get_hfa_type-from-IA64-backend-to-type.c-name-i.patch +Set-child-stack-alignment-in-trace-clone.c.patch +Add-missing-unistd.h +include-stdio.h-missing +More-testsuite-typo +wait-patch +system_calls.exp-test-case +initialize_libsym +secondary-threads-struct-process +ppc64el_p3 diff -Nru ltrace-0.7.3/debian/patches/Set-child-stack-alignment-in-trace-clone.c.patch ltrace-0.7.3/debian/patches/Set-child-stack-alignment-in-trace-clone.c.patch --- ltrace-0.7.3/debian/patches/Set-child-stack-alignment-in-trace-clone.c.patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/Set-child-stack-alignment-in-trace-clone.c.patch 2016-12-04 23:23:07.000000000 +0100 @@ -0,0 +1,31 @@ +Author: Petr Machata <pmach...@apm-mustang-ev2-02.ml3.eng.bos.redhat.com> +Description: Set child stack alignment in trace-clone.c + This is important on aarch64, which requires 16-byte aligned + stack pointer. This might be relevant on other arches as well, + I suspect we just happened to get the 16-byte boundary in some + cases. +Applied-Upstream: http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=0b5457a9e59978bcd2eb5240f54838910365a93c +Last-Update: 2014-03-13 + +Index: ltrace-0.7.3/testsuite/ltrace.minor/trace-clone.c +=================================================================== +--- ltrace-0.7.3.orig/testsuite/ltrace.minor/trace-clone.c ++++ ltrace-0.7.3/testsuite/ltrace.minor/trace-clone.c +@@ -8,6 +8,7 @@ + #include <sys/types.h> + #include <stdlib.h> + #include <sched.h> ++#include <unistd.h> + + int child () + { +@@ -22,7 +23,8 @@ typedef int (* myfunc)(); + int main () + { + pid_t pid; +- static char stack[STACK_SIZE]; ++ static __attribute__ ((aligned (16))) char stack[STACK_SIZE]; ++ + #ifdef __ia64__ + pid = __clone2((myfunc)&child, stack, STACK_SIZE, CLONE_FS, NULL); + #else diff -Nru ltrace-0.7.3/debian/patches/struct_process_sec_threads ltrace-0.7.3/debian/patches/struct_process_sec_threads --- ltrace-0.7.3/debian/patches/struct_process_sec_threads 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/struct_process_sec_threads 2016-12-05 21:45:43.000000000 +0100 @@ -0,0 +1,27 @@ +commit 8137e804992f15590105a3db29673674971dff7b +Author: Petr Machata <pmach...@redhat.com> +Date: Thu Feb 13 16:02:50 2014 +0100 + + Initialize struct process.e_machine and .e_class for secondary threads + +diff --git a/proc.c b/proc.c +index 6f4f64e..17bb3cd 100644 +--- a/proc.c ++++ b/proc.c +@@ -224,9 +224,11 @@ process_init(struct process *proc, const char *filename, pid_t pid) + goto fail; + } + +- if (proc->leader != proc) +- return 0; +- if (process_init_main(proc) < 0) { ++ if (proc->leader != proc) { ++ proc->e_machine = proc->leader->e_machine; ++ proc->e_class = proc->leader->e_class; ++ get_arch_dep(proc); ++ } else if (process_init_main(proc) < 0) { + process_bare_destroy(proc, 0); + goto fail; + } + + diff -Nru ltrace-0.7.3/debian/patches/system_calls.exp-test-case ltrace-0.7.3/debian/patches/system_calls.exp-test-case --- ltrace-0.7.3/debian/patches/system_calls.exp-test-case 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/system_calls.exp-test-case 2016-12-14 16:36:13.000000000 +0100 @@ -0,0 +1,21 @@ +Description: system_calls.exp test case check + . + ltrace (0.7.3-6.1) unstable; urgency=medium + . Correct test case value for subcase SYS_munmap + +Author: Thierry Fauck <tfa...@free.fr> + +--- +Last-Update: 2016-12-05 + +--- ltrace-0.7.3.orig/testsuite/ltrace.main/system_calls.exp ++++ ltrace-0.7.3/testsuite/ltrace.main/system_calls.exp +@@ -30,7 +30,7 @@ if [regexp {ELF from incompatible archit + + + set pattern "SYS_munmap" +-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 2 ++ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 + set pattern "SYS_write" + ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1 + set pattern "SYS_unlink" diff -Nru ltrace-0.7.3/debian/patches/wait-patch ltrace-0.7.3/debian/patches/wait-patch --- ltrace-0.7.3/debian/patches/wait-patch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/patches/wait-patch 2016-12-05 20:53:19.000000000 +0100 @@ -0,0 +1,30 @@ +Description: wait() change + . + ltrace (0.7.3-6.1) unstable; urgency=medium + . +Author: Thierry Fauck <tfa...@free.fr> + +--- + +Index: ltrace-0.7.3/testsuite/ltrace.minor/trace-fork.c +=================================================================== +--- ltrace-0.7.3.orig/testsuite/ltrace.minor/trace-fork.c ++++ ltrace-0.7.3/testsuite/ltrace.minor/trace-fork.c +@@ -7,7 +7,7 @@ + #include <stdio.h> + #include <sys/types.h> + #include <unistd.h> +-#include <wait.h> ++#include <sys/wait.h> + + void + child () +@@ -29,7 +29,7 @@ main () + else + { + printf("My child pid is %d\n",pid); +- wait(); ++ wait(NULL); + } + return 0; + } diff -Nru ltrace-0.7.3/debian/rules ltrace-0.7.3/debian/rules --- ltrace-0.7.3/debian/rules 2016-09-21 13:15:35.000000000 +0200 +++ ltrace-0.7.3/debian/rules 2016-12-15 19:45:27.000000000 +0100 @@ -1,9 +1,15 @@ #!/usr/bin/make -f +#DH_VERBOSE = 1 +#export DH_OPTIONS=-v + +export DEB_BUILD_MAINT_OPTIONS=hardening=+all + cdbs_configure_flags := --with-libunwind=no include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk +include /usr/share/cdbs/1/rules/autoreconf.mk install/ltrace:: rm -f debian/ltrace/usr/share/doc/ltrace/COPYING* diff -Nru ltrace-0.7.3/debian/source.lintian-overrides ltrace-0.7.3/debian/source.lintian-overrides --- ltrace-0.7.3/debian/source.lintian-overrides 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/source.lintian-overrides 2016-12-15 19:55:38.000000000 +0100 @@ -0,0 +1,2 @@ +# disable debian-watch-may-check-gpg-signature as upstream does not provide cryptographic signature +ltrace source: debian-watch-may-check-gpg-signature diff -Nru ltrace-0.7.3/debian/watch ltrace-0.7.3/debian/watch --- ltrace-0.7.3/debian/watch 1970-01-01 01:00:00.000000000 +0100 +++ ltrace-0.7.3/debian/watch 2016-12-15 10:31:30.000000000 +0100 @@ -0,0 +1,4 @@ +version=3 +#opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/ltrace-$1\.tar\.gz/ \ + https://www.ltrace.org/ltrace_([0-9\.]*)\..*\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) +