From: Markos Chandras <[email protected]>

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 <[email protected]>
---
 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      | 428 +++++++++++++++++++++++++++++++++++
 10 files changed, 968 insertions(+)
 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..414bdfb 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-uclibc
        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..d4a6f2f
--- /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"
+
+arch_addr_t
+get_instruction_pointer(struct process *proc)
+{
+       struct user_gp_regs regs;
+       struct iovec iov;
+
+       iov.iov_base = &regs;
+       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, arch_addr_t addr)
+{
+       struct user_gp_regs regs;
+       struct iovec iov;
+
+       iov.iov_base = &regs;
+       iov.iov_len = sizeof(regs);
+       if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
+               return;
+
+       regs.pc = (unsigned long)addr;
+
+       iov.iov_base = &regs;
+       iov.iov_len = sizeof(regs);
+       ptrace(PTRACE_SETREGSET, proc->pid, NT_PRSTATUS, (long)&iov);
+}
+
+arch_addr_t
+get_stack_pointer(struct process *proc)
+{
+       struct user_gp_regs regs;
+       struct iovec iov;
+
+       iov.iov_base = &regs;
+       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) */
+}
+
+arch_addr_t
+get_return_addr(struct process *proc, void *stack_pointer)
+{
+       struct user_gp_regs regs;
+       struct iovec iov;
+
+       iov.iov_base = &regs;
+       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..ad5fffe
--- /dev/null
+++ b/sysdeps/linux-gnu/metag/trace.c
@@ -0,0 +1,428 @@
+/*
+ * 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 = &regs;
+               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:
+               assert(unit != unit);
+               abort();
+       }
+       return 0;
+
+bad_reg:
+       fprintf(stderr,
+               "Reading from register %d of unit %d is not implemented.",
+               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 = &regs;
+               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, &regs);
+               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 = &regs;
+               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, &regs);
+                       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 = &regs;
+               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, &regs) + imm;
+               /* See where reg_val actually points to.  */
+               newpc[nr++] = ptrace(PTRACE_PEEKTEXT, proc->pid, reg_val, 0);
+       } else if (((inst & 0xfe0001e0) == 0x840000a0) || /* ADDcc R, A, R */
+                  ((inst & 0xfe00003f) == 0x8600002a) || /* ADD R, A, #X8 */
+                  ((inst & 0xfe0001e0) == 0x8c0000a0) || /* SUBcc R, A, R */
+                  ((inst & 0xfe00003f) == 0x8e00002a) || /* SUB R, A, #X8 */
+                  ((inst & 0xf40001e0) == 0x040000a0) || /* ADDcc R, D, D */
+                  ((inst & 0xfe00003f) == 0x0600002a) || /* ADD R, D, #X8 */
+                  ((inst & 0xf40001e0) == 0x140000a0) || /* SUBcc R, D, D */
+                  ((inst & 0xf600003f) == 0x1600002a)) { /* SUB R, D, #X8 */
+
+               /* bits4-1(Ud) == METAG_UNIT_PC */
+
+               int src1, src2, pc_src1 = 0, pc_src2 = 0, is_aunit = 0;
+               int umask = 0, optype = 0;
+
+               /* Look for O2R bit */
+               if ((((inst >> 24) & 0x6) == 0x4) && (inst & 0x1))
+                       goto unhandled;
+
+               iov.iov_base = &regs;
+               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 AU ops.  */
+                               src1 = regs.pc;
+                       else            /* This covers both AU an DU ops.  */
+                               src1 = get_regval_from_unit(unit, reg, &regs);
+               } else { /* ADD|SUB cc PC, X, X */
+                       if (pc_src1)
+                               src1 = regs.pc;
+                       else
+                               src1 = get_regval_from_unit(unit, (inst >> 14)
+                                                           & umask, &regs);
+                       if (pc_src2)
+                               src2 = regs.pc;
+                       else
+                               src2 = get_regval_from_unit(unit, (inst >> 9)
+                                                           & umask, &regs);
+               }
+
+               /* 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 && 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)
+{
+       arch_addr_t pc = get_instruction_pointer(proc);
+       uint32_t newpcs[2];
+       int nr;
+
+       nr = metag_next_pcs(proc, (uint32_t)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 = &regs;
+       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 *)&regs.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.8.1.5



_______________________________________________
Ltrace-devel mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/ltrace-devel

Reply via email to