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