Commit eebf3314 authored by Max Filippov's avatar Max Filippov Committed by Petr Machata

xtensa: add xtensa support

Signed-off-by: default avatarMax Filippov <[email protected]>
parent 9bacde77
......@@ -61,6 +61,10 @@ N: Timothy Fesig
E: [email protected]
D: s390 port
N: Max Filippov
E: [email protected]
D: xtensa port
N: Roman Hodek
E: [email protected]
D: m68k port
......
......@@ -40,6 +40,7 @@
- Imagination Technologies Meta is now supported.
- PowerPC64 ELFv2 little-endian ABI is now supported including full
fetch backend.
- 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
......
......@@ -38,6 +38,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:
......
......@@ -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
......
......@@ -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)
......
# 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
/*
* 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
/*
* 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;
}
}
/*
* 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);
}
This diff is collapsed.
/*
* 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>
/*
* 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;
}
/*
* 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 */
This diff is collapsed.
/*
* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment