| From 05ee6bd2986c62d611ff9dfe6dbf11d2def0844b Mon Sep 17 00:00:00 2001 |
| From: Max Filippov <jcmvbkbc@gmail.com> |
| Date: Sun, 4 Jan 2015 06:57:41 +0300 |
| Subject: [PATCH] xtensa: add xtensa support |
| |
| Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> |
| --- |
| 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 <gelf.h> |
| + |
| +#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 <sys/ptrace.h> |
| +#include <errno.h> |
| +#include <string.h> |
| +#include <stdio.h> |
| + |
| +#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 <sys/ptrace.h> |
| +#include <asm/ptrace.h> |
| +#include <assert.h> |
| +#include <elf.h> |
| +#include <libelf.h> |
| +#include <stdint.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| +#include <stdbool.h> |
| + |
| +#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 <errno.h> |
| +#include <error.h> |
| +#include <gelf.h> |
| +#include <inttypes.h> |
| +#include <string.h> |
| +#include <sys/ptrace.h> |
| + |
| +#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 <sys/ptrace.h> |
| 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 <errno.h> |
| +#include <string.h> |
| +#include <sys/types.h> |
| +#include <sys/ptrace.h> |
| +#include <asm/ptrace.h> |
| + |
| +#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 <sys/types.h> |
| +#include <sys/wait.h> |
| +#include <signal.h> |
| +#include <sys/ptrace.h> |
| +#include <asm/ptrace.h> |
| + |
| +#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 |
| |