[Buildroot] [PATCH] package/ltrace: add support for xtensa

Max Filippov jcmvbkbc at gmail.com
Tue Mar 17 20:26:01 UTC 2015


Backported from: 05143c95e4609e5592775fae5facbf77b7bfa694
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
---
 .../ltrace/0004-xtensa-add-xtensa-support.patch    | 1612 ++++++++++++++++++++
 package/ltrace/Config.in                           |    2 +-
 2 files changed, 1613 insertions(+), 1 deletion(-)
 create mode 100644 package/ltrace/0004-xtensa-add-xtensa-support.patch

diff --git a/package/ltrace/0004-xtensa-add-xtensa-support.patch b/package/ltrace/0004-xtensa-add-xtensa-support.patch
new file mode 100644
index 0000000..798a230
--- /dev/null
+++ b/package/ltrace/0004-xtensa-add-xtensa-support.patch
@@ -0,0 +1,1612 @@
+From 05ee6bd2986c62d611ff9dfe6dbf11d2def0844b Mon Sep 17 00:00:00 2001
+From: Max Filippov <jcmvbkbc at gmail.com>
+Date: Sun, 4 Jan 2015 06:57:41 +0300
+Subject: [PATCH] xtensa: add xtensa support
+
+Signed-off-by: Max Filippov <jcmvbkbc at 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 at us.ibm.com
+ D: s390 port
+ 
++N: Max Filippov
++E: jcmvbkbc at gmail.com
++D: xtensa port
++
+ N: Roman Hodek
+ E: Roman.Hodek at 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, &lte->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
+
diff --git a/package/ltrace/Config.in b/package/ltrace/Config.in
index 56e4402..e7237da 100644
--- a/package/ltrace/Config.in
+++ b/package/ltrace/Config.in
@@ -5,7 +5,7 @@ config BR2_PACKAGE_LTRACE
 	# 'relplt_count'). Issue reported upstream at
 	# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=756764.
 	depends on (BR2_i386 || BR2_arm \
-		|| BR2_powerpc || BR2_sparc || BR2_x86_64)
+		|| BR2_powerpc || BR2_sparc || BR2_x86_64 || BR2_xtensa)
 	select BR2_PACKAGE_ELFUTILS
 	depends on BR2_LARGEFILE # elfutils
 	depends on BR2_USE_WCHAR # elfutils
-- 
1.8.1.4



More information about the buildroot mailing list