|
@@ -0,0 +1,1612 @@
|
|
|
+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
|
|
|
+
|