[Ltrace-devel] [PATCH v2] ltrace: Add support for Imagination Technologies Meta
Markos Chandras
markos.chandras at gmail.com
Tue Mar 19 11:40:29 UTC 2013
From: Markos Chandras <markos.chandras at imgtec.com>
This patchset adds support for Imagination's Meta architecture.
The Meta Linux kernel port will be included in the Linux Kernel
v3.9. It also uses the generic system call numbers.
Signed-off-by: Markos Chandras <markos.chandras at imgtec.com>
---
README | 1 +
configure.ac | 1 +
sysdeps/linux-gnu/metag/Makefile.am | 16 ++
sysdeps/linux-gnu/metag/arch.h | 28 +++
sysdeps/linux-gnu/metag/plt.c | 38 +++
sysdeps/linux-gnu/metag/ptrace.h | 21 ++
sysdeps/linux-gnu/metag/regs.c | 89 ++++++++
sysdeps/linux-gnu/metag/signalent.h | 53 +++++
sysdeps/linux-gnu/metag/syscallent.h | 293 ++++++++++++++++++++++++
sysdeps/linux-gnu/metag/trace.c | 415 ++++++++++++++++++++++++++++++++++
10 files changed, 955 insertions(+), 0 deletions(-)
create mode 100644 sysdeps/linux-gnu/metag/Makefile.am
create mode 100644 sysdeps/linux-gnu/metag/arch.h
create mode 100644 sysdeps/linux-gnu/metag/plt.c
create mode 100644 sysdeps/linux-gnu/metag/ptrace.h
create mode 100644 sysdeps/linux-gnu/metag/regs.c
create mode 100644 sysdeps/linux-gnu/metag/signalent.h
create mode 100644 sysdeps/linux-gnu/metag/syscallent.h
create mode 100644 sysdeps/linux-gnu/metag/trace.c
diff --git a/README b/README
index 95871d1..42fe42d 100644
--- a/README
+++ b/README
@@ -29,6 +29,7 @@ to test each release comprehensively on each target.
i[4567]86-*-linux-gnu
ia64-*-linux-gnu
m68k-*-linux-gnu
+ metag-*-linux-gnu
mips-*-linux-gnu
powerpc-*-linux-gnu
powerpc64-*-linux-gnu
diff --git a/configure.ac b/configure.ac
index 82133ce..16c7a61 100644
--- a/configure.ac
+++ b/configure.ac
@@ -350,6 +350,7 @@ AC_CONFIG_FILES([
sysdeps/linux-gnu/cris/Makefile
sysdeps/linux-gnu/ia64/Makefile
sysdeps/linux-gnu/m68k/Makefile
+ sysdeps/linux-gnu/metag/Makefile
sysdeps/linux-gnu/mips/Makefile
sysdeps/linux-gnu/ppc/Makefile
sysdeps/linux-gnu/s390/Makefile
diff --git a/sysdeps/linux-gnu/metag/Makefile.am b/sysdeps/linux-gnu/metag/Makefile.am
new file mode 100644
index 0000000..a79d2f7
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = \
+ ../libcpu.la
+
+___libcpu_la_SOURCES = \
+ 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/metag/arch.h b/sysdeps/linux-gnu/metag/arch.h
new file mode 100644
index 0000000..2699c62
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/arch.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 1998,2004,2008 Juan Cespedes
+ *
+ * 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
+ */
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_METAG
+
+#define BREAKPOINT_VALUE { 0x01, 0x00, 0x40, 0xAF }
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 0
+#define ARCH_ENDIAN_LITTLE
+#define ARCH_HAVE_SW_SINGLESTEP
diff --git a/sysdeps/linux-gnu/metag/plt.c b/sysdeps/linux-gnu/metag/plt.c
new file mode 100644
index 0000000..2d479a4
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/plt.c
@@ -0,0 +1,38 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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>
+
+#include "debug.h"
+#include "proc.h"
+#include "library.h"
+#include "ltrace-elf.h"
+
+GElf_Addr
+arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+{
+ return lte->plt_addr + ( ndx * 0x14 ) + 0x14;
+}
+
+void
+*sym2addr(struct process *proc, struct library_symbol *sym)
+{
+ return sym->enter_addr;
+}
diff --git a/sysdeps/linux-gnu/metag/ptrace.h b/sysdeps/linux-gnu/metag/ptrace.h
new file mode 100644
index 0000000..7a41e4a
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/ptrace.h
@@ -0,0 +1,21 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/metag/regs.c b/sysdeps/linux-gnu/metag/regs.c
new file mode 100644
index 0000000..f899eb3
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/regs.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/ptrace.h>
+#include <linux/uio.h>
+#include <asm/ptrace.h>
+
+#include "proc.h"
+#include "common.h"
+
+void *
+get_instruction_pointer(struct process *proc)
+{
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ return (void *)-1;
+
+ return (void *)regs.pc; /* PC */
+}
+
+void
+set_instruction_pointer(struct process *proc, void *addr)
+{
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ return;
+
+ regs.pc = (unsigned long)addr;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ ptrace(PTRACE_SETREGSET, proc->pid, NT_PRSTATUS, (long)&iov);
+}
+
+void *
+get_stack_pointer(struct process *proc)
+{
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ return (void *)-1;
+
+ return (void *)regs.ax[0][0]; /* A0StP (A0.0) */
+}
+
+void *
+get_return_addr(struct process *proc, void *stack_pointer)
+{
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ return (void *)-1;
+
+ return (void *)regs.dx[4][1]; /* D1RtP (D1.4) */
+}
diff --git a/sysdeps/linux-gnu/metag/signalent.h b/sysdeps/linux-gnu/metag/signalent.h
new file mode 100644
index 0000000..80228b7
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/signalent.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 */
+ "SIGRTMIN", /* 32 */
diff --git a/sysdeps/linux-gnu/metag/syscallent.h b/sysdeps/linux-gnu/metag/syscallent.h
new file mode 100644
index 0000000..447c550
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/syscallent.h
@@ -0,0 +1,293 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+ "io_setup", /* 0 */
+ "io_destroy", /* 1 */
+ "io_submit", /* 2 */
+ "io_cancel", /* 3 */
+ "io_getevents", /* 4 */
+ "setxattr", /* 5 */
+ "lsetxattr", /* 6 */
+ "fsetxattr", /* 7 */
+ "getxattr", /* 8 */
+ "lgetxattr", /* 9 */
+ "fgetxattr", /* 10 */
+ "listxattr", /* 11 */
+ "llistxattr", /* 12 */
+ "flistxattr", /* 13 */
+ "removexattr", /* 14 */
+ "lremovexattr", /* 15 */
+ "fremovexattr", /* 16 */
+ "getcwd", /* 17 */
+ "lookup_dcookie", /* 18 */
+ "eventfd2", /* 19 */
+ "epoll_create1", /* 20 */
+ "epoll_ctl", /* 21 */
+ "epoll_pwait", /* 22 */
+ "dup", /* 23 */
+ "dup3", /* 24 */
+ "fcntl64", /* 25 */
+ "inotify_init1", /* 26 */
+ "inotify_add_watch", /* 27 */
+ "inotify_rm_watch", /* 28 */
+ "ioctl", /* 29 */
+ "ioprio_set", /* 30 */
+ "ioprio_get", /* 31 */
+ "flock", /* 32 */
+ "mknodat", /* 33 */
+ "mkdirat", /* 34 */
+ "unlinkat", /* 35 */
+ "symlinkat", /* 36 */
+ "linkat", /* 37 */
+ "renameat", /* 38 */
+ "umount", /* 39 */
+ "mount", /* 40 */
+ "pivot_root", /* 41 */
+ "42", /* 42 */
+ "statfs64", /* 43 */
+ "fstatfs64", /* 44 */
+ "truncate64", /* 45 */
+ "ftruncate64", /* 46 */
+ "fallocate", /* 47 */
+ "faccessat", /* 48 */
+ "chdir", /* 49 */
+ "fchdir", /* 50 */
+ "chroot", /* 51 */
+ "fchmod", /* 52 */
+ "fchmodat", /* 53 */
+ "fchownat", /* 54 */
+ "fchown", /* 55 */
+ "openat", /* 56 */
+ "close", /* 57 */
+ "vhangup", /* 58 */
+ "pipe2", /* 59 */
+ "quotactl", /* 60 */
+ "getdents64", /* 61 */
+ "llseek", /* 62 */
+ "read", /* 63 */
+ "write", /* 64 */
+ "readv", /* 65 */
+ "writev", /* 66 */
+ "pread64", /* 67 */
+ "pwrite64", /* 68 */
+ "preadv", /* 69 */
+ "pwritev", /* 70 */
+ "sendfile64", /* 71 */
+ "pselect6", /* 72 */
+ "ppoll", /* 73 */
+ "signalfd4", /* 74 */
+ "vmsplice", /* 75 */
+ "splice", /* 76 */
+ "tee", /* 77 */
+ "readlinkat", /* 78 */
+ "fstatat64", /* 79 */
+ "fstat64", /* 80 */
+ "sync", /* 81 */
+ "fsync", /* 82 */
+ "fdatasync", /* 83 */
+ "sync_file_range", /* 84 */
+ "timerfd_create", /* 85 */
+ "timerfd_settime", /* 86 */
+ "timerfd_gettime", /* 87 */
+ "utimensat", /* 88 */
+ "acct", /* 89 */
+ "capget", /* 90 */
+ "capset", /* 91 */
+ "personality", /* 92 */
+ "exit", /* 93 */
+ "exit_group", /* 94 */
+ "waitid", /* 95 */
+ "set_tid_address", /* 96 */
+ "unshare", /* 97 */
+ "futex", /* 98 */
+ "set_robust_list", /* 99 */
+ "get_robust_list", /* 100 */
+ "nanosleep", /* 101 */
+ "getitimer", /* 102 */
+ "setitimer", /* 103 */
+ "kexec_load", /* 104 */
+ "init_module", /* 105 */
+ "delete_module", /* 106 */
+ "timer_create", /* 107 */
+ "timer_gettime", /* 108 */
+ "timer_getoverrun", /* 109 */
+ "timer_settime", /* 110 */
+ "timer_delete", /* 111 */
+ "clock_settime", /* 112 */
+ "clock_gettime", /* 113 */
+ "clock_getres", /* 114 */
+ "clock_nanosleep", /* 115 */
+ "syslog", /* 116 */
+ "ptrace", /* 117 */
+ "sched_setparam", /* 118 */
+ "sched_setscheduler", /* 119 */
+ "sched_getscheduler", /* 120 */
+ "sched_getparam", /* 121 */
+ "sched_setaffinity", /* 122 */
+ "sched_getaffinity", /* 123 */
+ "sched_yield", /* 124 */
+ "sched_get_priority_max", /* 125 */
+ "sched_get_priority_min", /* 126 */
+ "sched_rr_get_interval", /* 127 */
+ "restart_syscall", /* 128 */
+ "kill", /* 129 */
+ "tkill", /* 130 */
+ "tgkill", /* 131 */
+ "sigaltstack", /* 132 */
+ "rt_sigsuspend", /* 133 */
+ "rt_sigaction", /* 134 */
+ "rt_sigprocmask", /* 135 */
+ "rt_sigpending", /* 136 */
+ "rt_sigtimedwait", /* 137 */
+ "rt_sigqueueinfo", /* 138 */
+ "rt_sigreturn", /* 139 */
+ "setpriority", /* 140 */
+ "getpriority", /* 141 */
+ "reboot", /* 142 */
+ "setregid", /* 143 */
+ "setgid", /* 144 */
+ "setreuid", /* 145 */
+ "setuid", /* 146 */
+ "setresuid", /* 147 */
+ "getresuid", /* 148 */
+ "setresgid", /* 149 */
+ "getresgid", /* 150 */
+ "setfsuid", /* 151 */
+ "setfsgid", /* 152 */
+ "times", /* 153 */
+ "setpgid", /* 154 */
+ "getpgid", /* 155 */
+ "getsid", /* 156 */
+ "setsid", /* 157 */
+ "getgroups", /* 158 */
+ "setgroups", /* 159 */
+ "newuname", /* 160 */
+ "sethostname", /* 161 */
+ "setdomainname", /* 162 */
+ "getrlimit", /* 163 */
+ "setrlimit", /* 164 */
+ "getrusage", /* 165 */
+ "umask", /* 166 */
+ "prctl", /* 167 */
+ "getcpu", /* 168 */
+ "gettimeofday", /* 169 */
+ "settimeofday", /* 170 */
+ "adjtimex", /* 171 */
+ "getpid", /* 172 */
+ "getppid", /* 173 */
+ "getuid", /* 174 */
+ "geteuid", /* 175 */
+ "getgid", /* 176 */
+ "getegid", /* 177 */
+ "gettid", /* 178 */
+ "sysinfo", /* 179 */
+ "mq_open", /* 180 */
+ "mq_unlink", /* 181 */
+ "mq_timedsend", /* 182 */
+ "mq_timedreceive", /* 183 */
+ "mq_notify", /* 184 */
+ "mq_getsetattr", /* 185 */
+ "msgget", /* 186 */
+ "msgctl", /* 187 */
+ "msgrcv", /* 188 */
+ "msgsnd", /* 189 */
+ "semget", /* 190 */
+ "semctl", /* 191 */
+ "semtimedop", /* 192 */
+ "semop", /* 193 */
+ "shmget", /* 194 */
+ "shmctl", /* 195 */
+ "shmat", /* 196 */
+ "shmdt", /* 197 */
+ "socket", /* 198 */
+ "socketpair", /* 199 */
+ "bind", /* 200 */
+ "listen", /* 201 */
+ "accept", /* 202 */
+ "connect", /* 203 */
+ "getsockname", /* 204 */
+ "getpeername", /* 205 */
+ "sendto", /* 206 */
+ "recvfrom", /* 207 */
+ "setsockopt", /* 208 */
+ "getsockopt", /* 209 */
+ "shutdown", /* 210 */
+ "sendmsg", /* 211 */
+ "recvmsg", /* 212 */
+ "readahead", /* 213 */
+ "brk", /* 214 */
+ "munmap", /* 215 */
+ "mremap", /* 216 */
+ "add_key", /* 217 */
+ "request_key", /* 218 */
+ "keyctl", /* 219 */
+ "clone", /* 220 */
+ "execve", /* 221 */
+ "mmap2", /* 222 */
+ "fadvise64_64", /* 223 */
+ "swapon", /* 224 */
+ "swapoff", /* 225 */
+ "mprotect", /* 226 */
+ "msync", /* 227 */
+ "mlock", /* 228 */
+ "munlock", /* 229 */
+ "mlockall", /* 230 */
+ "munlockall", /* 231 */
+ "mincore", /* 232 */
+ "madvise", /* 233 */
+ "remap_file_pages", /* 234 */
+ "mbind", /* 235 */
+ "get_mempolicy", /* 236 */
+ "set_mempolicy", /* 237 */
+ "migrate_pages", /* 238 */
+ "move_pages", /* 239 */
+ "rt_tgsigqueueinfo", /* 240 */
+ "perf_event_open", /* 241 */
+ "accept4", /* 242 */
+ "recvmmsg", /* 243 */
+ "244", /* 244 */
+ "metag_setglobalbit", /* 245 */
+ "metag_set_fpu_flags", /* 246 */
+ "metag_set_tls", /* 247 */
+ "metag_get_tls", /* 248 */
+ "249", /* 249 */
+ "250", /* 250 */
+ "251", /* 251 */
+ "252", /* 252 */
+ "253", /* 253 */
+ "254", /* 254 */
+ "255", /* 255 */
+ "256", /* 256 */
+ "257", /* 257 */
+ "258", /* 258 */
+ "259", /* 259 */
+ "wait4", /* 260 */
+ "prlimit64", /* 261 */
+ "fanotify_init", /* 262 */
+ "fanotify_mark", /* 263 */
+ "name_to_handle_at", /* 264 */
+ "open_by_handle_at", /* 265 */
+ "clock_adjtime", /* 266 */
+ "syncfs", /* 267 */
+ "setns", /* 268 */
+ "sendmmsg", /* 269 */
+ "process_vm_readv", /* 270 */
+ "process_vm_writev", /* 271 */
+ "kcmp", /* 272 */
diff --git a/sysdeps/linux-gnu/metag/trace.c b/sysdeps/linux-gnu/metag/trace.c
new file mode 100644
index 0000000..84757f0
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/trace.c
@@ -0,0 +1,415 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 <linux/uio.h>
+#include <asm/ptrace.h>
+#include <assert.h>
+
+#include "proc.h"
+#include "common.h"
+
+#define METAG_INSN_SIZE 4
+#define N_UNITS 2
+#define REG_SIZE 4
+
+/* unit codes */
+enum metag_unitnum {
+ METAG_UNIT_CT, /* 0x0 */
+ METAG_UNIT_D0,
+ METAG_UNIT_D1,
+ METAG_UNIT_A0,
+ METAG_UNIT_A1, /* 0x4 */
+ METAG_UNIT_PC,
+ METAG_UNIT_RA,
+ METAG_UNIT_TR,
+ METAG_UNIT_TT, /* 0x8 */
+ METAG_UNIT_FX,
+ METAG_UNIT_MAX,
+};
+
+/**
+ \param proc The process that had an event.
+
+ Called by \c next_event() right after the return from wait
+ */
+void
+get_arch_dep(struct process *proc)
+{
+
+}
+
+/**
+ \param proc Process that had event
+ \param status From \c\ waitpid()
+ \param sysnum 0-based syscall number
+ \return 1 if syscall, 2 if sysret, 0 otherwise.
+
+ Called by \c next_event() after the call to get_arch_dep()
+
+ */
+int
+syscall_p(struct process *proc, int status, int *sysnum)
+{
+ if (WIFSTOPPED(status)
+ && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ /* get GP registers */
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS,
+ (long)&iov))
+ return -1;
+
+ /* fetch the SWITCH instruction */
+ unsigned int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc,
+ 0);
+ *sysnum = regs.dx[0][1];
+
+ if (insn != 0xaf440001) {
+ /* check if we're returning from the system call */
+ insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc - 4,
+ 0);
+ if (insn == 0xaf440001)
+ return 2;
+
+ return 0;
+ }
+
+ if (*sysnum >= 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* 2-bit base unit (BU) mapping */
+static enum metag_unitnum metag_bu_map[4] = {
+ METAG_UNIT_A1,
+ METAG_UNIT_D0,
+ METAG_UNIT_D1,
+ METAG_UNIT_A0,
+};
+
+static int
+get_regval_from_unit(enum metag_unitnum unit, unsigned int reg, struct user_gp_regs *regs)
+{
+ /*
+ * Check if reg has a sane value.
+ * We do have N_UNITS, each one having X registers
+ * and each register is REG_SIZE bytes
+ */
+ if ((unit == METAG_UNIT_A0) || (unit == METAG_UNIT_A1)) {
+ if (reg >= ((sizeof(regs->ax)/N_UNITS/REG_SIZE)))
+ goto bad_reg;
+ } else if ((unit == METAG_UNIT_D0) || (unit == METAG_UNIT_D1)) {
+ if (reg >= ((sizeof(regs->dx)/N_UNITS/REG_SIZE)))
+ goto bad_reg;
+ }
+
+ switch(unit)
+ {
+ case METAG_UNIT_A1:
+ return regs->ax[reg][1];
+ case METAG_UNIT_D0:
+ return regs->dx[reg][0];
+ case METAG_UNIT_D1:
+ return regs->dx[reg][1];
+ case METAG_UNIT_A0:
+ return regs->ax[reg][0];
+ /* We really shouldn't be here */
+ default:
+ fprintf(stderr, "unhandled unit=%d\n", unit);
+ }
+ return 0;
+
+bad_reg:
+ fprintf(stderr,"Reading from register %d of unit %d is not implemented\n", reg, unit);
+ return 0;
+
+}
+
+static int
+metag_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
+{
+ uint32_t inst;
+ int nr = 0, imm, reg_val;
+ unsigned int unit = 0, reg;
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
+
+ if (inst == 0xa0fffffe) { /* NOP (Special branch instruction) */
+ newpc[nr++] = pc + 4;
+ } else if ((inst & 0xff000000) == 0xa0000000) {
+ /* Matching 0xA 0x0 for opcode for B #S19 or B<cc> #S19
+ *
+ * Potential Targets:
+ * - pc + #S19 * METAG_INSN_SIZE if R=1 or <CC> true
+ * - pc + 4 */
+ imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
+ newpc[nr++] = pc + imm;
+ newpc[nr++] = pc + 4;
+ } else if ((inst & 0xff000000) == 0xac000000) {
+ /* Matching 0xA 0xC for opcode
+ * JUMP BBx.r,#X16 or CALL BBx.r,#X16
+ *
+ * pc = reg + #x16 (aligned) */
+ imm = (inst >> 3) & 0xffff;
+ reg = (inst >> 19) & 0x1f;
+ unit = metag_bu_map[inst & 0x3];
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ goto ptrace_fail;
+
+ reg_val = get_regval_from_unit(unit, reg, ®s);
+ newpc[nr++] = (reg_val + imm) & -METAG_INSN_SIZE;
+ } else if ((inst & 0xff000000) == 0xab000000) {
+ /* Matching 0xA 0xB for opcode
+ *
+ * CALLR BBx.r,#S19 */
+ imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
+ newpc[nr++] = pc + imm;
+ } else if ((inst & 0xff0001e0) == 0xa30000a0) {
+ /*
+ * Matching 0xA 0x3 for opcode and then
+ * Ud (bit 8-5) = 0x5 = METAG_UNIT_PC
+ *
+ * Potential MOV PC,.. or SWAP<cc> PC,.. or SWAP<cc> ..,PC
+ */
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ goto ptrace_fail;
+
+ /*
+ * Maybe PC is the source register for a SWAP?
+ * bit9 = 1 and bit13-10(Us) == METAG_UNIT_PC
+ */
+ if (((inst >> 9 ) & 0x1) && (((inst >> 10) & 0xf) == METAG_UNIT_PC)) {
+ /* PC will get its value from the destination register */
+ reg = (inst >> 14) & 0x1f;
+ unit = (inst >> 5) & 0xf;
+ } else { /* PC is the destination register. Find the source register */
+ reg = (inst >> 19) & 0x1f;
+ unit = (inst >> 10) & 0xf;
+ }
+
+ switch(unit)
+ {
+ case METAG_UNIT_D0:
+ case METAG_UNIT_D1:
+ case METAG_UNIT_A0:
+ case METAG_UNIT_A1:
+ reg_val = get_regval_from_unit(unit, reg, ®s);
+ break;
+ case METAG_UNIT_PC:
+ reg_val = regs.pc;
+ break;
+ default:
+ goto unhandled;
+ }
+ newpc[nr++] = reg_val;
+ /* In case it is a conditional instruction */
+ newpc[nr++] = pc + 4;
+ } else if ((inst & 0xff00001f) == 0xc600000a){
+ /* Matching 0xC 0x{4,6} for opcode
+ * and UD == 0x5 == METAG_UNIT_PC
+ *
+ * GETD PC, [A0.r + #S6] or
+ * GETD PC, [A0.r + A0.r]*/
+ unit = metag_bu_map[(inst >> 5) & 0x3];
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ reg = (inst >> 14) & 0x1f;
+ imm = (inst << 18) >> 5; /* sign-extend it */
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ goto ptrace_fail;
+ reg_val = get_regval_from_unit(unit, reg, ®s) + imm;
+ /* See where reg_val actually points to */
+ newpc[nr++] = ptrace(PTRACE_PEEKTEXT, proc->pid, reg_val, 0);
+ } else if (((inst & 0xfe0001e0) == 0x840000a0) || /* ADDcc Rx.r, Ax.r, Rx.r */
+ ((inst & 0xfe00003f) == 0x8600002a) || /* ADD Rx.r, Ax.r, #X8 */
+ ((inst & 0xfe0001e0) == 0x8c0000a0) || /* SUBcc Rx.r, Ax.r, Rx.r */
+ ((inst & 0xfe00003f) == 0x8e00002a) || /* SUB Rxr, Ax.r, #X8 */
+ ((inst & 0xf40001e0) == 0x040000a0) || /* ADDcc Rx.r, Dx.r, De.r */
+ ((inst & 0xfe00003f) == 0x0600002a) || /* ADD Rx.r, Dx.r, #X8 */
+ ((inst & 0xf40001e0) == 0x140000a0) || /* SUBcc Rx.r, Dx.r, De.r */
+ ((inst & 0xf600003f) == 0x1600002a)) { /* SUB Rx.r, Dx.r, #X8 */
+
+ /* bits4-1(Ud) == METAG_UNIT_PC */
+
+ int src1, src2, pc_src1 = 0, pc_src2 = 0, is_aunit = 0, umask = 0, optype = 0;
+ /* Look for O2R bit */
+ if ((((inst >> 24) & 0x6) == 0x4) && (inst & 0x1))
+ goto unhandled;
+
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ goto ptrace_fail;
+
+ /* Figure out unit for source registers based on the opcode */
+ switch((inst >> 28) & 0xf)
+ {
+ case 0: /* ADD<cc> Rx.r, Dx.r, De.r|#X8 */
+ case 1: /* SUB<cc> Rx.r, Dx.r, De.r|#X8 */
+ unit = METAG_UNIT_D0 + ((inst >> 24) & 0x1);
+ is_aunit = 0;
+ umask = 0x1f;
+ optype = (inst >> 28) & 0x1;
+ break;
+ case 8:
+ unit = METAG_UNIT_A0 + ((inst >> 24) & 0x1);
+ is_aunit = 1;
+ umask = 0xf;
+ optype = (inst >> 27) & 0x1;
+ break;
+ }
+
+ /* Get pc bits (if any) */
+ if (is_aunit) {
+ pc_src1 = (inst >> 18) & 0x1;
+ pc_src2 = (inst >> 13) & 0x1;
+ }
+
+ /* Determine ADD|SUB format. Immediate or register ? */
+ if ((inst >> 25) & 0x1) { /* ADD|SUB cc PC, X, #imm8 */
+ src2 = (inst >> 6) & 0xff; /* so we can share code */
+ reg = (inst >> 14) & umask;
+ if (pc_src1) /* This can only be true for Address Unit operations */
+ src1 = regs.pc;
+ else /* This covers both Address and Data Unit operations */
+ src1 = get_regval_from_unit(unit, reg, ®s);
+ } else { /* ADD|SUB cc PC, X, X */
+ if (pc_src1)
+ src1 = regs.pc;
+ else
+ src1 = get_regval_from_unit(unit, (inst >> 14) & umask, ®s);
+ if (pc_src2)
+ src2 = regs.pc;
+ else
+ src2 = get_regval_from_unit(unit, (inst >> 9) & umask, ®s);
+ }
+
+ /* Construct the new PC */
+ if (optype)
+ /* SUB */
+ newpc[nr++] = src1 - src2;
+ else /* ADD */
+ newpc[nr++] = src1 + src2;
+ /* Conditional instruction so PC may not change */
+ newpc[nr++] = pc + 4;
+ } else {
+ newpc[nr++] = pc + 4;
+ }
+
+ if (nr <= 0 || nr > 2)
+ goto fail;
+ if (nr == 2) {
+ if (newpc[1] == 0)
+ goto fail;
+ }
+ return nr;
+
+ptrace_fail:
+ fprintf(stderr, "Failed to read the registers pid=%d @ pc=0x%08x\n", proc->pid, pc);
+ return 0;
+unhandled:
+ fprintf(stderr, "Unhandled instruction: pc=0x%08x, inst=0x%08x\n", pc, inst);
+ return 0;
+fail:
+ fprintf(stderr, "nr=%d pc=0x%08x\n", nr, pc);
+ fprintf(stderr, "newpc=0x%08x 0x%08x\n", newpc[0], newpc[1]);
+ return 0;
+
+}
+
+enum sw_singlestep_status
+arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
+ int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
+ struct sw_singlestep_data *add_cb_data)
+{
+ uint32_t pc = (uint32_t) get_instruction_pointer(proc);
+ uint32_t newpcs[2];
+ int nr;
+
+ nr = metag_next_pcs(proc, pc, newpcs);
+
+ while (nr-- > 0) {
+ arch_addr_t baddr = (arch_addr_t) newpcs[nr];
+ if (dict_find(proc->leader->breakpoints, &baddr) != NULL) {
+ fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
+ continue;
+ }
+
+ if (add_cb(baddr, add_cb_data) < 0)
+ return SWS_FAIL;
+ }
+
+ ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
+ return SWS_OK;
+}
+
+long
+gimme_arg(enum tof type, struct process *proc, int arg_num,
+ struct arg_type_info *info)
+{
+ long ret;
+ struct user_gp_regs regs;
+ struct iovec iov;
+
+ /* get GP registers */
+ iov.iov_base = ®s;
+ iov.iov_len = sizeof(regs);
+ if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+ return 0;
+
+ debug(2, "type %d arg %d arg",type, arg_num);
+ if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) {
+ if (arg_num < 6) {
+ /* Args go backwards starting from D1Ar1 (D1.3) */
+ ret = ((unsigned long *)®s.dx[3][1])[-arg_num];
+ debug(2,"ret = %#lx",ret);
+ return ret;
+ } else {
+ return 0;
+ }
+ }
+ if (arg_num >= 0) {
+ fprintf(stderr,"args on return?");
+ }
+ if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR) {
+ return regs.dx[0][0]; /* D0Re0 (D0.0) */
+ }
+
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+
+ return 0;
+}
--
1.7.1
More information about the Ltrace-devel
mailing list