From: Max Filippov Date: Tue, 17 Mar 2015 20:26:01 +0000 (+0300) Subject: package/ltrace: add support for xtensa X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ef804af14e8fed9567ddbe428342da4c57b7032d;p=buildroot.git package/ltrace: add support for xtensa Backported from: 05143c95e4609e5592775fae5facbf77b7bfa694 Signed-off-by: Max Filippov Signed-off-by: Thomas Petazzoni --- diff --git a/package/ltrace/0004-xtensa-add-xtensa-support.patch b/package/ltrace/0004-xtensa-add-xtensa-support.patch new file mode 100644 index 0000000000..798a230cfc --- /dev/null +++ b/package/ltrace/0004-xtensa-add-xtensa-support.patch @@ -0,0 +1,1612 @@ +From 05ee6bd2986c62d611ff9dfe6dbf11d2def0844b Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Sun, 4 Jan 2015 06:57:41 +0300 +Subject: [PATCH] xtensa: add xtensa support + +Signed-off-by: Max Filippov +--- + CREDITS | 4 + + NEWS | 1 + + README | 1 + + configure.ac | 2 + + sysdeps/linux-gnu/Makefile.am | 2 +- + sysdeps/linux-gnu/xtensa/Makefile.am | 36 +++ + sysdeps/linux-gnu/xtensa/arch.h | 111 ++++++++ + sysdeps/linux-gnu/xtensa/breakpoint.c | 71 ++++++ + sysdeps/linux-gnu/xtensa/fetch.c | 188 ++++++++++++++ + sysdeps/linux-gnu/xtensa/plt.c | 463 ++++++++++++++++++++++++++++++++++ + sysdeps/linux-gnu/xtensa/ptrace.h | 21 ++ + sysdeps/linux-gnu/xtensa/regs.c | 83 ++++++ + sysdeps/linux-gnu/xtensa/signalent.h | 52 ++++ + sysdeps/linux-gnu/xtensa/syscallent.h | 357 ++++++++++++++++++++++++++ + sysdeps/linux-gnu/xtensa/trace.c | 61 +++++ + 15 files changed, 1452 insertions(+), 1 deletion(-) + create mode 100644 sysdeps/linux-gnu/xtensa/Makefile.am + create mode 100644 sysdeps/linux-gnu/xtensa/arch.h + create mode 100644 sysdeps/linux-gnu/xtensa/breakpoint.c + create mode 100644 sysdeps/linux-gnu/xtensa/fetch.c + create mode 100644 sysdeps/linux-gnu/xtensa/plt.c + create mode 100644 sysdeps/linux-gnu/xtensa/ptrace.h + create mode 100644 sysdeps/linux-gnu/xtensa/regs.c + create mode 100644 sysdeps/linux-gnu/xtensa/signalent.h + create mode 100644 sysdeps/linux-gnu/xtensa/syscallent.h + create mode 100644 sysdeps/linux-gnu/xtensa/trace.c + +diff --git a/CREDITS b/CREDITS +index c85eb76..67f1761 100644 +--- a/CREDITS ++++ b/CREDITS +@@ -61,6 +61,10 @@ N: Timothy Fesig + E: slate@us.ibm.com + D: s390 port + ++N: Max Filippov ++E: jcmvbkbc@gmail.com ++D: xtensa port ++ + N: Roman Hodek + E: Roman.Hodek@informatik.uni-erlangen.de + D: m68k port +diff --git a/NEWS b/NEWS +index 71d3a1f..a8e83f1 100644 +--- a/NEWS ++++ b/NEWS +@@ -38,6 +38,7 @@ + binaries, as currently there's no 32-bit userspace available for + ARM64 processors. + - Imagination Technologies Meta is now supported. ++ - Cadence Tensilica Xtensa is now supported. + + - On Linux, tracing of IFUNC symbols is supported. On i386, + x86_64, ppc32 with secure PLT and ppc64, IRELATIVE PLT slots are +diff --git a/README b/README +index a04b767..a38e8dc 100644 +--- a/README ++++ b/README +@@ -37,6 +37,7 @@ to test each release comprehensively on each target. + s390-*-linux-gnu + s390x-*-linux-gnu + x86_64-*-linux-gnu ++ xtensa-*-linux-gnu + + The following systems were supported at some point in past, but + current status is unknown: +diff --git a/configure.ac b/configure.ac +index 4f360c8..55c5c84 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -47,6 +47,7 @@ case "${host_cpu}" in + sun4u|sparc64) HOST_CPU="sparc" ;; + s390x) HOST_CPU="s390" ;; + i?86|x86_64) HOST_CPU="x86" ;; ++ xtensa*) HOST_CPU="xtensa" ;; + *) HOST_CPU="${host_cpu}" ;; + esac + AC_SUBST(HOST_CPU) +@@ -412,6 +413,7 @@ AC_CONFIG_FILES([ + sysdeps/linux-gnu/s390/Makefile + sysdeps/linux-gnu/sparc/Makefile + sysdeps/linux-gnu/x86/Makefile ++ sysdeps/linux-gnu/xtensa/Makefile + testsuite/Makefile + testsuite/ltrace.main/Makefile + testsuite/ltrace.minor/Makefile +diff --git a/sysdeps/linux-gnu/Makefile.am b/sysdeps/linux-gnu/Makefile.am +index ec26162..857f2da 100644 +--- a/sysdeps/linux-gnu/Makefile.am ++++ b/sysdeps/linux-gnu/Makefile.am +@@ -18,7 +18,7 @@ + # 02110-1301 USA + + DIST_SUBDIRS = aarch64 alpha arm cris ia64 m68k metag mips ppc s390 \ +- sparc x86 ++ sparc x86 xtensa + + SUBDIRS = \ + $(HOST_CPU) +diff --git a/sysdeps/linux-gnu/xtensa/Makefile.am b/sysdeps/linux-gnu/xtensa/Makefile.am +new file mode 100644 +index 0000000..9ce81e1 +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/Makefile.am +@@ -0,0 +1,36 @@ ++# This file is part of ltrace. ++# Copyright (C) 2014 Cadence Design Systems Inc. ++# ++# This program is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2 of the ++# License, or (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++# 02110-1301 USA ++ ++noinst_LTLIBRARIES = \ ++ ../libcpu.la ++ ++___libcpu_la_SOURCES = \ ++ breakpoint.c \ ++ fetch.c \ ++ plt.c \ ++ regs.c \ ++ trace.c ++ ++noinst_HEADERS = \ ++ arch.h \ ++ ptrace.h \ ++ signalent.h \ ++ syscallent.h ++ ++MAINTAINERCLEANFILES = \ ++ Makefile.in +diff --git a/sysdeps/linux-gnu/xtensa/arch.h b/sysdeps/linux-gnu/xtensa/arch.h +new file mode 100644 +index 0000000..c4d300a +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/arch.h +@@ -0,0 +1,111 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++ ++#ifdef __XTENSA_EL__ ++ ++# define ARCH_ENDIAN_LITTLE ++ ++# define BREAKPOINT_VALUE { 0x00, 0x41, 0x00 } ++# define DENSITY_BREAKPOINT_VALUE { 0x2d, 0xf1 } ++ ++# define XTENSA_OP0_MASK 0xf ++# define XTENSA_DENSITY_FIRST 0x8 ++# define XTENSA_DENSITY_LAST 0xe ++# define XTENSA_SYSCALL_MASK 0xffffff ++# define XTENSA_SYSCALL_VALUE 0x005000 ++# define XTENSA_ENTRY_MASK 0xff ++# define XTENSA_ENTRY_VALUE 0x36 ++ ++#elif defined(__XTENSA_EB__) ++ ++# define ARCH_ENDIAN_BIG ++ ++# define BREAKPOINT_VALUE { 0x00, 0x14, 0x00 } ++# define DENSITY_BREAKPOINT_VALUE { 0xd2, 0x1f } ++ ++# define XTENSA_OP0_MASK 0xf0 ++# define XTENSA_DENSITY_FIRST 0x80 ++# define XTENSA_DENSITY_LAST 0xe0 ++# define XTENSA_SYSCALL_MASK 0xffffff00 ++# define XTENSA_SYSCALL_VALUE 0x00050000 ++# define XTENSA_ENTRY_MASK 0xff000000 ++# define XTENSA_ENTRY_VALUE 0x63000000 ++ ++#else ++# error __XTENSA_EL__ or __XTENSA_EB__ must be defined ++#endif ++ ++#define BREAKPOINT_LENGTH 3 ++#define DENSITY_BREAKPOINT_LENGTH 2 ++ ++#define DECR_PC_AFTER_BREAK 0 ++ ++#define LT_ELFCLASS ELFCLASS32 ++#define LT_ELF_MACHINE EM_XTENSA ++ ++static inline int is_density(const void *p) ++{ ++ const unsigned char *bytes = p; ++ return (bytes[0] & XTENSA_OP0_MASK) >= XTENSA_DENSITY_FIRST && ++ (bytes[0] & XTENSA_OP0_MASK) < XTENSA_DENSITY_LAST; ++} ++ ++#define ARCH_HAVE_LTELF_DATA ++struct arch_ltelf_data { ++}; ++ ++enum xtensa_plt_type { ++ XTENSA_DEFAULT, ++ XTENSA_PLT_UNRESOLVED, ++ XTENSA_PLT_RESOLVED, ++}; ++ ++#define ARCH_HAVE_LIBRARY_DATA ++struct arch_library_data { ++ GElf_Addr loadable_sz; ++}; ++ ++#define ARCH_HAVE_LIBRARY_SYMBOL_DATA ++struct arch_library_symbol_data { ++ enum xtensa_plt_type type; ++ GElf_Addr resolved_addr; ++}; ++ ++#define ARCH_HAVE_BREAKPOINT_DATA ++struct arch_breakpoint_data { ++}; ++ ++#define ARCH_HAVE_PROCESS_DATA ++struct arch_process_data { ++ /* Breakpoint that hits when the dynamic linker is about to ++ * update a .plt slot. NULL before that address is known. */ ++ struct breakpoint *dl_plt_update_bp; ++ ++ /* PLT update breakpoint looks here for the handler. */ ++ struct process_stopping_handler *handler; ++}; ++ ++#define ARCH_HAVE_ADD_PLT_ENTRY ++#define ARCH_HAVE_DYNLINK_DONE ++#define ARCH_HAVE_ENABLE_BREAKPOINT ++#define ARCH_HAVE_GET_SYMINFO ++#define ARCH_HAVE_FETCH_ARG +diff --git a/sysdeps/linux-gnu/xtensa/breakpoint.c b/sysdeps/linux-gnu/xtensa/breakpoint.c +new file mode 100644 +index 0000000..256d1dd +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/breakpoint.c +@@ -0,0 +1,71 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "backend.h" ++#include "sysdep.h" ++#include "breakpoint.h" ++#include "proc.h" ++#include "library.h" ++ ++void ++arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) ++{ ++ static unsigned char break_insn[] = BREAKPOINT_VALUE; ++ static unsigned char density_break_insn[] = DENSITY_BREAKPOINT_VALUE; ++ unsigned char *bytes; ++ long a; ++ ++ debug(DEBUG_PROCESS, ++ "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s", ++ pid, sbp->addr, breakpoint_name(sbp)); ++ ++ errno = 0; ++ a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0); ++ if (a == -1 && errno) { ++ fprintf(stderr, "enable_breakpoint" ++ " pid=%d, addr=%p, symbol=%s: %s\n", ++ pid, sbp->addr, breakpoint_name(sbp), ++ strerror(errno)); ++ return; ++ } ++ bytes = (unsigned char *)&a; ++ memcpy(sbp->orig_value, bytes, BREAKPOINT_LENGTH); ++ if (is_density(bytes)) { ++ memcpy(bytes, density_break_insn, DENSITY_BREAKPOINT_LENGTH); ++ } else { ++ memcpy(bytes, break_insn, BREAKPOINT_LENGTH); ++ } ++ a = ptrace(PTRACE_POKETEXT, pid, sbp->addr, a); ++ if (a == -1) { ++ fprintf(stderr, "enable_breakpoint" ++ " pid=%d, addr=%p, symbol=%s: %s\n", ++ pid, sbp->addr, breakpoint_name(sbp), ++ strerror(errno)); ++ return; ++ } ++} +diff --git a/sysdeps/linux-gnu/xtensa/fetch.c b/sysdeps/linux-gnu/xtensa/fetch.c +new file mode 100644 +index 0000000..c211ac5 +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/fetch.c +@@ -0,0 +1,188 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "backend.h" ++#include "fetch.h" ++#include "library.h" ++#include "proc.h" ++#include "ptrace.h" ++#include "type.h" ++#include "value.h" ++ ++enum { ++ MAX_REG_ARG_WORDS = 6, ++ REG_ARG_BASE_REG = 2, ++ ++ MAX_RETURN_WORDS = 4, ++ RETURN_BASE_REG = 10, ++ SYSCALL_RETURN_BASE_REG = 2, ++}; ++ ++struct fetch_context { ++ unsigned arg_word_idx; ++ arch_addr_t sp; ++ arch_addr_t ret_struct; ++ ++}; ++ ++struct fetch_context * ++arch_fetch_arg_init(enum tof type, struct process *proc, ++ struct arg_type_info *ret_info) ++{ ++ struct fetch_context *ctx = malloc(sizeof(*ctx)); ++ size_t ret_sz = type_sizeof(proc, ret_info); ++ unsigned long sp = ptrace(PTRACE_PEEKUSER, proc->pid, ++ (REG_A_BASE + 1), 0); ++ ++ if (ctx == NULL || sp == (size_t)-1) { ++ free(ctx); ++ return NULL; ++ } ++ ++ ctx->arg_word_idx = 0; ++ ctx->sp = (arch_addr_t)sp; ++ ctx->ret_struct = NULL; ++ ++ if (ret_sz > MAX_RETURN_WORDS * sizeof(long)) { ++ unsigned long a2 = ptrace(PTRACE_PEEKUSER, proc->pid, ++ (REG_A_BASE + 2), 0); ++ ctx->ret_struct = (arch_addr_t)a2; ++ ++ctx->arg_word_idx; ++ } ++ ++ return ctx; ++} ++ ++struct fetch_context * ++arch_fetch_arg_clone(struct process *proc, ++ struct fetch_context *ctx) ++{ ++ struct fetch_context *clone = malloc(sizeof(*ctx)); ++ ++ if (clone == NULL) ++ return NULL; ++ *clone = *ctx; ++ return clone; ++} ++ ++int ++arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, ++ struct process *proc, ++ struct arg_type_info *info, struct value *valuep) ++{ ++ size_t sz = type_sizeof(proc, info); ++ size_t al = type_alignof(proc, info); ++ size_t words = (sz + sizeof(long) - 1) / sizeof(long); ++ ++ assert(sz != (size_t)-1); ++ assert(al != (size_t)-1); ++ ++ if (al > sizeof(long)) { ++ al /= sizeof(long); ++ ctx->arg_word_idx = (ctx->arg_word_idx + al - 1) & ~(al - 1); ++ } ++ ++ if (ctx->arg_word_idx + words <= MAX_REG_ARG_WORDS) { ++ size_t i; ++ unsigned char *data = value_reserve(valuep, sz); ++ ++ if (data == NULL) ++ return -1; ++ ++ for (i = 0; i < words; ++i) { ++ static const unsigned syscall_reg[] = { ++ 6, 3, 4, 5, 8, 9 ++ }; ++ unsigned regnr = ++ (type == LT_TOF_FUNCTION ? ++ REG_ARG_BASE_REG + ctx->arg_word_idx + i : ++ syscall_reg[ctx->arg_word_idx + i]); ++ unsigned long a = ptrace(PTRACE_PEEKUSER, proc->pid, ++ (REG_A_BASE + regnr), 0); ++ size_t copy = sizeof(a) < sz ? sizeof(a) : sz; ++ ++ memcpy(data, &a, copy); ++ data += sizeof(long); ++ sz -= copy; ++ } ++ ctx->arg_word_idx += words; ++ return 0; ++ } else if (ctx->arg_word_idx < MAX_REG_ARG_WORDS) { ++ ctx->arg_word_idx = MAX_REG_ARG_WORDS; ++ } ++ ++ value_in_inferior(valuep, ctx->sp + sizeof(long) * ++ (ctx->arg_word_idx - MAX_REG_ARG_WORDS)); ++ ctx->arg_word_idx += words; ++ ++ return 0; ++} ++ ++int ++arch_fetch_retval(struct fetch_context *ctx, enum tof type, ++ struct process *proc, struct arg_type_info *info, ++ struct value *valuep) ++{ ++ size_t sz = type_sizeof(proc, info); ++ size_t words = (sz + sizeof(long) - 1) / sizeof(long); ++ ++ assert(sz != (size_t)-1); ++ ++ if (words <= MAX_RETURN_WORDS) { ++ size_t i; ++ unsigned char *data = value_reserve(valuep, sz); ++ ++ if (data == NULL) ++ return -1; ++ ++ for (i = 0; i < words; ++i) { ++ unsigned regnr = i + ++ (type == LT_TOF_FUNCTIONR ? ++ RETURN_BASE_REG : SYSCALL_RETURN_BASE_REG); ++ unsigned long a = ptrace(PTRACE_PEEKUSER, proc->pid, ++ (REG_A_BASE + regnr), 0); ++ size_t copy = sizeof(a) < sz ? sizeof(a) : sz; ++ ++ memcpy(data, &a, copy); ++ data += sizeof(long); ++ sz -= copy; ++ } ++ } else { ++ value_in_inferior(valuep, ctx->ret_struct); ++ } ++ return 0; ++} ++ ++void ++arch_fetch_arg_done(struct fetch_context *context) ++{ ++ free(context); ++} +diff --git a/sysdeps/linux-gnu/xtensa/plt.c b/sysdeps/linux-gnu/xtensa/plt.c +new file mode 100644 +index 0000000..dd0a0f1 +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/plt.c +@@ -0,0 +1,463 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "debug.h" ++#include "proc.h" ++#include "library.h" ++#include "breakpoint.h" ++#include "backend.h" ++#include "trace.h" ++ ++static void ++mark_as_resolved(struct process *proc, struct library_symbol *libsym, ++ GElf_Addr value) ++{ ++ arch_addr_t addr = (arch_addr_t)(intptr_t)libsym->arch.resolved_addr; ++ struct breakpoint *bp = insert_breakpoint_at(proc, addr, libsym); ++ ++ if (bp != NULL) { ++ enable_breakpoint(proc, bp); ++ } ++ libsym->arch.type = XTENSA_PLT_RESOLVED; ++ libsym->arch.resolved_addr = value; ++} ++ ++static int ++read_plt_slot_value(struct process *proc, arch_addr_t addr, GElf_Addr *valp) ++{ ++ long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr); ++ ++ if (l < 0) { ++ debug(DEBUG_EVENT, "ptrace .plt slot value @%p: %s", ++ addr, strerror(errno)); ++ return -1; ++ } ++ ++ *valp = (GElf_Addr)l; ++ return 0; ++} ++ ++static int ++unresolve_plt_slot(struct process *proc, arch_addr_t addr, GElf_Addr value) ++{ ++ if (ptrace(PTRACE_POKETEXT, proc->pid, addr, ++ (void *)(intptr_t)value) < 0) { ++ debug(DEBUG_EVENT, "failed to unresolve .plt slot @%p: %s", ++ addr, strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++int ++arch_elf_init(struct ltelf *lte, struct library *lib) ++{ ++ Elf_Scn *scn; ++ GElf_Shdr shdr; ++ GElf_Addr relplt_addr; ++ GElf_Phdr phdr; ++ GElf_Addr low, high; ++ int has_loadable = 0; ++ size_t i; ++ ++ for (i = 0; gelf_getphdr(lte->elf, i, &phdr) != NULL; ++i) { ++ if (phdr.p_type == PT_LOAD) { ++ if (has_loadable) { ++ if (phdr.p_vaddr < low) ++ low = phdr.p_vaddr; ++ if (phdr.p_vaddr + phdr.p_memsz > high) ++ high = phdr.p_vaddr + phdr.p_memsz; ++ } else { ++ has_loadable = 1; ++ low = phdr.p_vaddr; ++ high = phdr.p_vaddr + phdr.p_memsz; ++ } ++ } ++ } ++ lib->arch.loadable_sz = has_loadable ? high - low : 0; ++ ++ if (elf_load_dynamic_entry(lte, DT_JMPREL, &relplt_addr) < 0 || ++ elf_get_section_covering(lte, relplt_addr, &scn, &shdr) < 0 || ++ scn == NULL) ++ return 0; ++ ++ if (elf_read_relocs(lte, scn, &shdr, <e->plt_relocs) < 0) { ++ fprintf(stderr, "Couldn't get .rel*.plt data: %s\n", ++ elf_errmsg(-1)); ++ return -1; ++ } ++ return 0; ++} ++ ++void ++arch_elf_destroy(struct ltelf *lte) ++{ ++} ++ ++int ++arch_get_sym_info(struct ltelf *lte, const char *filename, ++ size_t sym_index, GElf_Rela *rela, GElf_Sym *sym) ++{ ++ if (gelf_getsym(lte->dynsym, ELF64_R_SYM(rela->r_info), sym) == NULL) ++ return -1; ++ ++ /* .rela.plt entries that reference locally defined functions point ++ * to their entry points directly, not to PLT entries. Skip such ++ * symbols. */ ++ if (sym->st_shndx != SHN_UNDEF) { ++ const char *name = lte->dynstr + sym->st_name; ++ debug(2, "symbol %s does not have plt entry", name); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++enum plt_status ++arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte, ++ const char *name, GElf_Rela *rela, size_t ndx, ++ struct library_symbol **ret) ++{ ++ if (default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret) < 0) { ++ return PLT_FAIL; ++ } ++ ++ /* All PLT library symbols are initially marked as delayed. Some of ++ * them may reference weak symbols that are never loaded, sym2addr for ++ * such entries will return NULL. All other symbols are activated ++ * after the dynlink is done. */ ++ (*ret)->delayed = 1; ++ return PLT_OK; ++} ++ ++void ++arch_dynlink_done(struct process *proc) ++{ ++ struct library_symbol *libsym = NULL; ++ ++ while ((libsym = proc_each_symbol(proc, libsym, ++ library_symbol_delayed_cb, NULL))) { ++ assert(libsym->plt_type == LS_TOPLT_EXEC); ++ ++ if (read_plt_slot_value(proc, libsym->enter_addr, ++ &libsym->arch.resolved_addr) == 0 && ++ libsym->arch.resolved_addr) { ++ GElf_Addr base = ++ (GElf_Addr)(intptr_t)libsym->lib->base; ++ GElf_Addr sz = libsym->lib->arch.loadable_sz; ++ ++ /* Some references may be resolved at this point, they ++ * will point outside the loadable area of their own ++ * library. */ ++ if (libsym->arch.resolved_addr >= base && ++ libsym->arch.resolved_addr - base < sz) { ++ libsym->arch.type = XTENSA_PLT_UNRESOLVED; ++ proc_activate_delayed_symbol(proc, libsym); ++ } else { ++ libsym->arch.type = XTENSA_PLT_RESOLVED; ++ } ++ } ++ } ++} ++ ++GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) ++{ ++ return rela->r_offset; ++} ++ ++void *sym2addr(struct process *proc, struct library_symbol *sym) ++{ ++ void *addr = NULL; ++ long ret = ptrace(PTRACE_PEEKTEXT, proc->pid, sym->enter_addr, 0); ++ ++ switch (sym->plt_type) { ++ case LS_TOPLT_NONE: ++ addr = sym->enter_addr; ++ ++ /* Not every exported function starts with ENTRY instruction, ++ * e.g. _start does not. Only skip first instruction if it's ++ * entry, otherwise don't do it: if the first instruction is ++ * FLIX or density it will break it or the following ++ * instruction. */ ++ if ((ret & XTENSA_ENTRY_MASK) == XTENSA_ENTRY_VALUE) { ++ addr += 3; ++ } ++ break; ++ ++ case LS_TOPLT_EXEC: ++ ++ /* OTOH every PLT entry starts with ENTRY. Put initial ++ * breakpoint after it. After symbol resolution put ++ * additional breakpoint at the first instruction. */ ++ addr = (ret == -1 || ret == 0) ? NULL : (void *)(ret + 3); ++ break; ++ } ++ return addr; ++} ++ ++int ++arch_library_symbol_init(struct library_symbol *libsym) ++{ ++ libsym->arch.type = XTENSA_DEFAULT; ++ return 0; ++} ++ ++void ++arch_library_symbol_destroy(struct library_symbol *libsym) ++{ ++} ++ ++int ++arch_library_symbol_clone(struct library_symbol *retp, ++ struct library_symbol *libsym) ++{ ++ retp->arch = libsym->arch; ++ return 0; ++} ++ ++static void ++dl_plt_update_bp_on_hit(struct breakpoint *bp, struct process *proc) ++{ ++ debug(DEBUG_PROCESS, "pid=%d dl_plt_update_bp_on_hit %s(%p)", ++ proc->pid, breakpoint_name(bp), bp->addr); ++ struct process_stopping_handler *self = proc->arch.handler; ++ assert(self != NULL); ++ ++ struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; ++ GElf_Addr value; ++ if (read_plt_slot_value(proc, libsym->enter_addr, &value) < 0) ++ return; ++ ++ unresolve_plt_slot(proc, libsym->enter_addr, ++ libsym->arch.resolved_addr); ++ mark_as_resolved(proc, libsym, value); ++ ++ /* cb_on_all_stopped looks if HANDLER is set to NULL as a way ++ * to check that this was run. It's an error if it ++ * wasn't. */ ++ proc->arch.handler = NULL; ++ ++ breakpoint_turn_off(bp, proc); ++} ++ ++static enum callback_status ++cb_keep_stepping_p(struct process_stopping_handler *self) ++{ ++ struct process *proc = self->task_enabling_breakpoint; ++ struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; ++ ++ GElf_Addr value; ++ if (read_plt_slot_value(proc, libsym->enter_addr, &value) < 0) ++ return CBS_FAIL; ++ ++ /* In UNRESOLVED state, the resolved_addr in fact contains ++ * the PLT entry value. */ ++ if (value == libsym->arch.resolved_addr) { ++ /* Don't try to single-step over our own breakpoint infinitely. ++ * This may happen if we fail to detect resolved PLT entry. */ ++ if (address2bpstruct(proc, get_instruction_pointer(proc))) { ++ return CBS_FAIL; ++ } ++ return CBS_CONT; ++ } ++ ++ debug(DEBUG_PROCESS, "pid=%d PLT got resolved to value %#"PRIx64, ++ proc->pid, value); ++ ++ /* The .plt slot got resolved! We can migrate the breakpoint ++ * to RESOLVED and stop single-stepping. */ ++ if (unresolve_plt_slot(proc, libsym->enter_addr, ++ libsym->arch.resolved_addr) < 0) ++ return CBS_FAIL; ++ ++ /* Install breakpoint to the address where the change takes ++ * place. If we fail, then that just means that we'll have to ++ * singlestep the next time around as well. */ ++ struct process *leader = proc->leader; ++ if (leader == NULL || leader->arch.dl_plt_update_bp != NULL) ++ goto done; ++ ++ arch_addr_t addr = get_instruction_pointer(proc); ++ struct breakpoint *dl_plt_update_bp = ++ insert_breakpoint_at(proc, addr, NULL); ++ if (dl_plt_update_bp == NULL) ++ goto done; ++ ++ leader->arch.dl_plt_update_bp = dl_plt_update_bp; ++ ++ static struct bp_callbacks dl_plt_update_cbs = { ++ .on_hit = dl_plt_update_bp_on_hit, ++ }; ++ breakpoint_set_callbacks(dl_plt_update_bp, &dl_plt_update_cbs); ++ ++ /* Turn it off for now. We will turn it on again when we hit ++ * the PLT entry that needs this. */ ++ breakpoint_turn_off(dl_plt_update_bp, proc); ++ ++done: ++ mark_as_resolved(proc, libsym, value); ++ ++ return CBS_STOP; ++} ++ ++static void ++cb_on_all_stopped(struct process_stopping_handler *self) ++{ ++ /* Put that in for dl_plt_update_bp_on_hit to see. */ ++ assert(self->task_enabling_breakpoint->arch.handler == NULL); ++ self->task_enabling_breakpoint->arch.handler = self; ++ ++ linux_ptrace_disable_and_continue(self); ++} ++ ++static void ++xtensa_plt_bp_hit(struct breakpoint *bp, struct process *proc) ++{ ++ struct library_symbol *libsym = bp->libsym; ++ ++ if (libsym->arch.type == XTENSA_PLT_RESOLVED) { ++ arch_addr_t addr = ++ (arch_addr_t)(intptr_t)libsym->arch.resolved_addr; ++ ++ set_instruction_pointer(proc, addr); ++ ptrace(PTRACE_SINGLESTEP, proc->pid, NULL, NULL); ++ return; ++ } ++} ++ ++static void ++xtensa_plt_bp_continue(struct breakpoint *bp, struct process *proc) ++{ ++ struct process *leader = proc->leader; ++ void (*on_all_stopped)(struct process_stopping_handler *) = NULL; ++ enum callback_status (*keep_stepping_p) ++ (struct process_stopping_handler *) = NULL; ++ ++ if (bp->libsym->arch.type != XTENSA_PLT_UNRESOLVED) { ++ continue_process(proc->pid); ++ return; ++ } ++ ++ if (leader != NULL && leader->arch.dl_plt_update_bp != NULL && ++ breakpoint_turn_on(leader->arch.dl_plt_update_bp, proc) >= 0) { ++ on_all_stopped = cb_on_all_stopped; ++ } else { ++ keep_stepping_p = cb_keep_stepping_p; ++ } ++ ++ if (process_install_stopping_handler(proc, bp, on_all_stopped, ++ keep_stepping_p, NULL) < 0) { ++ fprintf(stderr, "%s: couldn't install event handler\n", ++ __func__); ++ continue_after_breakpoint(proc, bp); ++ } ++} ++ ++/* For some symbol types, we need to set up custom callbacks. ++ */ ++int ++arch_breakpoint_init(struct process *proc, struct breakpoint *bp) ++{ ++ /* Artificial and entry-point breakpoints are plain. */ ++ if (bp->libsym == NULL || bp->libsym->plt_type != LS_TOPLT_EXEC) ++ return 0; ++ ++ static struct bp_callbacks cbs = { ++ .on_hit = xtensa_plt_bp_hit, ++ .on_continue = xtensa_plt_bp_continue, ++ }; ++ breakpoint_set_callbacks(bp, &cbs); ++ ++ return 0; ++} ++ ++void ++arch_breakpoint_destroy(struct breakpoint *bp) ++{ ++} ++ ++int ++arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) ++{ ++ retp->arch = sbp->arch; ++ return 0; ++} ++ ++int ++arch_process_init(struct process *proc) ++{ ++ proc->arch.dl_plt_update_bp = NULL; ++ return 0; ++} ++ ++void ++arch_process_destroy(struct process *proc) ++{ ++} ++ ++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; ++} ++ ++int ++arch_process_exec(struct process *proc) ++{ ++ return arch_process_init(proc); ++} ++ ++int ++arch_library_init(struct library *lib) ++{ ++ return 0; ++} ++ ++void ++arch_library_destroy(struct library *lib) ++{ ++} ++ ++int ++arch_library_clone(struct library *retp, struct library *lib) ++{ ++ return 0; ++} +diff --git a/sysdeps/linux-gnu/xtensa/ptrace.h b/sysdeps/linux-gnu/xtensa/ptrace.h +new file mode 100644 +index 0000000..6e67fff +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/ptrace.h +@@ -0,0 +1,21 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include +diff --git a/sysdeps/linux-gnu/xtensa/regs.c b/sysdeps/linux-gnu/xtensa/regs.c +new file mode 100644 +index 0000000..a5a8c8d +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/regs.c +@@ -0,0 +1,83 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "proc.h" ++#include "common.h" ++ ++static int xtensa_peek_user(struct process *proc, unsigned addr, ++ unsigned long *res) ++{ ++ long retval; ++ ++ errno = 0; ++ retval = ptrace(PTRACE_PEEKUSER, proc->pid, addr, 0); ++ if (retval == -1 && errno) { ++ fprintf(stderr, "%s: pid=%d, %s\n", ++ __func__, proc->pid, strerror(errno)); ++ *res = 0; ++ return 0; ++ } ++ *res = retval; ++ return 1; ++} ++ ++void *get_instruction_pointer(struct process *proc) ++{ ++ unsigned long res; ++ ++ if (xtensa_peek_user(proc, REG_PC, &res)) ++ return (void *)res; ++ else ++ return NULL; ++} ++ ++void set_instruction_pointer(struct process *proc, void *addr) ++{ ++ ptrace(PTRACE_POKEUSER, proc->pid, REG_PC, addr); ++} ++ ++void *get_stack_pointer(struct process *proc) ++{ ++ unsigned long res; ++ ++ if (xtensa_peek_user(proc, REG_A_BASE + 1, &res)) ++ return (void *)res; ++ else ++ return NULL; ++} ++ ++void *get_return_addr(struct process *proc, void *stack_pointer) ++{ ++ unsigned long res; ++ ++ if (xtensa_peek_user(proc, REG_A_BASE, &res)) ++ /* Assume call8, mask the upper 2 bits. */ ++ return (void *)(0x3FFFFFFF & res); ++ else ++ return NULL; ++} +diff --git a/sysdeps/linux-gnu/xtensa/signalent.h b/sysdeps/linux-gnu/xtensa/signalent.h +new file mode 100644 +index 0000000..953534d +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/signalent.h +@@ -0,0 +1,52 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++ "SIG_0", /* 0 */ ++ "SIGHUP", /* 1 */ ++ "SIGINT", /* 2 */ ++ "SIGQUIT", /* 3 */ ++ "SIGILL", /* 4 */ ++ "SIGTRAP", /* 5 */ ++ "SIGABRT", /* 6 */ ++ "SIGBUS", /* 7 */ ++ "SIGFPE", /* 8 */ ++ "SIGKILL", /* 9 */ ++ "SIGUSR1", /* 10 */ ++ "SIGSEGV", /* 11 */ ++ "SIGUSR2", /* 12 */ ++ "SIGPIPE", /* 13 */ ++ "SIGALRM", /* 14 */ ++ "SIGTERM", /* 15 */ ++ "SIGSTKFLT", /* 16 */ ++ "SIGCHLD", /* 17 */ ++ "SIGCONT", /* 18 */ ++ "SIGSTOP", /* 19 */ ++ "SIGTSTP", /* 20 */ ++ "SIGTTIN", /* 21 */ ++ "SIGTTOU", /* 22 */ ++ "SIGURG", /* 23 */ ++ "SIGXCPU", /* 24 */ ++ "SIGXFSZ", /* 25 */ ++ "SIGVTALRM", /* 26 */ ++ "SIGPROF", /* 27 */ ++ "SIGWINCH", /* 28 */ ++ "SIGIO", /* 29 */ ++ "SIGPWR", /* 30 */ ++ "SIGSYS", /* 31 */ +diff --git a/sysdeps/linux-gnu/xtensa/syscallent.h b/sysdeps/linux-gnu/xtensa/syscallent.h +new file mode 100644 +index 0000000..ff19d83 +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/syscallent.h +@@ -0,0 +1,357 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++ "spill", /* 0 */ ++ "xtensa", /* 1 */ ++ "available4", /* 2 */ ++ "available5", /* 3 */ ++ "available6", /* 4 */ ++ "available7", /* 5 */ ++ "available8", /* 6 */ ++ "available9", /* 7 */ ++ "open", /* 8 */ ++ "close", /* 9 */ ++ "dup", /* 10 */ ++ "dup2", /* 11 */ ++ "read", /* 12 */ ++ "write", /* 13 */ ++ "select", /* 14 */ ++ "lseek", /* 15 */ ++ "poll", /* 16 */ ++ "_llseek", /* 17 */ ++ "epoll_wait", /* 18 */ ++ "epoll_ctl", /* 19 */ ++ "epoll_create", /* 20 */ ++ "creat", /* 21 */ ++ "truncate", /* 22 */ ++ "ftruncate", /* 23 */ ++ "readv", /* 24 */ ++ "writev", /* 25 */ ++ "fsync", /* 26 */ ++ "fdatasync", /* 27 */ ++ "truncate64", /* 28 */ ++ "ftruncate64", /* 29 */ ++ "pread64", /* 30 */ ++ "pwrite64", /* 31 */ ++ "link", /* 32 */ ++ "rename", /* 33 */ ++ "symlink", /* 34 */ ++ "readlink", /* 35 */ ++ "mknod", /* 36 */ ++ "pipe", /* 37 */ ++ "unlink", /* 38 */ ++ "rmdir", /* 39 */ ++ "mkdir", /* 40 */ ++ "chdir", /* 41 */ ++ "fchdir", /* 42 */ ++ "getcwd", /* 43 */ ++ "chmod", /* 44 */ ++ "chown", /* 45 */ ++ "stat", /* 46 */ ++ "stat64", /* 47 */ ++ "lchown", /* 48 */ ++ "lstat", /* 49 */ ++ "lstat64", /* 50 */ ++ "available51", /* 51 */ ++ "fchmod", /* 52 */ ++ "fchown", /* 53 */ ++ "fstat", /* 54 */ ++ "fstat64", /* 55 */ ++ "flock", /* 56 */ ++ "access", /* 57 */ ++ "umask", /* 58 */ ++ "getdents", /* 59 */ ++ "getdents64", /* 60 */ ++ "fcntl64", /* 61 */ ++ "available62", /* 62 */ ++ "fadvise64_64", /* 63 */ ++ "utime", /* 64 */ ++ "utimes", /* 65 */ ++ "ioctl", /* 66 */ ++ "fcntl", /* 67 */ ++ "setxattr", /* 68 */ ++ "getxattr", /* 69 */ ++ "listxattr", /* 70 */ ++ "removexattr", /* 71 */ ++ "lsetxattr", /* 72 */ ++ "lgetxattr", /* 73 */ ++ "llistxattr", /* 74 */ ++ "lremovexattr", /* 75 */ ++ "fsetxattr", /* 76 */ ++ "fgetxattr", /* 77 */ ++ "flistxattr", /* 78 */ ++ "fremovexattr", /* 79 */ ++ "mmap2", /* 80 */ ++ "munmap", /* 81 */ ++ "mprotect", /* 82 */ ++ "brk", /* 83 */ ++ "mlock", /* 84 */ ++ "munlock", /* 85 */ ++ "mlockall", /* 86 */ ++ "munlockall", /* 87 */ ++ "mremap", /* 88 */ ++ "msync", /* 89 */ ++ "mincore", /* 90 */ ++ "madvise", /* 91 */ ++ "shmget", /* 92 */ ++ "shmat", /* 93 */ ++ "shmctl", /* 94 */ ++ "shmdt", /* 95 */ ++ "socket", /* 96 */ ++ "setsockopt", /* 97 */ ++ "getsockopt", /* 98 */ ++ "shutdown", /* 99 */ ++ "bind", /* 100 */ ++ "connect", /* 101 */ ++ "listen", /* 102 */ ++ "accept", /* 103 */ ++ "getsockname", /* 104 */ ++ "getpeername", /* 105 */ ++ "sendmsg", /* 106 */ ++ "recvmsg", /* 107 */ ++ "send", /* 108 */ ++ "recv", /* 109 */ ++ "sendto", /* 110 */ ++ "recvfrom", /* 111 */ ++ "socketpair", /* 112 */ ++ "sendfile", /* 113 */ ++ "sendfile64", /* 114 */ ++ "sendmmsg", /* 115 */ ++ "clone", /* 116 */ ++ "execve", /* 117 */ ++ "exit", /* 118 */ ++ "exit_group", /* 119 */ ++ "getpid", /* 120 */ ++ "wait4", /* 121 */ ++ "waitid", /* 122 */ ++ "kill", /* 123 */ ++ "tkill", /* 124 */ ++ "tgkill", /* 125 */ ++ "set_tid_address", /* 126 */ ++ "gettid", /* 127 */ ++ "setsid", /* 128 */ ++ "getsid", /* 129 */ ++ "prctl", /* 130 */ ++ "personality", /* 131 */ ++ "getpriority", /* 132 */ ++ "setpriority", /* 133 */ ++ "setitimer", /* 134 */ ++ "getitimer", /* 135 */ ++ "setuid", /* 136 */ ++ "getuid", /* 137 */ ++ "setgid", /* 138 */ ++ "getgid", /* 139 */ ++ "geteuid", /* 140 */ ++ "getegid", /* 141 */ ++ "setreuid", /* 142 */ ++ "setregid", /* 143 */ ++ "setresuid", /* 144 */ ++ "getresuid", /* 145 */ ++ "setresgid", /* 146 */ ++ "getresgid", /* 147 */ ++ "setpgid", /* 148 */ ++ "getpgid", /* 149 */ ++ "getppid", /* 150 */ ++ "getpgrp", /* 151 */ ++ "reserved152", /* 152 */ ++ "reserved153", /* 153 */ ++ "times", /* 154 */ ++ "acct", /* 155 */ ++ "sched_setaffinity", /* 156 */ ++ "sched_getaffinity", /* 157 */ ++ "capget", /* 158 */ ++ "capset", /* 159 */ ++ "ptrace", /* 160 */ ++ "semtimedop", /* 161 */ ++ "semget", /* 162 */ ++ "semop", /* 163 */ ++ "semctl", /* 164 */ ++ "available165", /* 165 */ ++ "msgget", /* 166 */ ++ "msgsnd", /* 167 */ ++ "msgrcv", /* 168 */ ++ "msgctl", /* 169 */ ++ "available170", /* 170 */ ++ "umount2", /* 171 */ ++ "mount", /* 172 */ ++ "swapon", /* 173 */ ++ "chroot", /* 174 */ ++ "pivot_root", /* 175 */ ++ "umount", /* 176 */ ++ "swapoff", /* 177 */ ++ "sync", /* 178 */ ++ "syncfs", /* 179 */ ++ "setfsuid", /* 180 */ ++ "setfsgid", /* 181 */ ++ "sysfs", /* 182 */ ++ "ustat", /* 183 */ ++ "statfs", /* 184 */ ++ "fstatfs", /* 185 */ ++ "statfs64", /* 186 */ ++ "fstatfs64", /* 187 */ ++ "setrlimit", /* 188 */ ++ "getrlimit", /* 189 */ ++ "getrusage", /* 190 */ ++ "futex", /* 191 */ ++ "gettimeofday", /* 192 */ ++ "settimeofday", /* 193 */ ++ "adjtimex", /* 194 */ ++ "nanosleep", /* 195 */ ++ "getgroups", /* 196 */ ++ "setgroups", /* 197 */ ++ "sethostname", /* 198 */ ++ "setdomainname", /* 199 */ ++ "syslog", /* 200 */ ++ "vhangup", /* 201 */ ++ "uselib", /* 202 */ ++ "reboot", /* 203 */ ++ "quotactl", /* 204 */ ++ "nfsservctl", /* 205 */ ++ "_sysctl", /* 206 */ ++ "bdflush", /* 207 */ ++ "uname", /* 208 */ ++ "sysinfo", /* 209 */ ++ "init_module", /* 210 */ ++ "delete_module", /* 211 */ ++ "sched_setparam", /* 212 */ ++ "sched_getparam", /* 213 */ ++ "sched_setscheduler", /* 214 */ ++ "sched_getscheduler", /* 215 */ ++ "sched_get_priority_max", /* 216 */ ++ "sched_get_priority_min", /* 217 */ ++ "sched_rr_get_interval", /* 218 */ ++ "sched_yield", /* 219 */ ++ "220", /* 220 */ ++ "221", /* 221 */ ++ "available222", /* 222 */ ++ "restart_syscall", /* 223 */ ++ "sigaltstack", /* 224 */ ++ "rt_sigreturn", /* 225 */ ++ "rt_sigaction", /* 226 */ ++ "rt_sigprocmask", /* 227 */ ++ "rt_sigpending", /* 228 */ ++ "rt_sigtimedwait", /* 229 */ ++ "rt_sigqueueinfo", /* 230 */ ++ "rt_sigsuspend", /* 231 */ ++ "mq_open", /* 232 */ ++ "mq_unlink", /* 233 */ ++ "mq_timedsend", /* 234 */ ++ "mq_timedreceive", /* 235 */ ++ "mq_notify", /* 236 */ ++ "mq_getsetattr", /* 237 */ ++ "available238", /* 238 */ ++ "io_setup", /* 239 */ ++ "io_destroy", /* 240 */ ++ "io_submit", /* 241 */ ++ "io_getevents", /* 242 */ ++ "io_cancel", /* 243 */ ++ "clock_settime", /* 244 */ ++ "clock_gettime", /* 245 */ ++ "clock_getres", /* 246 */ ++ "clock_nanosleep", /* 247 */ ++ "timer_create", /* 248 */ ++ "timer_delete", /* 249 */ ++ "timer_settime", /* 250 */ ++ "timer_gettime", /* 251 */ ++ "timer_getoverrun", /* 252 */ ++ "reserved253", /* 253 */ ++ "lookup_dcookie", /* 254 */ ++ "available255", /* 255 */ ++ "add_key", /* 256 */ ++ "request_key", /* 257 */ ++ "keyctl", /* 258 */ ++ "available259", /* 259 */ ++ "readahead", /* 260 */ ++ "remap_file_pages", /* 261 */ ++ "migrate_pages", /* 262 */ ++ "mbind", /* 263 */ ++ "get_mempolicy", /* 264 */ ++ "set_mempolicy", /* 265 */ ++ "unshare", /* 266 */ ++ "move_pages", /* 267 */ ++ "splice", /* 268 */ ++ "tee", /* 269 */ ++ "vmsplice", /* 270 */ ++ "available271", /* 271 */ ++ "pselect6", /* 272 */ ++ "ppoll", /* 273 */ ++ "epoll_pwait", /* 274 */ ++ "epoll_create1", /* 275 */ ++ "inotify_init", /* 276 */ ++ "inotify_add_watch", /* 277 */ ++ "inotify_rm_watch", /* 278 */ ++ "inotify_init1", /* 279 */ ++ "getcpu", /* 280 */ ++ "kexec_load", /* 281 */ ++ "ioprio_set", /* 282 */ ++ "ioprio_get", /* 283 */ ++ "set_robust_list", /* 284 */ ++ "get_robust_list", /* 285 */ ++ "available286", /* 286 */ ++ "available287", /* 287 */ ++ "openat", /* 288 */ ++ "mkdirat", /* 289 */ ++ "mknodat", /* 290 */ ++ "unlinkat", /* 291 */ ++ "renameat", /* 292 */ ++ "linkat", /* 293 */ ++ "symlinkat", /* 294 */ ++ "readlinkat", /* 295 */ ++ "utimensat", /* 296 */ ++ "fchownat", /* 297 */ ++ "futimesat", /* 298 */ ++ "fstatat64", /* 299 */ ++ "fchmodat", /* 300 */ ++ "faccessat", /* 301 */ ++ "available302", /* 302 */ ++ "available303", /* 303 */ ++ "signalfd", /* 304 */ ++ "305", /* 305 */ ++ "eventfd", /* 306 */ ++ "recvmmsg", /* 307 */ ++ "setns", /* 308 */ ++ "signalfd4", /* 309 */ ++ "dup3", /* 310 */ ++ "pipe2", /* 311 */ ++ "timerfd_create", /* 312 */ ++ "timerfd_settime", /* 313 */ ++ "timerfd_gettime", /* 314 */ ++ "available315", /* 315 */ ++ "eventfd2", /* 316 */ ++ "preadv", /* 317 */ ++ "pwritev", /* 318 */ ++ "available319", /* 319 */ ++ "fanotify_init", /* 320 */ ++ "fanotify_mark", /* 321 */ ++ "process_vm_readv", /* 322 */ ++ "process_vm_writev", /* 323 */ ++ "name_to_handle_at", /* 324 */ ++ "open_by_handle_at", /* 325 */ ++ "sync_file_range", /* 326 */ ++ "perf_event_open", /* 327 */ ++ "rt_tgsigqueueinfo", /* 328 */ ++ "clock_adjtime", /* 329 */ ++ "prlimit64", /* 330 */ ++ "kcmp", /* 331 */ ++ "finit_module", /* 332 */ ++ "accept4", /* 333 */ ++ "sched_setattr", /* 334 */ ++ "sched_getattr", /* 335 */ ++ "syscall_count", /* 336 */ +diff --git a/sysdeps/linux-gnu/xtensa/trace.c b/sysdeps/linux-gnu/xtensa/trace.c +new file mode 100644 +index 0000000..c7d3077 +--- /dev/null ++++ b/sysdeps/linux-gnu/xtensa/trace.c +@@ -0,0 +1,61 @@ ++/* ++ * This file is part of ltrace. ++ * Copyright (C) 2014 Cadence Design Systems Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ++ * 02110-1301 USA ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "proc.h" ++ ++void ++get_arch_dep(struct process *proc) ++{ ++} ++ ++/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ ++int syscall_p(struct process *proc, int status, int *sysnum) ++{ ++ if (WIFSTOPPED(status) ++ && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { ++ /* get the user's pc */ ++ int pc = ptrace(PTRACE_PEEKUSER, proc->pid, REG_PC, 0); ++ ++ /* fetch the SWI instruction */ ++ int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 3, 0); ++ ++ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, SYSCALL_NR, 0); ++ /* if it is a syscall, return 1 or 2 */ ++ if ((insn & XTENSA_SYSCALL_MASK) == XTENSA_SYSCALL_VALUE) { ++ if ((proc->callstack_depth > 0) ++ && proc->callstack[proc->callstack_depth ++ - 1].is_syscall) { ++ return 2; ++ } else { ++ return 1; ++ } ++ } ++ } ++ return 0; ++} +-- +1.8.1.4 + diff --git a/package/ltrace/Config.in b/package/ltrace/Config.in index 56e4402b88..e7237da801 100644 --- a/package/ltrace/Config.in +++ b/package/ltrace/Config.in @@ -5,7 +5,7 @@ config BR2_PACKAGE_LTRACE # 'relplt_count'). Issue reported upstream at # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=756764. depends on (BR2_i386 || BR2_arm \ - || BR2_powerpc || BR2_sparc || BR2_x86_64) + || BR2_powerpc || BR2_sparc || BR2_x86_64 || BR2_xtensa) select BR2_PACKAGE_ELFUTILS depends on BR2_LARGEFILE # elfutils depends on BR2_USE_WCHAR # elfutils