[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, &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 = ®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, &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 = ®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, &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 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, &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) {
+		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 *)&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.7.1





More information about the Ltrace-devel mailing list