Common changes:
* New macro ARCH_HAVE_GET_ABI to check ABI-specific flags

mips-specific changes:
* ARCH_HAVE_GET_ABI backend for mips
* Correct read/write sizes for memory access
* Check mips64 instruction encodings when scanning stubs / atomic-ops
* Check signal and syscall numbers for mips64
* ARCH_TYPE_SIZEOF/ALIGNOF backends for tracing 32-bit process from 64-bit
* Explicit type-casts as necessary for building
* Modify mksyscallent_mips to regenerate both o32 and n64 syscall numbers
---
 backend.h                            |    8 +
 ltrace-elf.c                         |   12 ++
 proc.h                               |    1 +
 sysdeps/linux-gnu/mips/Makefile.am   |    1 +
 sysdeps/linux-gnu/mips/abi.c         |   64 +++++++
 sysdeps/linux-gnu/mips/arch.h        |   24 ++-
 sysdeps/linux-gnu/mips/plt.c         |   68 +++++--
 sysdeps/linux-gnu/mips/signalent1.h  |   52 ++++++
 sysdeps/linux-gnu/mips/syscallent1.h |  328 ++++++++++++++++++++++++++++++++++
 sysdeps/linux-gnu/mips/trace.c       |  241 +++++++++++++++++++------
 sysdeps/linux-gnu/mksyscallent_mips  |    9 +-
 11 files changed, 728 insertions(+), 80 deletions(-)
 create mode 100644 sysdeps/linux-gnu/mips/abi.c
 create mode 100644 sysdeps/linux-gnu/mips/signalent1.h
 create mode 100644 sysdeps/linux-gnu/mips/syscallent1.h

diff --git a/backend.h b/backend.h
index e25daa0..5c37179 100644
--- a/backend.h
+++ b/backend.h
@@ -314,6 +314,14 @@ int arch_process_exec(struct process *proc);
 int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t 
sym_index,
                      GElf_Rela *rela, GElf_Sym *sym);
 
+/* The following callback has to be implemented in backend if arch.h
+ * defines ARCH_HAVE_GET_ABI
+ *
+ * This is called from read_module just once, when reading the main module.
+ * The value returned is an architecture specific ID for the current ABI
+ * to be used later for ABI-specific operations. */
+ char arch_get_abi(GElf_Ehdr ehdr);
+
 enum plt_status {
        PLT_FAIL,
        PLT_OK,
diff --git a/ltrace-elf.c b/ltrace-elf.c
index f439cb0..a85edca 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -1131,6 +1131,14 @@ populate_symtab(struct process *proc, const char 
*filename,
                                    only_exported_names);
 }
 
+#ifndef ARCH_HAVE_GET_ABI
+char
+arch_get_abi(GElf_Ehdr ehdr)
+{
+       return 0;
+}
+#endif
+
 static int
 read_module(struct library *lib, struct process *proc,
            const char *filename, GElf_Addr bias, int main)
@@ -1151,6 +1159,10 @@ read_module(struct library *lib, struct process *proc,
         * with 32-bit ltrace.  It is desirable to preserve this.  */
        proc->e_machine = lte.ehdr.e_machine;
        proc->e_class = lte.ehdr.e_ident[EI_CLASS];
+       /* Another candidate for the ABI module. We probably
+        * want to do all of the e_* stuff only once, for main */
+       if (main)
+               proc->e_abi = arch_get_abi(lte.ehdr);
        get_arch_dep(proc);
 
        /* Find out the base address.  For PIE main binaries we look
diff --git a/proc.h b/proc.h
index a611456..00094e1 100644
--- a/proc.h
+++ b/proc.h
@@ -117,6 +117,7 @@ struct process {
         * nauseam.  */
        short e_machine;
        char e_class;
+       char e_abi;
 
 #if defined(HAVE_LIBDW)
        /* Unwind info for leader, NULL for non-leader procs. */
diff --git a/sysdeps/linux-gnu/mips/Makefile.am 
b/sysdeps/linux-gnu/mips/Makefile.am
index 1fd8c2a..571ee0d 100644
--- a/sysdeps/linux-gnu/mips/Makefile.am
+++ b/sysdeps/linux-gnu/mips/Makefile.am
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = \
        ../libcpu.la
 
 ___libcpu_la_SOURCES = \
+       abi.c \
        plt.c \
        regs.c \
        trace.c
diff --git a/sysdeps/linux-gnu/mips/abi.c b/sysdeps/linux-gnu/mips/abi.c
new file mode 100644
index 0000000..64e3c10
--- /dev/null
+++ b/sysdeps/linux-gnu/mips/abi.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <gelf.h>
+#include "arch.h"
+
+/*
+ *  There is no bit in the header-flags to mark N64 ABI, it must be
+ *  determined by exclusion of other ABIs. The following values are
+ *  from elfcpp/mips.h in binutils sources
+ */
+enum
+{
+       E_MIPS_ABI_MASK = 0x0000F000,
+       E_MIPS_ABI_N32  = 0x00000020,
+       E_MIPS_ABI_O32  = 0x00001000,
+       E_MIPS_ABI_O64  = 0x00002000,
+       E_MIPS_ABI_EABI32 = 0x00003000,
+       E_MIPS_ABI_EABI64 = 0x00004000,
+};
+
+char
+arch_get_abi(GElf_Ehdr ehdr)
+{
+       enum mips_abi_type abi;
+       switch (ehdr.e_flags & E_MIPS_ABI_MASK) {
+       case E_MIPS_ABI_O32:
+               abi = ABI_O32; break;
+       case E_MIPS_ABI_O64:
+               abi = ABI_O64; break;
+       case E_MIPS_ABI_EABI32:
+       case E_MIPS_ABI_EABI64:
+               fprintf(stderr, "%s: MIPS EABI is not supported\n", __func__);
+               abi = -1;
+               break;
+       default:
+               if (ehdr.e_flags & E_MIPS_ABI_N32)
+                       abi = ABI_N32;
+               else
+                       abi = ABI_N64;
+       }
+
+       return abi;
+}
+
+/**@}*/
diff --git a/sysdeps/linux-gnu/mips/arch.h b/sysdeps/linux-gnu/mips/arch.h
index 16273d2..8b75df2 100644
--- a/sysdeps/linux-gnu/mips/arch.h
+++ b/sysdeps/linux-gnu/mips/arch.h
@@ -1,5 +1,6 @@
 /*
  * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
  * Copyright (C) 2013,2014 Petr Machata, Red Hat Inc.
  * Copyright (C) 2006 Eric Vaitl
  *
@@ -38,8 +39,12 @@
 #define BREAKPOINT_LENGTH 4
 #define DECR_PC_AFTER_BREAK 0
 
-#define LT_ELFCLASS    ELFCLASS32
+#ifdef __LP64__
+#define LT_ELFCLASS    ELFCLASS64
 #define LT_ELF_MACHINE EM_MIPS
+#endif /* __LP64__ */
+#define LT_ELFCLASS2   ELFCLASS32
+#define LT_ELF_MACHINE2 EM_MIPS
 
 #define ARCH_HAVE_LTELF_DATA
 struct arch_ltelf_data {
@@ -53,8 +58,14 @@ struct arch_ltelf_data {
 #define ARCH_HAVE_ADD_PLT_ENTRY
 #define ARCH_HAVE_SW_SINGLESTEP
 #define ARCH_HAVE_SYMBOL_RET
-
+#define ARCH_HAVE_GET_ABI
 #define ARCH_HAVE_LIBRARY_SYMBOL_DATA
+
+#ifdef __LP64__
+#define ARCH_HAVE_SIZEOF
+#define ARCH_HAVE_ALIGNOF
+#endif /* __LP64__ */
+
 enum mips_plt_type
 {
        /* A symbol has associated PLT entry.  */
@@ -73,7 +84,14 @@ enum mips_plt_type
        MIPS_PLT_NEED_UNRESOLVE,
 };
 
-struct mips_unresolve_data;
+enum mips_abi_type
+{
+       ABI_O32,
+       ABI_N32,
+       ABI_N64,
+       ABI_O64,
+};
+
 struct arch_library_symbol_data {
        enum mips_plt_type type;
        union {
diff --git a/sysdeps/linux-gnu/mips/plt.c b/sysdeps/linux-gnu/mips/plt.c
index c7c10ac..fdca9dc 100644
--- a/sysdeps/linux-gnu/mips/plt.c
+++ b/sysdeps/linux-gnu/mips/plt.c
@@ -1,5 +1,6 @@
 /*
  * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
  * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
  * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
  * Copyright (C) 2008,2009 Juan Cespedes
@@ -182,6 +183,11 @@ arch_find_dl_debug(struct process *proc, arch_addr_t 
dyn_addr,
 {
        arch_addr_t rld_addr;
        int r;
+#ifdef __LP64__
+       size_t addrsize = proc->mask_32bit ? 4 : (sizeof *ret);
+#else /* !__LP64__ */
+       size_t addrsize = sizeof *ret;
+#endif /* !__LP64__ */
 
        /* MIPS puts the address of the r_debug structure into the
         * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry.  */
@@ -189,7 +195,7 @@ arch_find_dl_debug(struct process *proc, arch_addr_t 
dyn_addr,
                                         DT_MIPS_RLD_MAP, &rld_addr);
        if (r == 0) {
                if (umovebytes(proc, rld_addr,
-                              ret, sizeof *ret) != sizeof *ret) {
+                              ret, addrsize) != addrsize) {
                        r = -1;
                }
        }
@@ -295,14 +301,25 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
 
        for (j = 0; j < data->d_size / 16; ++j) {
                uint32_t insn;
+               int got_size = 4;
+               uint32_t load_inst = 0x24180000U; /* addui t8,0,xx  */
+
+#ifdef __LP64__
+               if (arch_get_abi(lte->ehdr) == ABI_N64
+                   || arch_get_abi(lte->ehdr) == ABI_O64) {
+                       got_size = 8;
+                       load_inst = 0x64180000U; /* daddui t8,0,xx  */
+               }
+#endif /* __LP64__ */
+
                if (elf_read_u32(data, j * 16 + 12, &insn) < 0)
                        goto fail_stubs;
 
                if (insn == 0)
                        continue;
 
-               /* 0x2418XXXX encodes lbu 0,t8,XXXX or li t8,XXXX.  */
-               if ((insn & 0xffff0000U) != 0x24180000U)
+               /* 0x[62]418XXXX encodes [d]addiu t8, 0, XXXX.  */
+               if ((insn & 0xffff0000U) != load_inst)
                        goto fail_stubs;
 
                unsigned idx = insn & 0xffff;
@@ -323,8 +340,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
                        + lte->arch.mips_local_gotno;
                /* XXX Double cast.  */
                arch_addr_t got_entry_addr
-                       = (arch_addr_t) (uintptr_t) lte->arch.pltgot_addr
-                       + got_idx * 4;
+                       = (arch_addr_t) (uintptr_t) (lte->arch.pltgot_addr
+                                                    + got_idx * got_size);
 
                GElf_Rela rela = {
                        /* XXX double cast.  */
@@ -336,7 +353,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
                if (VECT_PUSHBACK(&lte->plt_relocs, &rela) < 0)
                        goto fail_stubs;
 
-               fprintf(stderr,
+               debug(2,
                        "added stub entry for symbol %u at %#lx, GOT @%p\n",
                        idx, (unsigned long) rela.r_addend, got_entry_addr);
        }
@@ -362,8 +379,17 @@ read_got_entry(struct process *proc, GElf_Addr addr, 
GElf_Addr *valp)
 {
        /* XXX double cast.  */
        arch_addr_t a = (arch_addr_t) (uintptr_t) addr;
-       uint32_t l;
-       if (proc_read_32(proc, a, &l) < 0) {
+       uint64_t l = 0;
+       int result;
+
+#ifdef __LP64__
+       if (!proc->mask_32bit)
+               result = proc_read_64(proc, a, &l);
+       else
+#endif /* __LP64__ */
+               result = proc_read_32(proc, a, (uint32_t *) &l);
+
+       if (result < 0) {
                fprintf(stderr, "ptrace read got entry @%#" PRIx64 ": %s\n",
                        addr, strerror(errno));
                return -1;
@@ -426,13 +452,13 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf 
*lte,
        GElf_Addr stub_addr = rela->r_addend + lte->bias;
 
        debug(2, "PLT-less arch_elf_add_plt_entry %s = %#llx\n",
-             a_name, stub_addr);
+             a_name, (unsigned long long) stub_addr);
 
        struct library_symbol *libsym = NULL;
        if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx,
                                      &libsym) < 0) {
-               fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__,
-                       a_name, stub_addr, strerror(errno));
+               fprintf(stderr, "%s: failed %s(%#lx): %s\n", __func__,
+                       a_name, (unsigned long) stub_addr, strerror(errno));
                goto fail;
        }
 
@@ -503,13 +529,27 @@ jump_to_entry_point(struct process *proc, struct 
breakpoint *bp)
 static int
 unresolve_got_entry(struct process *proc, GElf_Addr addr, GElf_Addr value)
 {
-       uint32_t v32 = (uint32_t) value;
-       uint32_t a32 = (uint32_t) addr;
-       if (ptrace(PTRACE_POKETEXT, proc->pid, a32, v32) < 0) {
+       arch_addr_t a = (arch_addr_t) (uintptr_t) addr;
+#ifdef __LP64__
+       /* To write 32-bit value in 64-bit mode, we must read-modify-write
+          the 64-bit value with only the lower 32 bits modified.  */
+       if (proc->mask_32bit) {
+               GElf_Addr orig = ptrace(PTRACE_PEEKTEXT, proc->pid, a, 0);
+               char *obytes = (char *) &orig;
+               char *nbytes = (char *) &value;
+               unsigned i;
+
+               for (i = 0; i < 4; i++)
+                       obytes[i] = nbytes[i];
+               value = orig;
+       }
+#endif /* __LP64__ */
+       if (ptrace(PTRACE_POKETEXT, proc->pid, a, (unsigned long) value) < 0) {
                fprintf(stderr, "failed to unresolve GOT entry: %s\n",
                        strerror(errno));
                return -1;
        }
+
        return 0;
 }
 
diff --git a/sysdeps/linux-gnu/mips/signalent1.h 
b/sysdeps/linux-gnu/mips/signalent1.h
new file mode 100644
index 0000000..9e9d1f7
--- /dev/null
+++ b/sysdeps/linux-gnu/mips/signalent1.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+       "SIG_0",           /* 0 */
+       "SIGHUP",          /* 1 */
+       "SIGINT",          /* 2 */
+       "SIGQUIT",         /* 3 */
+       "SIGILL",          /* 4 */
+       "SIGTRAP",         /* 5 */
+       "SIGIOT",          /* 6 */
+       "SIGEMT",          /* 7 */
+       "SIGFPE",          /* 8 */
+       "SIGKILL",         /* 9 */
+       "SIGBUS",          /* 10 */
+       "SIGSEGV",         /* 11 */
+       "SIGSYS",          /* 12 */
+       "SIGPIPE",         /* 13 */
+       "SIGALRM",         /* 14 */
+       "SIGTERM",         /* 15 */
+       "SIGUSR1",         /* 16 */
+       "SIGUSR2",         /* 17 */
+       "SIGCHLD",         /* 18 */
+       "SIGPWR",          /* 19 */
+       "SIGWINCH",        /* 20 */
+       "SIGURG",          /* 21 */
+       "SIGIO",           /* 22 */
+       "SIGSTOP",         /* 23 */
+       "SIGTSTP",         /* 24 */
+       "SIGCONT",         /* 25 */
+       "SIGTTIN",         /* 26 */
+       "SIGTTOU",         /* 27 */
+       "SIGVTALRM",       /* 28 */
+       "SIGPROF",         /* 29 */
+       "SIGXCPU",         /* 30 */
+       "SIGXFSZ",         /* 31 */
diff --git a/sysdeps/linux-gnu/mips/syscallent1.h 
b/sysdeps/linux-gnu/mips/syscallent1.h
new file mode 100644
index 0000000..dfa4954
--- /dev/null
+++ b/sysdeps/linux-gnu/mips/syscallent1.h
@@ -0,0 +1,328 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
+ *
+ * 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
+ */
+
+/* MIPS64 */
+
+       "read",                            /* 0 */
+       "write",                           /* 1 */
+       "open",                            /* 2 */
+       "close",                           /* 3 */
+       "stat",                            /* 4 */
+       "fstat",                           /* 5 */
+       "lstat",                           /* 6 */
+       "poll",                            /* 7 */
+       "lseek",                           /* 8 */
+       "mmap",                            /* 9 */
+       "mprotect",                        /* 10 */
+       "munmap",                          /* 11 */
+       "brk",                             /* 12 */
+       "rt_sigaction",                    /* 13 */
+       "rt_sigprocmask",                  /* 14 */
+       "ioctl",                           /* 15 */
+       "pread64",                         /* 16 */
+       "pwrite64",                        /* 17 */
+       "readv",                           /* 18 */
+       "writev",                          /* 19 */
+       "access",                          /* 20 */
+       "pipe",                            /* 21 */
+       "_newselect",                      /* 22 */
+       "sched_yield",                     /* 23 */
+       "mremap",                          /* 24 */
+       "msync",                           /* 25 */
+       "mincore",                         /* 26 */
+       "madvise",                         /* 27 */
+       "shmget",                          /* 28 */
+       "shmat",                           /* 29 */
+       "shmctl",                          /* 30 */
+       "dup",                             /* 31 */
+       "dup2",                            /* 32 */
+       "pause",                           /* 33 */
+       "nanosleep",                       /* 34 */
+       "getitimer",                       /* 35 */
+       "setitimer",                       /* 36 */
+       "alarm",                           /* 37 */
+       "getpid",                          /* 38 */
+       "sendfile",                        /* 39 */
+       "socket",                          /* 40 */
+       "connect",                         /* 41 */
+       "accept",                          /* 42 */
+       "sendto",                          /* 43 */
+       "recvfrom",                        /* 44 */
+       "sendmsg",                         /* 45 */
+       "recvmsg",                         /* 46 */
+       "shutdown",                        /* 47 */
+       "bind",                            /* 48 */
+       "listen",                          /* 49 */
+       "getsockname",                     /* 50 */
+       "getpeername",                     /* 51 */
+       "socketpair",                      /* 52 */
+       "setsockopt",                      /* 53 */
+       "getsockopt",                      /* 54 */
+       "clone",                           /* 55 */
+       "fork",                            /* 56 */
+       "execve",                          /* 57 */
+       "exit",                            /* 58 */
+       "wait4",                           /* 59 */
+       "kill",                            /* 60 */
+       "uname",                           /* 61 */
+       "semget",                          /* 62 */
+       "semop",                           /* 63 */
+       "semctl",                          /* 64 */
+       "shmdt",                           /* 65 */
+       "msgget",                          /* 66 */
+       "msgsnd",                          /* 67 */
+       "msgrcv",                          /* 68 */
+       "msgctl",                          /* 69 */
+       "fcntl",                           /* 70 */
+       "flock",                           /* 71 */
+       "fsync",                           /* 72 */
+       "fdatasync",                       /* 73 */
+       "truncate",                        /* 74 */
+       "ftruncate",                       /* 75 */
+       "getdents",                        /* 76 */
+       "getcwd",                          /* 77 */
+       "chdir",                           /* 78 */
+       "fchdir",                          /* 79 */
+       "rename",                          /* 80 */
+       "mkdir",                           /* 81 */
+       "rmdir",                           /* 82 */
+       "creat",                           /* 83 */
+       "link",                            /* 84 */
+       "unlink",                          /* 85 */
+       "symlink",                         /* 86 */
+       "readlink",                        /* 87 */
+       "chmod",                           /* 88 */
+       "fchmod",                          /* 89 */
+       "chown",                           /* 90 */
+       "fchown",                          /* 91 */
+       "lchown",                          /* 92 */
+       "umask",                           /* 93 */
+       "gettimeofday",                    /* 94 */
+       "getrlimit",                       /* 95 */
+       "getrusage",                       /* 96 */
+       "sysinfo",                         /* 97 */
+       "times",                           /* 98 */
+       "ptrace",                          /* 99 */
+       "getuid",                          /* 100 */
+       "syslog",                          /* 101 */
+       "getgid",                          /* 102 */
+       "setuid",                          /* 103 */
+       "setgid",                          /* 104 */
+       "geteuid",                         /* 105 */
+       "getegid",                         /* 106 */
+       "setpgid",                         /* 107 */
+       "getppid",                         /* 108 */
+       "getpgrp",                         /* 109 */
+       "setsid",                          /* 110 */
+       "setreuid",                        /* 111 */
+       "setregid",                        /* 112 */
+       "getgroups",                       /* 113 */
+       "setgroups",                       /* 114 */
+       "setresuid",                       /* 115 */
+       "getresuid",                       /* 116 */
+       "setresgid",                       /* 117 */
+       "getresgid",                       /* 118 */
+       "getpgid",                         /* 119 */
+       "setfsuid",                        /* 120 */
+       "setfsgid",                        /* 121 */
+       "getsid",                          /* 122 */
+       "capget",                          /* 123 */
+       "capset",                          /* 124 */
+       "rt_sigpending",                   /* 125 */
+       "rt_sigtimedwait",                 /* 126 */
+       "rt_sigqueueinfo",                 /* 127 */
+       "rt_sigsuspend",                   /* 128 */
+       "sigaltstack",                     /* 129 */
+       "utime",                           /* 130 */
+       "mknod",                           /* 131 */
+       "personality",                     /* 132 */
+       "ustat",                           /* 133 */
+       "statfs",                          /* 134 */
+       "fstatfs",                         /* 135 */
+       "sysfs",                           /* 136 */
+       "getpriority",                     /* 137 */
+       "setpriority",                     /* 138 */
+       "sched_setparam",                  /* 139 */
+       "sched_getparam",                  /* 140 */
+       "sched_setscheduler",              /* 141 */
+       "sched_getscheduler",              /* 142 */
+       "sched_get_priority_max",          /* 143 */
+       "sched_get_priority_min",          /* 144 */
+       "sched_rr_get_interval",           /* 145 */
+       "mlock",                           /* 146 */
+       "munlock",                         /* 147 */
+       "mlockall",                        /* 148 */
+       "munlockall",                      /* 149 */
+       "vhangup",                         /* 150 */
+       "pivot_root",                      /* 151 */
+       "_sysctl",                         /* 152 */
+       "prctl",                           /* 153 */
+       "adjtimex",                        /* 154 */
+       "setrlimit",                       /* 155 */
+       "chroot",                          /* 156 */
+       "sync",                            /* 157 */
+       "acct",                            /* 158 */
+       "settimeofday",                    /* 159 */
+       "mount",                           /* 160 */
+       "umount2",                         /* 161 */
+       "swapon",                          /* 162 */
+       "swapoff",                         /* 163 */
+       "reboot",                          /* 164 */
+       "sethostname",                     /* 165 */
+       "setdomainname",                   /* 166 */
+       "create_module",                   /* 167 */
+       "init_module",                     /* 168 */
+       "delete_module",                   /* 169 */
+       "get_kernel_syms",                 /* 170 */
+       "query_module",                    /* 171 */
+       "quotactl",                        /* 172 */
+       "nfsservctl",                      /* 173 */
+       "getpmsg",                         /* 174 */
+       "putpmsg",                         /* 175 */
+       "afs_syscall",                     /* 176 */
+       "reserved177",                     /* 177 */
+       "gettid",                          /* 178 */
+       "readahead",                       /* 179 */
+       "setxattr",                        /* 180 */
+       "lsetxattr",                       /* 181 */
+       "fsetxattr",                       /* 182 */
+       "getxattr",                        /* 183 */
+       "lgetxattr",                       /* 184 */
+       "fgetxattr",                       /* 185 */
+       "listxattr",                       /* 186 */
+       "llistxattr",                      /* 187 */
+       "flistxattr",                      /* 188 */
+       "removexattr",                     /* 189 */
+       "lremovexattr",                    /* 190 */
+       "fremovexattr",                    /* 191 */
+       "tkill",                           /* 192 */
+       "reserved193",                     /* 193 */
+       "futex",                           /* 194 */
+       "sched_setaffinity",               /* 195 */
+       "sched_getaffinity",               /* 196 */
+       "cacheflush",                      /* 197 */
+       "cachectl",                        /* 198 */
+       "sysmips",                         /* 199 */
+       "io_setup",                        /* 200 */
+       "io_destroy",                      /* 201 */
+       "io_getevents",                    /* 202 */
+       "io_submit",                       /* 203 */
+       "io_cancel",                       /* 204 */
+       "exit_group",                      /* 205 */
+       "lookup_dcookie",                  /* 206 */
+       "epoll_create",                    /* 207 */
+       "epoll_ctl",                       /* 208 */
+       "epoll_wait",                      /* 209 */
+       "remap_file_pages",                /* 210 */
+       "rt_sigreturn",                    /* 211 */
+       "set_tid_address",                 /* 212 */
+       "restart_syscall",                 /* 213 */
+       "semtimedop",                      /* 214 */
+       "fadvise64",                       /* 215 */
+       "timer_create",                    /* 216 */
+       "timer_settime",                   /* 217 */
+       "timer_gettime",                   /* 218 */
+       "timer_getoverrun",                /* 219 */
+       "timer_delete",                    /* 220 */
+       "clock_settime",                   /* 221 */
+       "clock_gettime",                   /* 222 */
+       "clock_getres",                    /* 223 */
+       "clock_nanosleep",                 /* 224 */
+       "tgkill",                          /* 225 */
+       "utimes",                          /* 226 */
+       "mbind",                           /* 227 */
+       "get_mempolicy",                   /* 228 */
+       "set_mempolicy",                   /* 229 */
+       "mq_open",                         /* 230 */
+       "mq_unlink",                       /* 231 */
+       "mq_timedsend",                    /* 232 */
+       "mq_timedreceive",                 /* 233 */
+       "mq_notify",                       /* 234 */
+       "mq_getsetattr",                   /* 235 */
+       "vserver",                         /* 236 */
+       "waitid",                          /* 237 */
+       "238",                             /* 238 */
+       "add_key",                         /* 239 */
+       "request_key",                     /* 240 */
+       "keyctl",                          /* 241 */
+       "set_thread_area",                 /* 242 */
+       "inotify_init",                    /* 243 */
+       "inotify_add_watch",               /* 244 */
+       "inotify_rm_watch",                /* 245 */
+       "migrate_pages",                   /* 246 */
+       "openat",                          /* 247 */
+       "mkdirat",                         /* 248 */
+       "mknodat",                         /* 249 */
+       "fchownat",                        /* 250 */
+       "futimesat",                       /* 251 */
+       "newfstatat",                      /* 252 */
+       "unlinkat",                        /* 253 */
+       "renameat",                        /* 254 */
+       "linkat",                          /* 255 */
+       "symlinkat",                       /* 256 */
+       "readlinkat",                      /* 257 */
+       "fchmodat",                        /* 258 */
+       "faccessat",                       /* 259 */
+       "pselect6",                        /* 260 */
+       "ppoll",                           /* 261 */
+       "unshare",                         /* 262 */
+       "splice",                          /* 263 */
+       "sync_file_range",                 /* 264 */
+       "tee",                             /* 265 */
+       "vmsplice",                        /* 266 */
+       "move_pages",                      /* 267 */
+       "set_robust_list",                 /* 268 */
+       "get_robust_list",                 /* 269 */
+       "kexec_load",                      /* 270 */
+       "getcpu",                          /* 271 */
+       "epoll_pwait",                     /* 272 */
+       "ioprio_set",                      /* 273 */
+       "ioprio_get",                      /* 274 */
+       "utimensat",                       /* 275 */
+       "signalfd",                        /* 276 */
+       "timerfd",                         /* 277 */
+       "eventfd",                         /* 278 */
+       "fallocate",                       /* 279 */
+       "timerfd_create",                  /* 280 */
+       "timerfd_gettime",                 /* 281 */
+       "timerfd_settime",                 /* 282 */
+       "signalfd4",                       /* 283 */
+       "eventfd2",                        /* 284 */
+       "epoll_create1",                   /* 285 */
+       "dup3",                            /* 286 */
+       "pipe2",                           /* 287 */
+       "inotify_init1",                   /* 288 */
+       "preadv",                          /* 289 */
+       "pwritev",                         /* 290 */
+       "rt_tgsigqueueinfo",               /* 291 */
+       "perf_event_open",                 /* 292 */
+       "accept4",                         /* 293 */
+       "recvmmsg",                        /* 294 */
+       "fanotify_init",                   /* 295 */
+       "fanotify_mark",                   /* 296 */
+       "prlimit64",                       /* 297 */
+       "name_to_handle_at",               /* 298 */
+       "open_by_handle_at",               /* 299 */
+       "clock_adjtime",                   /* 300 */
+       "syncfs",                          /* 301 */
+       "sendmmsg",                        /* 302 */
+       "setns",                           /* 303 */
+       "process_vm_readv",                /* 304 */
+       "process_vm_writev",               /* 305 */
diff --git a/sysdeps/linux-gnu/mips/trace.c b/sysdeps/linux-gnu/mips/trace.c
index e81b374..d54818e 100644
--- a/sysdeps/linux-gnu/mips/trace.c
+++ b/sysdeps/linux-gnu/mips/trace.c
@@ -1,5 +1,6 @@
 /*
  * This file is part of ltrace.
+ * Copyright (C) 2015 Imagination Technologies Limited
  * Copyright (C) 2013 Petr Machata, Red Hat Inc.
  * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
  * Copyright (C) 2010 Arnaud Patard, Mandriva SA
@@ -29,6 +30,7 @@
 #include <signal.h>
 #include <sys/ptrace.h>
 #include <asm/ptrace.h>
+#include <asm/unistd.h>
 #include <assert.h>
 #include <asm/unistd.h>
 
@@ -68,6 +70,44 @@
 void
 get_arch_dep(struct process *proc)
 {
+#ifdef __LP64__
+       proc->mask_32bit = (proc->e_class == ELFCLASS32);
+#endif /* __LP64__ */
+       /* n32 personality is best approximated by n64,
+          at least for syscall numbers */
+       proc->personality = (proc->e_class == ELFCLASS64
+                            || proc->e_abi == ABI_N32);
+}
+
+/**
+   \param abi ABI of current process, from mips_abi_type enum
+   \param list An array of 4 elements, each corresponding to an ABI, in
+   the order: o32, n32, n64, o64
+
+   return value from array corresponding to requested ABI
+ */
+static int
+abi_select(const int abi, const int list[])
+{
+       int retval;
+       switch (abi)
+       {
+       case ABI_N32:
+               retval = list[1];
+               break;
+       case ABI_N64:
+               retval = list[2];
+               break;
+       case ABI_O64:
+               retval = list[3];
+               break;
+       case ABI_O32:
+       default:
+               retval = list[0];
+               break;
+       }
+
+       return retval;
 }
 
 /**
@@ -90,53 +130,94 @@ get_arch_dep(struct process *proc)
 int
 syscall_p(struct process *proc, int status, int *sysnum)
 {
-       if (WIFSTOPPED(status)
-                       && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
-               /* get the user's pc (plus 8) */
-               long pc = (long)get_instruction_pointer(proc);
-               /* fetch the SWI instruction */
-               int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
-               int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0);
-
-               /*
-                  On a mips,  syscall looks like:
-                  24040fa1    li v0, 0x0fa1   # 4001 --> _exit syscall
-                  0000000c    syscall
-                */
-               if(insn!=0x0000000c){
-                       /* sigreturn returns control to the point
-                          where the signal was received; skip check 
-                          for preceeding syscall instruction */
-                       int depth = proc->callstack_depth;
-                       struct callstack_element *top = NULL;
-                       if (depth > 0)
-                               top = &proc->callstack[depth - 1];
-
-                       if (top != NULL &&  top->is_syscall &&
-                           (top->c_un.syscall == (__NR_rt_sigreturn -
-                                                  __NR_Linux) ||
-                            top->c_un.syscall == (__NR_sigreturn -
-                                                  __NR_Linux))) {
-                               *sysnum = top->c_un.syscall;
-                               return 2;
-                       }
-                       else
-                               return 0;
-               }
-
-               *sysnum = (num & 0xFFFF) - 4000;
-               /* if it is a syscall, return 1 or 2 */
-               if (proc->callstack_depth > 0 &&
-                               proc->callstack[proc->callstack_depth - 
1].is_syscall &&
-                               proc->callstack[proc->callstack_depth - 
1].c_un.syscall == *sysnum) {
+       unsigned long pc;
+       int insn, prev;
+       int min_syscall, max_syscall, sigreturn, rt_sigreturn;
+       struct callstack_element *top = NULL;
+       int depth = proc->callstack_depth;
+       const int syscallbase[] = {__NR_O32_Linux, __NR_N32_Linux,
+                                  __NR_64_Linux, __NR_O32_Linux};
+       const int syscallnum[] = {__NR_O32_Linux_syscalls,
+                                 __NR_N32_Linux_syscalls,
+                                 __NR_64_Linux_syscalls,
+                                 __NR_O32_Linux_syscalls};
+       const int rt_sigreturn_list[] = {193, 211, 211, 193};
+       const int sigreturn_list[] = {119, -1, -1, 119};
+
+       if (!WIFSTOPPED(status)
+           || WSTOPSIG(status) != (SIGTRAP | proc->tracesysgood))
+               return 0;
+
+       /* get the user's pc (plus 8) */
+       pc = (unsigned long)get_instruction_pointer(proc);
+       /* fetch the SWI instruction */
+       insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
+       prev = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0);
+
+       if (depth > 0)
+               top = &proc->callstack[depth - 1];
+
+       /* Range of syscall numbers varies with ABI; ref:asm/unistd.h */
+       min_syscall = abi_select(proc->e_abi, syscallbase);
+       max_syscall = min_syscall + abi_select(proc->e_abi, syscallnum);
+       sigreturn = min_syscall + abi_select(proc->e_abi, sigreturn_list);
+       rt_sigreturn = min_syscall + abi_select(proc->e_abi, rt_sigreturn_list);
+
+       /* not a syscall instruction */
+       if(insn!=0x0000000c){
+               /* sigreturn returns control to the point where the signal was
+                  received; skip check for preceeding syscall instruction */
+               if (top != NULL &&  top->is_syscall
+                   && (top->c_un.syscall == (rt_sigreturn - min_syscall)
+                       || top->c_un.syscall == (sigreturn - min_syscall))) {
+                       *sysnum = top->c_un.syscall;
                        return 2;
                }
+               else
+                       return 0;
+       }
 
-               if (*sysnum >= 0) {
-                       return 1;
-               }
+       /*
+         On a mips,  syscall looks like:
+         24020fa1    li v0, 0x0fa1   # 4001 --> _exit syscall
+         0000000c    syscall
+       */
+       if ((prev & 0xFFFF0000) == 0x24020000) {
+               *sysnum = (prev & 0xFFFF) - min_syscall;
        }
-       return 0;
+       /*
+         The above is not necessary in Linux kernel > v2.6.35. Recent
+         kernels have a fancy-pants method of restarting syscalls.
+         We must read v0 instead, to get the syscall number.
+
+         Unfortunately, v0 is not preserved till the point of return.
+         If already in syscall and v0 is invalid, assume this event
+         to be a return without attempting to match previous syscall.
+
+         Caveat: logic fails if v0 incidentally contains a valid
+         syscall number, distinct from the current syscall number,
+         at the point of return from a nested syscall.
+       */
+       else {
+               int v0 = ptrace(PTRACE_PEEKUSER, proc->pid, off_v0, 0);
+
+               if ((v0 >= min_syscall) && (v0 <= max_syscall))
+                       *sysnum = v0 - min_syscall;
+               else if (depth > 0 && top->is_syscall)
+                       *sysnum = top->c_un.syscall;
+               else /* syscall instruction without valid number - ignored */
+                       return 0;
+       }
+
+       /* if it is a syscall, return 1 or 2 */
+       if (depth > 0 && top->is_syscall && top->c_un.syscall == *sysnum) {
+               return 2;
+       }
+
+       if (*sysnum >= 0)
+               return 1;
+       else
+               return 0;
 }
 
 /* Based on GDB code.  */
@@ -162,9 +243,11 @@ mips32_relative_offset (uint32_t inst)
   return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2;
 }
 
-int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
+int mips_next_pcs(struct process *proc, unsigned long pc,
+                 unsigned long *newpc)
 {
-       uint32_t inst, rx;
+       uint32_t inst;
+       unsigned long rx;
        int op;
        int rn;
        int nr = 0;
@@ -277,8 +360,8 @@ int mips_next_pcs(struct process *proc, uint32_t pc, 
uint32_t *newpc)
        return nr;
 
 fail:
-       printf("nr=%d pc=%x\n", nr, pc);
-       printf("pc=%x %x\n", newpc[0], newpc[1]);
+       printf("nr=%d pc=%lx\n", nr, pc);
+       printf("pc=%lx %lx\n", newpc[0], newpc[1]);
        return 0;
 }
 
@@ -304,17 +387,27 @@ fail:
  * branches within the LL-SC sequence.
  */
 #define inrange(x,lo,hi) ((x)<=(hi) && (x)>=(lo))
+/* Instruction encodings for atomic operations */
+#ifdef __mips64
+#define op_SC_p(op)    (op == 0x38 || op == 0x3c)
+#define op_LL_p(op)    (op == 0x30 || op == 0x34)
+#else /* !__mips64 */
+#define op_SC_p(op)    (op == 0x38)
+#define op_LL_p(op)    (op == 0x30)
+#endif /* !__mips64 */
+
 static int
-mips_atomic_next_pcs(struct process *proc, uint32_t lladdr, uint32_t *newpcs)
+mips_atomic_next_pcs(struct process *proc, unsigned long lladdr,
+                    unsigned long *newpcs)
 {
        int nr = 0;
 
-       uint32_t scaddr;
+       unsigned long scaddr;
        for (scaddr = lladdr + 4; scaddr - lladdr <= 2048; scaddr += 4) {
                /* Found SC, now stepover trailing branch */
                uint32_t inst;
                if (proc_read_32(proc, (arch_addr_t)scaddr, &inst) >= 0 &&
-                   itype_op(inst) == 0x38) {
+                   op_SC_p (itype_op(inst))) {
                        newpcs[nr++] = scaddr + 4;
                        break;
                }
@@ -327,16 +420,16 @@ mips_atomic_next_pcs(struct process *proc, uint32_t 
lladdr, uint32_t *newpcs)
        }
 
        /* Scan LL<->SC range for branches going outside that range */
-       uint32_t spc;
+       unsigned long spc;
        for (spc = lladdr + 4; spc < scaddr; spc += 4) {
-               uint32_t scanpcs[2];
+               unsigned long scanpcs[2];
                int snr = mips_next_pcs(proc, spc, scanpcs);
 
                int i;
                for (i = 0; i < snr; ++i) {
                        if (!inrange(scanpcs[i], lladdr, scaddr)) {
-                               uint32_t *tmp = realloc(newpcs, (nr + 1) *
-                                                       sizeof *newpcs);
+                               unsigned long *tmp = realloc(newpcs, (nr + 1)
+                                                            * sizeof *newpcs);
                                if (tmp == NULL) {
                                        perror("malloc atomic next pcs");
                                        return -1;
@@ -357,8 +450,8 @@ 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;
+       unsigned long pc = (unsigned long) get_instruction_pointer(proc);
+       unsigned long *newpcs;
        int nr;
        uint32_t inst;
 
@@ -369,7 +462,7 @@ arch_sw_singlestep(struct process *proc, struct breakpoint 
*bp,
                return SWS_FAIL;
 
        /* Starting an atomic read-modify-write sequence */
-       if (itype_op(inst) == 0x30)
+       if (op_LL_p(itype_op(inst)))
                nr = mips_atomic_next_pcs(proc, pc, newpcs);
        else
                nr = mips_next_pcs(proc, pc, newpcs);
@@ -462,7 +555,7 @@ gimme_arg(enum tof type, struct process *proc, int arg_num,
                                debug(2,"ret = %#lx",addr);
                                return addr;
                        }
-                       ret = addr + 4*arg_num;
+                       ret = addr + sizeof(long) * arg_num;
                        ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
                        debug(2,"ret = %#lx",ret);
                        return ret;
@@ -474,7 +567,7 @@ gimme_arg(enum tof type, struct process *proc, int arg_num,
                        debug(2,"ret = %#lx",addr);
                        return addr;
                }
-               ret = addr + 4*arg_num;
+               ret = addr + sizeof(long) * arg_num;
                ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0);
                debug(2,"ret = %#lx",ret);
                return ret;
@@ -483,4 +576,34 @@ gimme_arg(enum tof type, struct process *proc, int arg_num,
        return 0;
 }
 
+#ifdef __LP64__
+size_t
+arch_type_sizeof(struct process *proc, struct arg_type_info *info)
+{
+       if (proc == NULL)
+               return (size_t)-2;
+
+       switch (info->type) {
+       case ARGTYPE_LONG:
+       case ARGTYPE_ULONG:
+               return proc->mask_32bit ? 4 : sizeof (long);
+
+       case ARGTYPE_POINTER:
+               return proc->mask_32bit ? 4 : sizeof (void *);
+
+       default:
+               /* Use default value.  */
+               return (size_t)-2;
+       }
+}
+
+size_t
+arch_type_alignof(struct process *proc, struct arg_type_info *info)
+{
+       if (proc == NULL)
+               return (size_t)-2;
+
+       return arch_type_sizeof(proc, info);
+}
+#endif /* __LP64__ */
 /**@}*/
diff --git a/sysdeps/linux-gnu/mksyscallent_mips 
b/sysdeps/linux-gnu/mksyscallent_mips
index f3961b4..f8dcfe1 100755
--- a/sysdeps/linux-gnu/mksyscallent_mips
+++ b/sysdeps/linux-gnu/mksyscallent_mips
@@ -19,9 +19,7 @@
 
 # hack expression to generate arch/syscallent.h from <asm/unistd.h>
 # It reads from stdin and writes to stdout
-# It should work OK on i386,m68k,arm,ia64
-# It does NOT work in mips, s390
-# It is untested in other architectures
+# Default is o32; arch=mips64 generates n64 syscalls
 
 BEGIN {
        max=0;
@@ -31,7 +29,10 @@ BEGIN {
 {
        #debug
        #printf("/%s/%s/%s/%s/\n", $1, $2, $3, $4);
-       if ($2 ~ /__NR_Linux/ && $3 ~ /4000/) {
+        min=4000
+        if (arch ~ "mips64") min=5000
+
+       if ($2 ~ /__NR_Linux/ && $3 ~ min) {
                syscall=1;
        }
        if ($2 ~ /__NR_Linux_syscalls/) {
-- 1.7.9.5


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

Reply via email to