1From 5f6dfafb80bdc2566fe91d5fde96769175fabf35 Mon Sep 17 00:00:00 2001 2From: Faraz Shahbazker <faraz.shahbazker@imgtec.com> 3Date: Sat, 1 Jul 2017 10:56:59 -0700 4Subject: [PATCH] Add support for mips64 n32/n64 5 6Signed-off-by: Khem Raj <raj.khem@gmail.com> 7--- 8Upstream-Status: Pending 9Source: http://lists.alioth.debian.org/pipermail/ltrace-devel/2015-May/001327.html 10 11 backend.h | 8 + 12 ltrace-elf.c | 12 ++ 13 proc.h | 1 + 14 sysdeps/linux-gnu/mips/Makefile.am | 1 + 15 sysdeps/linux-gnu/mips/abi.c | 64 +++++++ 16 sysdeps/linux-gnu/mips/arch.h | 24 ++- 17 sysdeps/linux-gnu/mips/plt.c | 68 ++++++-- 18 sysdeps/linux-gnu/mips/signalent1.h | 52 ++++++ 19 sysdeps/linux-gnu/mips/syscallent1.h | 328 +++++++++++++++++++++++++++++++++++ 20 sysdeps/linux-gnu/mips/trace.c | 241 ++++++++++++++++++------- 21 sysdeps/linux-gnu/mksyscallent_mips | 9 +- 22 11 files changed, 728 insertions(+), 80 deletions(-) 23 create mode 100644 sysdeps/linux-gnu/mips/abi.c 24 create mode 100644 sysdeps/linux-gnu/mips/signalent1.h 25 create mode 100644 sysdeps/linux-gnu/mips/syscallent1.h 26 27diff --git a/backend.h b/backend.h 28index e25daa0..0d6926a 100644 29--- a/backend.h 30+++ b/backend.h 31@@ -314,6 +314,14 @@ int arch_process_exec(struct process *proc); 32 int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index, 33 GElf_Rela *rela, GElf_Sym *sym); 34 35+/* The following callback has to be implemented in backend if arch.h 36+ * defines ARCH_HAVE_GET_ABI 37+ * 38+ * This is called from read_module just once, when reading the main module. 39+ * The value returned is an architecture specific ID for the current ABI 40+ * to be used later for ABI-specific operations. */ 41+char arch_get_abi(GElf_Ehdr ehdr); 42+ 43 enum plt_status { 44 PLT_FAIL, 45 PLT_OK, 46diff --git a/ltrace-elf.c b/ltrace-elf.c 47index f439cb0..a85edca 100644 48--- a/ltrace-elf.c 49+++ b/ltrace-elf.c 50@@ -1131,6 +1131,14 @@ populate_symtab(struct process *proc, const char *filename, 51 only_exported_names); 52 } 53 54+#ifndef ARCH_HAVE_GET_ABI 55+char 56+arch_get_abi(GElf_Ehdr ehdr) 57+{ 58+ return 0; 59+} 60+#endif 61+ 62 static int 63 read_module(struct library *lib, struct process *proc, 64 const char *filename, GElf_Addr bias, int main) 65@@ -1151,6 +1159,10 @@ read_module(struct library *lib, struct process *proc, 66 * with 32-bit ltrace. It is desirable to preserve this. */ 67 proc->e_machine = lte.ehdr.e_machine; 68 proc->e_class = lte.ehdr.e_ident[EI_CLASS]; 69+ /* Another candidate for the ABI module. We probably 70+ * want to do all of the e_* stuff only once, for main */ 71+ if (main) 72+ proc->e_abi = arch_get_abi(lte.ehdr); 73 get_arch_dep(proc); 74 75 /* Find out the base address. For PIE main binaries we look 76diff --git a/proc.h b/proc.h 77index a611456..00094e1 100644 78--- a/proc.h 79+++ b/proc.h 80@@ -117,6 +117,7 @@ struct process { 81 * nauseam. */ 82 short e_machine; 83 char e_class; 84+ char e_abi; 85 86 #if defined(HAVE_LIBDW) 87 /* Unwind info for leader, NULL for non-leader procs. */ 88diff --git a/sysdeps/linux-gnu/mips/Makefile.am b/sysdeps/linux-gnu/mips/Makefile.am 89index 1fd8c2a..571ee0d 100644 90--- a/sysdeps/linux-gnu/mips/Makefile.am 91+++ b/sysdeps/linux-gnu/mips/Makefile.am 92@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = \ 93 ../libcpu.la 94 95 ___libcpu_la_SOURCES = \ 96+ abi.c \ 97 plt.c \ 98 regs.c \ 99 trace.c 100diff --git a/sysdeps/linux-gnu/mips/abi.c b/sysdeps/linux-gnu/mips/abi.c 101new file mode 100644 102index 0000000..64e3c10 103--- /dev/null 104+++ b/sysdeps/linux-gnu/mips/abi.c 105@@ -0,0 +1,64 @@ 106+/* 107+ * This file is part of ltrace. 108+ * Copyright (C) 2015 Imagination Technologies Limited 109+ * 110+ * This program is free software; you can redistribute it and/or 111+ * modify it under the terms of the GNU General Public License as 112+ * published by the Free Software Foundation; either version 2 of the 113+ * License, or (at your option) any later version. 114+ * 115+ * This program is distributed in the hope that it will be useful, but 116+ * WITHOUT ANY WARRANTY; without even the implied warranty of 117+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 118+ * General Public License for more details. 119+ * 120+ * You should have received a copy of the GNU General Public License 121+ * along with this program; if not, write to the Free Software 122+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 123+ * 02110-1301 USA 124+ */ 125+ 126+#include <stdio.h> 127+#include <gelf.h> 128+#include "arch.h" 129+ 130+/* 131+ * There is no bit in the header-flags to mark N64 ABI, it must be 132+ * determined by exclusion of other ABIs. The following values are 133+ * from elfcpp/mips.h in binutils sources 134+ */ 135+enum 136+{ 137+ E_MIPS_ABI_MASK = 0x0000F000, 138+ E_MIPS_ABI_N32 = 0x00000020, 139+ E_MIPS_ABI_O32 = 0x00001000, 140+ E_MIPS_ABI_O64 = 0x00002000, 141+ E_MIPS_ABI_EABI32 = 0x00003000, 142+ E_MIPS_ABI_EABI64 = 0x00004000, 143+}; 144+ 145+char 146+arch_get_abi(GElf_Ehdr ehdr) 147+{ 148+ enum mips_abi_type abi; 149+ switch (ehdr.e_flags & E_MIPS_ABI_MASK) { 150+ case E_MIPS_ABI_O32: 151+ abi = ABI_O32; break; 152+ case E_MIPS_ABI_O64: 153+ abi = ABI_O64; break; 154+ case E_MIPS_ABI_EABI32: 155+ case E_MIPS_ABI_EABI64: 156+ fprintf(stderr, "%s: MIPS EABI is not supported\n", __func__); 157+ abi = -1; 158+ break; 159+ default: 160+ if (ehdr.e_flags & E_MIPS_ABI_N32) 161+ abi = ABI_N32; 162+ else 163+ abi = ABI_N64; 164+ } 165+ 166+ return abi; 167+} 168+ 169+/**@}*/ 170diff --git a/sysdeps/linux-gnu/mips/arch.h b/sysdeps/linux-gnu/mips/arch.h 171index 16273d2..8b75df2 100644 172--- a/sysdeps/linux-gnu/mips/arch.h 173+++ b/sysdeps/linux-gnu/mips/arch.h 174@@ -1,5 +1,6 @@ 175 /* 176 * This file is part of ltrace. 177+ * Copyright (C) 2015 Imagination Technologies Limited 178 * Copyright (C) 2013,2014 Petr Machata, Red Hat Inc. 179 * Copyright (C) 2006 Eric Vaitl 180 * 181@@ -38,8 +39,12 @@ 182 #define BREAKPOINT_LENGTH 4 183 #define DECR_PC_AFTER_BREAK 0 184 185-#define LT_ELFCLASS ELFCLASS32 186+#ifdef __LP64__ 187+#define LT_ELFCLASS ELFCLASS64 188 #define LT_ELF_MACHINE EM_MIPS 189+#endif /* __LP64__ */ 190+#define LT_ELFCLASS2 ELFCLASS32 191+#define LT_ELF_MACHINE2 EM_MIPS 192 193 #define ARCH_HAVE_LTELF_DATA 194 struct arch_ltelf_data { 195@@ -53,8 +58,14 @@ struct arch_ltelf_data { 196 #define ARCH_HAVE_ADD_PLT_ENTRY 197 #define ARCH_HAVE_SW_SINGLESTEP 198 #define ARCH_HAVE_SYMBOL_RET 199- 200+#define ARCH_HAVE_GET_ABI 201 #define ARCH_HAVE_LIBRARY_SYMBOL_DATA 202+ 203+#ifdef __LP64__ 204+#define ARCH_HAVE_SIZEOF 205+#define ARCH_HAVE_ALIGNOF 206+#endif /* __LP64__ */ 207+ 208 enum mips_plt_type 209 { 210 /* A symbol has associated PLT entry. */ 211@@ -73,7 +84,14 @@ enum mips_plt_type 212 MIPS_PLT_NEED_UNRESOLVE, 213 }; 214 215-struct mips_unresolve_data; 216+enum mips_abi_type 217+{ 218+ ABI_O32, 219+ ABI_N32, 220+ ABI_N64, 221+ ABI_O64, 222+}; 223+ 224 struct arch_library_symbol_data { 225 enum mips_plt_type type; 226 union { 227diff --git a/sysdeps/linux-gnu/mips/plt.c b/sysdeps/linux-gnu/mips/plt.c 228index f3c12da..2d85ad9 100644 229--- a/sysdeps/linux-gnu/mips/plt.c 230+++ b/sysdeps/linux-gnu/mips/plt.c 231@@ -1,5 +1,6 @@ 232 /* 233 * This file is part of ltrace. 234+ * Copyright (C) 2015 Imagination Technologies Limited 235 * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc. 236 * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications 237 * Copyright (C) 2008,2009 Juan Cespedes 238@@ -182,6 +183,11 @@ arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr, 239 { 240 arch_addr_t rld_addr; 241 int r; 242+#ifdef __LP64__ 243+ size_t addrsize = proc->mask_32bit ? 4 : (sizeof *ret); 244+#else /* !__LP64__ */ 245+ size_t addrsize = sizeof *ret; 246+#endif /* !__LP64__ */ 247 248 /* MIPS puts the address of the r_debug structure into the 249 * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry. */ 250@@ -189,7 +195,7 @@ arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr, 251 DT_MIPS_RLD_MAP, &rld_addr); 252 if (r == 0) { 253 if (umovebytes(proc, rld_addr, 254- ret, sizeof *ret) != sizeof *ret) { 255+ ret, addrsize) != addrsize) { 256 r = -1; 257 } 258 } 259@@ -295,14 +301,25 @@ arch_elf_init(struct ltelf *lte, struct library *lib) 260 261 for (j = 0; j < data->d_size / 16; ++j) { 262 uint32_t insn; 263+ int got_size = 4; 264+ uint32_t load_inst = 0x24180000U; /* addui t8,0,xx */ 265+ 266+#ifdef __LP64__ 267+ if (arch_get_abi(lte->ehdr) == ABI_N64 268+ || arch_get_abi(lte->ehdr) == ABI_O64) { 269+ got_size = 8; 270+ load_inst = 0x64180000U; /* daddui t8,0,xx */ 271+ } 272+#endif /* __LP64__ */ 273+ 274 if (elf_read_u32(data, j * 16 + 12, &insn) < 0) 275 goto fail_stubs; 276 277 if (insn == 0) 278 continue; 279 280- /* 0x2418XXXX encodes lbu 0,t8,XXXX or li t8,XXXX. */ 281- if ((insn & 0xffff0000U) != 0x24180000U) 282+ /* 0x[62]418XXXX encodes [d]addiu t8, 0, XXXX. */ 283+ if ((insn & 0xffff0000U) != load_inst) 284 goto fail_stubs; 285 286 unsigned idx = insn & 0xffff; 287@@ -323,8 +340,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib) 288 + lte->arch.mips_local_gotno; 289 /* XXX Double cast. */ 290 arch_addr_t got_entry_addr 291- = (arch_addr_t) (uintptr_t) lte->arch.pltgot_addr 292- + got_idx * 4; 293+ = (arch_addr_t) (uintptr_t) (lte->arch.pltgot_addr 294+ + got_idx * got_size); 295 296 GElf_Rela rela = { 297 /* XXX double cast. */ 298@@ -336,7 +353,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib) 299 if (VECT_PUSHBACK(<e->plt_relocs, &rela) < 0) 300 goto fail_stubs; 301 302- fprintf(stderr, 303+ debug(2, 304 "added stub entry for symbol %u at %#lx, GOT @%p\n", 305 idx, (unsigned long) rela.r_addend, got_entry_addr); 306 } 307@@ -362,8 +379,17 @@ read_got_entry(struct process *proc, GElf_Addr addr, GElf_Addr *valp) 308 { 309 /* XXX double cast. */ 310 arch_addr_t a = (arch_addr_t) (uintptr_t) addr; 311- uint32_t l; 312- if (proc_read_32(proc, a, &l) < 0) { 313+ uint64_t l = 0; 314+ int result; 315+ 316+#ifdef __LP64__ 317+ if (!proc->mask_32bit) 318+ result = proc_read_64(proc, a, &l); 319+ else 320+#endif /* __LP64__ */ 321+ result = proc_read_32(proc, a, (uint32_t *) &l); 322+ 323+ if (result < 0) { 324 fprintf(stderr, "ptrace read got entry @%#" PRIx64 ": %s\n", 325 addr, strerror(errno)); 326 return -1; 327@@ -426,13 +452,13 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte, 328 GElf_Addr stub_addr = rela->r_addend + lte->bias; 329 330 debug(2, "PLT-less arch_elf_add_plt_entry %s = %#llx\n", 331- a_name, stub_addr); 332+ a_name, (unsigned long long) stub_addr); 333 334 struct library_symbol *libsym = NULL; 335 if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx, 336 &libsym) < 0) { 337- fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__, 338- a_name, stub_addr, strerror(errno)); 339+ fprintf(stderr, "%s: failed %s(%#lx): %s\n", __func__, 340+ a_name, (unsigned long) stub_addr, strerror(errno)); 341 goto fail; 342 } 343 344@@ -503,13 +529,27 @@ jump_to_entry_point(struct process *proc, struct breakpoint *bp) 345 static int 346 unresolve_got_entry(struct process *proc, GElf_Addr addr, GElf_Addr value) 347 { 348- uint32_t v32 = (uint32_t) value; 349- uint32_t a32 = (uint32_t) addr; 350- if (ptrace(PTRACE_POKETEXT, proc->pid, a32, v32) < 0) { 351+ arch_addr_t a = (arch_addr_t) (uintptr_t) addr; 352+#ifdef __LP64__ 353+ /* To write 32-bit value in 64-bit mode, we must read-modify-write 354+ the 64-bit value with only the lower 32 bits modified. */ 355+ if (proc->mask_32bit) { 356+ GElf_Addr orig = ptrace(PTRACE_PEEKTEXT, proc->pid, a, 0); 357+ char *obytes = (char *) &orig; 358+ char *nbytes = (char *) &value; 359+ unsigned i; 360+ 361+ for (i = 0; i < 4; i++) 362+ obytes[i] = nbytes[i]; 363+ value = orig; 364+ } 365+#endif /* __LP64__ */ 366+ if (ptrace(PTRACE_POKETEXT, proc->pid, a, (unsigned long) value) < 0) { 367 fprintf(stderr, "failed to unresolve GOT entry: %s\n", 368 strerror(errno)); 369 return -1; 370 } 371+ 372 return 0; 373 } 374 375diff --git a/sysdeps/linux-gnu/mips/signalent1.h b/sysdeps/linux-gnu/mips/signalent1.h 376new file mode 100644 377index 0000000..9e9d1f7 378--- /dev/null 379+++ b/sysdeps/linux-gnu/mips/signalent1.h 380@@ -0,0 +1,52 @@ 381+/* 382+ * This file is part of ltrace. 383+ * Copyright (C) 2015 Imagination Technologies Limited 384+ * 385+ * This program is free software; you can redistribute it and/or 386+ * modify it under the terms of the GNU General Public License as 387+ * published by the Free Software Foundation; either version 2 of the 388+ * License, or (at your option) any later version. 389+ * 390+ * This program is distributed in the hope that it will be useful, but 391+ * WITHOUT ANY WARRANTY; without even the implied warranty of 392+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 393+ * General Public License for more details. 394+ * 395+ * You should have received a copy of the GNU General Public License 396+ * along with this program; if not, write to the Free Software 397+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 398+ * 02110-1301 USA 399+ */ 400+ 401+ "SIG_0", /* 0 */ 402+ "SIGHUP", /* 1 */ 403+ "SIGINT", /* 2 */ 404+ "SIGQUIT", /* 3 */ 405+ "SIGILL", /* 4 */ 406+ "SIGTRAP", /* 5 */ 407+ "SIGIOT", /* 6 */ 408+ "SIGEMT", /* 7 */ 409+ "SIGFPE", /* 8 */ 410+ "SIGKILL", /* 9 */ 411+ "SIGBUS", /* 10 */ 412+ "SIGSEGV", /* 11 */ 413+ "SIGSYS", /* 12 */ 414+ "SIGPIPE", /* 13 */ 415+ "SIGALRM", /* 14 */ 416+ "SIGTERM", /* 15 */ 417+ "SIGUSR1", /* 16 */ 418+ "SIGUSR2", /* 17 */ 419+ "SIGCHLD", /* 18 */ 420+ "SIGPWR", /* 19 */ 421+ "SIGWINCH", /* 20 */ 422+ "SIGURG", /* 21 */ 423+ "SIGIO", /* 22 */ 424+ "SIGSTOP", /* 23 */ 425+ "SIGTSTP", /* 24 */ 426+ "SIGCONT", /* 25 */ 427+ "SIGTTIN", /* 26 */ 428+ "SIGTTOU", /* 27 */ 429+ "SIGVTALRM", /* 28 */ 430+ "SIGPROF", /* 29 */ 431+ "SIGXCPU", /* 30 */ 432+ "SIGXFSZ", /* 31 */ 433diff --git a/sysdeps/linux-gnu/mips/syscallent1.h b/sysdeps/linux-gnu/mips/syscallent1.h 434new file mode 100644 435index 0000000..dfa4954 436--- /dev/null 437+++ b/sysdeps/linux-gnu/mips/syscallent1.h 438@@ -0,0 +1,328 @@ 439+/* 440+ * This file is part of ltrace. 441+ * Copyright (C) 2015 Imagination Technologies Limited 442+ * 443+ * This program is free software; you can redistribute it and/or 444+ * modify it under the terms of the GNU General Public License as 445+ * published by the Free Software Foundation; either version 2 of the 446+ * License, or (at your option) any later version. 447+ * 448+ * This program is distributed in the hope that it will be useful, but 449+ * WITHOUT ANY WARRANTY; without even the implied warranty of 450+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 451+ * General Public License for more details. 452+ * 453+ * You should have received a copy of the GNU General Public License 454+ * along with this program; if not, write to the Free Software 455+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 456+ * 02110-1301 USA 457+ */ 458+ 459+/* MIPS64 */ 460+ 461+ "read", /* 0 */ 462+ "write", /* 1 */ 463+ "open", /* 2 */ 464+ "close", /* 3 */ 465+ "stat", /* 4 */ 466+ "fstat", /* 5 */ 467+ "lstat", /* 6 */ 468+ "poll", /* 7 */ 469+ "lseek", /* 8 */ 470+ "mmap", /* 9 */ 471+ "mprotect", /* 10 */ 472+ "munmap", /* 11 */ 473+ "brk", /* 12 */ 474+ "rt_sigaction", /* 13 */ 475+ "rt_sigprocmask", /* 14 */ 476+ "ioctl", /* 15 */ 477+ "pread64", /* 16 */ 478+ "pwrite64", /* 17 */ 479+ "readv", /* 18 */ 480+ "writev", /* 19 */ 481+ "access", /* 20 */ 482+ "pipe", /* 21 */ 483+ "_newselect", /* 22 */ 484+ "sched_yield", /* 23 */ 485+ "mremap", /* 24 */ 486+ "msync", /* 25 */ 487+ "mincore", /* 26 */ 488+ "madvise", /* 27 */ 489+ "shmget", /* 28 */ 490+ "shmat", /* 29 */ 491+ "shmctl", /* 30 */ 492+ "dup", /* 31 */ 493+ "dup2", /* 32 */ 494+ "pause", /* 33 */ 495+ "nanosleep", /* 34 */ 496+ "getitimer", /* 35 */ 497+ "setitimer", /* 36 */ 498+ "alarm", /* 37 */ 499+ "getpid", /* 38 */ 500+ "sendfile", /* 39 */ 501+ "socket", /* 40 */ 502+ "connect", /* 41 */ 503+ "accept", /* 42 */ 504+ "sendto", /* 43 */ 505+ "recvfrom", /* 44 */ 506+ "sendmsg", /* 45 */ 507+ "recvmsg", /* 46 */ 508+ "shutdown", /* 47 */ 509+ "bind", /* 48 */ 510+ "listen", /* 49 */ 511+ "getsockname", /* 50 */ 512+ "getpeername", /* 51 */ 513+ "socketpair", /* 52 */ 514+ "setsockopt", /* 53 */ 515+ "getsockopt", /* 54 */ 516+ "clone", /* 55 */ 517+ "fork", /* 56 */ 518+ "execve", /* 57 */ 519+ "exit", /* 58 */ 520+ "wait4", /* 59 */ 521+ "kill", /* 60 */ 522+ "uname", /* 61 */ 523+ "semget", /* 62 */ 524+ "semop", /* 63 */ 525+ "semctl", /* 64 */ 526+ "shmdt", /* 65 */ 527+ "msgget", /* 66 */ 528+ "msgsnd", /* 67 */ 529+ "msgrcv", /* 68 */ 530+ "msgctl", /* 69 */ 531+ "fcntl", /* 70 */ 532+ "flock", /* 71 */ 533+ "fsync", /* 72 */ 534+ "fdatasync", /* 73 */ 535+ "truncate", /* 74 */ 536+ "ftruncate", /* 75 */ 537+ "getdents", /* 76 */ 538+ "getcwd", /* 77 */ 539+ "chdir", /* 78 */ 540+ "fchdir", /* 79 */ 541+ "rename", /* 80 */ 542+ "mkdir", /* 81 */ 543+ "rmdir", /* 82 */ 544+ "creat", /* 83 */ 545+ "link", /* 84 */ 546+ "unlink", /* 85 */ 547+ "symlink", /* 86 */ 548+ "readlink", /* 87 */ 549+ "chmod", /* 88 */ 550+ "fchmod", /* 89 */ 551+ "chown", /* 90 */ 552+ "fchown", /* 91 */ 553+ "lchown", /* 92 */ 554+ "umask", /* 93 */ 555+ "gettimeofday", /* 94 */ 556+ "getrlimit", /* 95 */ 557+ "getrusage", /* 96 */ 558+ "sysinfo", /* 97 */ 559+ "times", /* 98 */ 560+ "ptrace", /* 99 */ 561+ "getuid", /* 100 */ 562+ "syslog", /* 101 */ 563+ "getgid", /* 102 */ 564+ "setuid", /* 103 */ 565+ "setgid", /* 104 */ 566+ "geteuid", /* 105 */ 567+ "getegid", /* 106 */ 568+ "setpgid", /* 107 */ 569+ "getppid", /* 108 */ 570+ "getpgrp", /* 109 */ 571+ "setsid", /* 110 */ 572+ "setreuid", /* 111 */ 573+ "setregid", /* 112 */ 574+ "getgroups", /* 113 */ 575+ "setgroups", /* 114 */ 576+ "setresuid", /* 115 */ 577+ "getresuid", /* 116 */ 578+ "setresgid", /* 117 */ 579+ "getresgid", /* 118 */ 580+ "getpgid", /* 119 */ 581+ "setfsuid", /* 120 */ 582+ "setfsgid", /* 121 */ 583+ "getsid", /* 122 */ 584+ "capget", /* 123 */ 585+ "capset", /* 124 */ 586+ "rt_sigpending", /* 125 */ 587+ "rt_sigtimedwait", /* 126 */ 588+ "rt_sigqueueinfo", /* 127 */ 589+ "rt_sigsuspend", /* 128 */ 590+ "sigaltstack", /* 129 */ 591+ "utime", /* 130 */ 592+ "mknod", /* 131 */ 593+ "personality", /* 132 */ 594+ "ustat", /* 133 */ 595+ "statfs", /* 134 */ 596+ "fstatfs", /* 135 */ 597+ "sysfs", /* 136 */ 598+ "getpriority", /* 137 */ 599+ "setpriority", /* 138 */ 600+ "sched_setparam", /* 139 */ 601+ "sched_getparam", /* 140 */ 602+ "sched_setscheduler", /* 141 */ 603+ "sched_getscheduler", /* 142 */ 604+ "sched_get_priority_max", /* 143 */ 605+ "sched_get_priority_min", /* 144 */ 606+ "sched_rr_get_interval", /* 145 */ 607+ "mlock", /* 146 */ 608+ "munlock", /* 147 */ 609+ "mlockall", /* 148 */ 610+ "munlockall", /* 149 */ 611+ "vhangup", /* 150 */ 612+ "pivot_root", /* 151 */ 613+ "_sysctl", /* 152 */ 614+ "prctl", /* 153 */ 615+ "adjtimex", /* 154 */ 616+ "setrlimit", /* 155 */ 617+ "chroot", /* 156 */ 618+ "sync", /* 157 */ 619+ "acct", /* 158 */ 620+ "settimeofday", /* 159 */ 621+ "mount", /* 160 */ 622+ "umount2", /* 161 */ 623+ "swapon", /* 162 */ 624+ "swapoff", /* 163 */ 625+ "reboot", /* 164 */ 626+ "sethostname", /* 165 */ 627+ "setdomainname", /* 166 */ 628+ "create_module", /* 167 */ 629+ "init_module", /* 168 */ 630+ "delete_module", /* 169 */ 631+ "get_kernel_syms", /* 170 */ 632+ "query_module", /* 171 */ 633+ "quotactl", /* 172 */ 634+ "nfsservctl", /* 173 */ 635+ "getpmsg", /* 174 */ 636+ "putpmsg", /* 175 */ 637+ "afs_syscall", /* 176 */ 638+ "reserved177", /* 177 */ 639+ "gettid", /* 178 */ 640+ "readahead", /* 179 */ 641+ "setxattr", /* 180 */ 642+ "lsetxattr", /* 181 */ 643+ "fsetxattr", /* 182 */ 644+ "getxattr", /* 183 */ 645+ "lgetxattr", /* 184 */ 646+ "fgetxattr", /* 185 */ 647+ "listxattr", /* 186 */ 648+ "llistxattr", /* 187 */ 649+ "flistxattr", /* 188 */ 650+ "removexattr", /* 189 */ 651+ "lremovexattr", /* 190 */ 652+ "fremovexattr", /* 191 */ 653+ "tkill", /* 192 */ 654+ "reserved193", /* 193 */ 655+ "futex", /* 194 */ 656+ "sched_setaffinity", /* 195 */ 657+ "sched_getaffinity", /* 196 */ 658+ "cacheflush", /* 197 */ 659+ "cachectl", /* 198 */ 660+ "sysmips", /* 199 */ 661+ "io_setup", /* 200 */ 662+ "io_destroy", /* 201 */ 663+ "io_getevents", /* 202 */ 664+ "io_submit", /* 203 */ 665+ "io_cancel", /* 204 */ 666+ "exit_group", /* 205 */ 667+ "lookup_dcookie", /* 206 */ 668+ "epoll_create", /* 207 */ 669+ "epoll_ctl", /* 208 */ 670+ "epoll_wait", /* 209 */ 671+ "remap_file_pages", /* 210 */ 672+ "rt_sigreturn", /* 211 */ 673+ "set_tid_address", /* 212 */ 674+ "restart_syscall", /* 213 */ 675+ "semtimedop", /* 214 */ 676+ "fadvise64", /* 215 */ 677+ "timer_create", /* 216 */ 678+ "timer_settime", /* 217 */ 679+ "timer_gettime", /* 218 */ 680+ "timer_getoverrun", /* 219 */ 681+ "timer_delete", /* 220 */ 682+ "clock_settime", /* 221 */ 683+ "clock_gettime", /* 222 */ 684+ "clock_getres", /* 223 */ 685+ "clock_nanosleep", /* 224 */ 686+ "tgkill", /* 225 */ 687+ "utimes", /* 226 */ 688+ "mbind", /* 227 */ 689+ "get_mempolicy", /* 228 */ 690+ "set_mempolicy", /* 229 */ 691+ "mq_open", /* 230 */ 692+ "mq_unlink", /* 231 */ 693+ "mq_timedsend", /* 232 */ 694+ "mq_timedreceive", /* 233 */ 695+ "mq_notify", /* 234 */ 696+ "mq_getsetattr", /* 235 */ 697+ "vserver", /* 236 */ 698+ "waitid", /* 237 */ 699+ "238", /* 238 */ 700+ "add_key", /* 239 */ 701+ "request_key", /* 240 */ 702+ "keyctl", /* 241 */ 703+ "set_thread_area", /* 242 */ 704+ "inotify_init", /* 243 */ 705+ "inotify_add_watch", /* 244 */ 706+ "inotify_rm_watch", /* 245 */ 707+ "migrate_pages", /* 246 */ 708+ "openat", /* 247 */ 709+ "mkdirat", /* 248 */ 710+ "mknodat", /* 249 */ 711+ "fchownat", /* 250 */ 712+ "futimesat", /* 251 */ 713+ "newfstatat", /* 252 */ 714+ "unlinkat", /* 253 */ 715+ "renameat", /* 254 */ 716+ "linkat", /* 255 */ 717+ "symlinkat", /* 256 */ 718+ "readlinkat", /* 257 */ 719+ "fchmodat", /* 258 */ 720+ "faccessat", /* 259 */ 721+ "pselect6", /* 260 */ 722+ "ppoll", /* 261 */ 723+ "unshare", /* 262 */ 724+ "splice", /* 263 */ 725+ "sync_file_range", /* 264 */ 726+ "tee", /* 265 */ 727+ "vmsplice", /* 266 */ 728+ "move_pages", /* 267 */ 729+ "set_robust_list", /* 268 */ 730+ "get_robust_list", /* 269 */ 731+ "kexec_load", /* 270 */ 732+ "getcpu", /* 271 */ 733+ "epoll_pwait", /* 272 */ 734+ "ioprio_set", /* 273 */ 735+ "ioprio_get", /* 274 */ 736+ "utimensat", /* 275 */ 737+ "signalfd", /* 276 */ 738+ "timerfd", /* 277 */ 739+ "eventfd", /* 278 */ 740+ "fallocate", /* 279 */ 741+ "timerfd_create", /* 280 */ 742+ "timerfd_gettime", /* 281 */ 743+ "timerfd_settime", /* 282 */ 744+ "signalfd4", /* 283 */ 745+ "eventfd2", /* 284 */ 746+ "epoll_create1", /* 285 */ 747+ "dup3", /* 286 */ 748+ "pipe2", /* 287 */ 749+ "inotify_init1", /* 288 */ 750+ "preadv", /* 289 */ 751+ "pwritev", /* 290 */ 752+ "rt_tgsigqueueinfo", /* 291 */ 753+ "perf_event_open", /* 292 */ 754+ "accept4", /* 293 */ 755+ "recvmmsg", /* 294 */ 756+ "fanotify_init", /* 295 */ 757+ "fanotify_mark", /* 296 */ 758+ "prlimit64", /* 297 */ 759+ "name_to_handle_at", /* 298 */ 760+ "open_by_handle_at", /* 299 */ 761+ "clock_adjtime", /* 300 */ 762+ "syncfs", /* 301 */ 763+ "sendmmsg", /* 302 */ 764+ "setns", /* 303 */ 765+ "process_vm_readv", /* 304 */ 766+ "process_vm_writev", /* 305 */ 767diff --git a/sysdeps/linux-gnu/mips/trace.c b/sysdeps/linux-gnu/mips/trace.c 768index e81b374..d54818e 100644 769--- a/sysdeps/linux-gnu/mips/trace.c 770+++ b/sysdeps/linux-gnu/mips/trace.c 771@@ -1,5 +1,6 @@ 772 /* 773 * This file is part of ltrace. 774+ * Copyright (C) 2015 Imagination Technologies Limited 775 * Copyright (C) 2013 Petr Machata, Red Hat Inc. 776 * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications 777 * Copyright (C) 2010 Arnaud Patard, Mandriva SA 778@@ -29,6 +30,7 @@ 779 #include <signal.h> 780 #include <sys/ptrace.h> 781 #include <asm/ptrace.h> 782+#include <asm/unistd.h> 783 #include <assert.h> 784 #include <asm/unistd.h> 785 786@@ -68,6 +70,44 @@ 787 void 788 get_arch_dep(struct process *proc) 789 { 790+#ifdef __LP64__ 791+ proc->mask_32bit = (proc->e_class == ELFCLASS32); 792+#endif /* __LP64__ */ 793+ /* n32 personality is best approximated by n64, 794+ at least for syscall numbers */ 795+ proc->personality = (proc->e_class == ELFCLASS64 796+ || proc->e_abi == ABI_N32); 797+} 798+ 799+/** 800+ \param abi ABI of current process, from mips_abi_type enum 801+ \param list An array of 4 elements, each corresponding to an ABI, in 802+ the order: o32, n32, n64, o64 803+ 804+ return value from array corresponding to requested ABI 805+ */ 806+static int 807+abi_select(const int abi, const int list[]) 808+{ 809+ int retval; 810+ switch (abi) 811+ { 812+ case ABI_N32: 813+ retval = list[1]; 814+ break; 815+ case ABI_N64: 816+ retval = list[2]; 817+ break; 818+ case ABI_O64: 819+ retval = list[3]; 820+ break; 821+ case ABI_O32: 822+ default: 823+ retval = list[0]; 824+ break; 825+ } 826+ 827+ return retval; 828 } 829 830 /** 831@@ -90,53 +130,94 @@ get_arch_dep(struct process *proc) 832 int 833 syscall_p(struct process *proc, int status, int *sysnum) 834 { 835- if (WIFSTOPPED(status) 836- && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 837- /* get the user's pc (plus 8) */ 838- long pc = (long)get_instruction_pointer(proc); 839- /* fetch the SWI instruction */ 840- int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); 841- int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0); 842- 843- /* 844- On a mips, syscall looks like: 845- 24040fa1 li v0, 0x0fa1 # 4001 --> _exit syscall 846- 0000000c syscall 847- */ 848- if(insn!=0x0000000c){ 849- /* sigreturn returns control to the point 850- where the signal was received; skip check 851- for preceeding syscall instruction */ 852- int depth = proc->callstack_depth; 853- struct callstack_element *top = NULL; 854- if (depth > 0) 855- top = &proc->callstack[depth - 1]; 856- 857- if (top != NULL && top->is_syscall && 858- (top->c_un.syscall == (__NR_rt_sigreturn - 859- __NR_Linux) || 860- top->c_un.syscall == (__NR_sigreturn - 861- __NR_Linux))) { 862- *sysnum = top->c_un.syscall; 863- return 2; 864- } 865- else 866- return 0; 867- } 868- 869- *sysnum = (num & 0xFFFF) - 4000; 870- /* if it is a syscall, return 1 or 2 */ 871- if (proc->callstack_depth > 0 && 872- proc->callstack[proc->callstack_depth - 1].is_syscall && 873- proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { 874+ unsigned long pc; 875+ int insn, prev; 876+ int min_syscall, max_syscall, sigreturn, rt_sigreturn; 877+ struct callstack_element *top = NULL; 878+ int depth = proc->callstack_depth; 879+ const int syscallbase[] = {__NR_O32_Linux, __NR_N32_Linux, 880+ __NR_64_Linux, __NR_O32_Linux}; 881+ const int syscallnum[] = {__NR_O32_Linux_syscalls, 882+ __NR_N32_Linux_syscalls, 883+ __NR_64_Linux_syscalls, 884+ __NR_O32_Linux_syscalls}; 885+ const int rt_sigreturn_list[] = {193, 211, 211, 193}; 886+ const int sigreturn_list[] = {119, -1, -1, 119}; 887+ 888+ if (!WIFSTOPPED(status) 889+ || WSTOPSIG(status) != (SIGTRAP | proc->tracesysgood)) 890+ return 0; 891+ 892+ /* get the user's pc (plus 8) */ 893+ pc = (unsigned long)get_instruction_pointer(proc); 894+ /* fetch the SWI instruction */ 895+ insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); 896+ prev = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0); 897+ 898+ if (depth > 0) 899+ top = &proc->callstack[depth - 1]; 900+ 901+ /* Range of syscall numbers varies with ABI; ref:asm/unistd.h */ 902+ min_syscall = abi_select(proc->e_abi, syscallbase); 903+ max_syscall = min_syscall + abi_select(proc->e_abi, syscallnum); 904+ sigreturn = min_syscall + abi_select(proc->e_abi, sigreturn_list); 905+ rt_sigreturn = min_syscall + abi_select(proc->e_abi, rt_sigreturn_list); 906+ 907+ /* not a syscall instruction */ 908+ if(insn!=0x0000000c){ 909+ /* sigreturn returns control to the point where the signal was 910+ received; skip check for preceeding syscall instruction */ 911+ if (top != NULL && top->is_syscall 912+ && (top->c_un.syscall == (rt_sigreturn - min_syscall) 913+ || top->c_un.syscall == (sigreturn - min_syscall))) { 914+ *sysnum = top->c_un.syscall; 915 return 2; 916 } 917+ else 918+ return 0; 919+ } 920 921- if (*sysnum >= 0) { 922- return 1; 923- } 924+ /* 925+ On a mips, syscall looks like: 926+ 24020fa1 li v0, 0x0fa1 # 4001 --> _exit syscall 927+ 0000000c syscall 928+ */ 929+ if ((prev & 0xFFFF0000) == 0x24020000) { 930+ *sysnum = (prev & 0xFFFF) - min_syscall; 931 } 932- return 0; 933+ /* 934+ The above is not necessary in Linux kernel > v2.6.35. Recent 935+ kernels have a fancy-pants method of restarting syscalls. 936+ We must read v0 instead, to get the syscall number. 937+ 938+ Unfortunately, v0 is not preserved till the point of return. 939+ If already in syscall and v0 is invalid, assume this event 940+ to be a return without attempting to match previous syscall. 941+ 942+ Caveat: logic fails if v0 incidentally contains a valid 943+ syscall number, distinct from the current syscall number, 944+ at the point of return from a nested syscall. 945+ */ 946+ else { 947+ int v0 = ptrace(PTRACE_PEEKUSER, proc->pid, off_v0, 0); 948+ 949+ if ((v0 >= min_syscall) && (v0 <= max_syscall)) 950+ *sysnum = v0 - min_syscall; 951+ else if (depth > 0 && top->is_syscall) 952+ *sysnum = top->c_un.syscall; 953+ else /* syscall instruction without valid number - ignored */ 954+ return 0; 955+ } 956+ 957+ /* if it is a syscall, return 1 or 2 */ 958+ if (depth > 0 && top->is_syscall && top->c_un.syscall == *sysnum) { 959+ return 2; 960+ } 961+ 962+ if (*sysnum >= 0) 963+ return 1; 964+ else 965+ return 0; 966 } 967 968 /* Based on GDB code. */ 969@@ -162,9 +243,11 @@ mips32_relative_offset (uint32_t inst) 970 return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2; 971 } 972 973-int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc) 974+int mips_next_pcs(struct process *proc, unsigned long pc, 975+ unsigned long *newpc) 976 { 977- uint32_t inst, rx; 978+ uint32_t inst; 979+ unsigned long rx; 980 int op; 981 int rn; 982 int nr = 0; 983@@ -277,8 +360,8 @@ int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc) 984 return nr; 985 986 fail: 987- printf("nr=%d pc=%x\n", nr, pc); 988- printf("pc=%x %x\n", newpc[0], newpc[1]); 989+ printf("nr=%d pc=%lx\n", nr, pc); 990+ printf("pc=%lx %lx\n", newpc[0], newpc[1]); 991 return 0; 992 } 993 994@@ -304,17 +387,27 @@ fail: 995 * branches within the LL-SC sequence. 996 */ 997 #define inrange(x,lo,hi) ((x)<=(hi) && (x)>=(lo)) 998+/* Instruction encodings for atomic operations */ 999+#ifdef __mips64 1000+#define op_SC_p(op) (op == 0x38 || op == 0x3c) 1001+#define op_LL_p(op) (op == 0x30 || op == 0x34) 1002+#else /* !__mips64 */ 1003+#define op_SC_p(op) (op == 0x38) 1004+#define op_LL_p(op) (op == 0x30) 1005+#endif /* !__mips64 */ 1006+ 1007 static int 1008-mips_atomic_next_pcs(struct process *proc, uint32_t lladdr, uint32_t *newpcs) 1009+mips_atomic_next_pcs(struct process *proc, unsigned long lladdr, 1010+ unsigned long *newpcs) 1011 { 1012 int nr = 0; 1013 1014- uint32_t scaddr; 1015+ unsigned long scaddr; 1016 for (scaddr = lladdr + 4; scaddr - lladdr <= 2048; scaddr += 4) { 1017 /* Found SC, now stepover trailing branch */ 1018 uint32_t inst; 1019 if (proc_read_32(proc, (arch_addr_t)scaddr, &inst) >= 0 && 1020- itype_op(inst) == 0x38) { 1021+ op_SC_p (itype_op(inst))) { 1022 newpcs[nr++] = scaddr + 4; 1023 break; 1024 } 1025@@ -327,16 +420,16 @@ mips_atomic_next_pcs(struct process *proc, uint32_t lladdr, uint32_t *newpcs) 1026 } 1027 1028 /* Scan LL<->SC range for branches going outside that range */ 1029- uint32_t spc; 1030+ unsigned long spc; 1031 for (spc = lladdr + 4; spc < scaddr; spc += 4) { 1032- uint32_t scanpcs[2]; 1033+ unsigned long scanpcs[2]; 1034 int snr = mips_next_pcs(proc, spc, scanpcs); 1035 1036 int i; 1037 for (i = 0; i < snr; ++i) { 1038 if (!inrange(scanpcs[i], lladdr, scaddr)) { 1039- uint32_t *tmp = realloc(newpcs, (nr + 1) * 1040- sizeof *newpcs); 1041+ unsigned long *tmp = realloc(newpcs, (nr + 1) 1042+ * sizeof *newpcs); 1043 if (tmp == NULL) { 1044 perror("malloc atomic next pcs"); 1045 return -1; 1046@@ -357,8 +450,8 @@ arch_sw_singlestep(struct process *proc, struct breakpoint *bp, 1047 int (*add_cb)(arch_addr_t, struct sw_singlestep_data *), 1048 struct sw_singlestep_data *add_cb_data) 1049 { 1050- uint32_t pc = (uint32_t) get_instruction_pointer(proc); 1051- uint32_t *newpcs; 1052+ unsigned long pc = (unsigned long) get_instruction_pointer(proc); 1053+ unsigned long *newpcs; 1054 int nr; 1055 uint32_t inst; 1056 1057@@ -369,7 +462,7 @@ arch_sw_singlestep(struct process *proc, struct breakpoint *bp, 1058 return SWS_FAIL; 1059 1060 /* Starting an atomic read-modify-write sequence */ 1061- if (itype_op(inst) == 0x30) 1062+ if (op_LL_p(itype_op(inst))) 1063 nr = mips_atomic_next_pcs(proc, pc, newpcs); 1064 else 1065 nr = mips_next_pcs(proc, pc, newpcs); 1066@@ -462,7 +555,7 @@ gimme_arg(enum tof type, struct process *proc, int arg_num, 1067 debug(2,"ret = %#lx",addr); 1068 return addr; 1069 } 1070- ret = addr + 4*arg_num; 1071+ ret = addr + sizeof(long) * arg_num; 1072 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0); 1073 debug(2,"ret = %#lx",ret); 1074 return ret; 1075@@ -474,7 +567,7 @@ gimme_arg(enum tof type, struct process *proc, int arg_num, 1076 debug(2,"ret = %#lx",addr); 1077 return addr; 1078 } 1079- ret = addr + 4*arg_num; 1080+ ret = addr + sizeof(long) * arg_num; 1081 ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0); 1082 debug(2,"ret = %#lx",ret); 1083 return ret; 1084@@ -483,4 +576,34 @@ gimme_arg(enum tof type, struct process *proc, int arg_num, 1085 return 0; 1086 } 1087 1088+#ifdef __LP64__ 1089+size_t 1090+arch_type_sizeof(struct process *proc, struct arg_type_info *info) 1091+{ 1092+ if (proc == NULL) 1093+ return (size_t)-2; 1094+ 1095+ switch (info->type) { 1096+ case ARGTYPE_LONG: 1097+ case ARGTYPE_ULONG: 1098+ return proc->mask_32bit ? 4 : sizeof (long); 1099+ 1100+ case ARGTYPE_POINTER: 1101+ return proc->mask_32bit ? 4 : sizeof (void *); 1102+ 1103+ default: 1104+ /* Use default value. */ 1105+ return (size_t)-2; 1106+ } 1107+} 1108+ 1109+size_t 1110+arch_type_alignof(struct process *proc, struct arg_type_info *info) 1111+{ 1112+ if (proc == NULL) 1113+ return (size_t)-2; 1114+ 1115+ return arch_type_sizeof(proc, info); 1116+} 1117+#endif /* __LP64__ */ 1118 /**@}*/ 1119diff --git a/sysdeps/linux-gnu/mksyscallent_mips b/sysdeps/linux-gnu/mksyscallent_mips 1120index f3961b4..f8dcfe1 100755 1121--- a/sysdeps/linux-gnu/mksyscallent_mips 1122+++ b/sysdeps/linux-gnu/mksyscallent_mips 1123@@ -19,9 +19,7 @@ 1124 1125 # hack expression to generate arch/syscallent.h from <asm/unistd.h> 1126 # It reads from stdin and writes to stdout 1127-# It should work OK on i386,m68k,arm,ia64 1128-# It does NOT work in mips, s390 1129-# It is untested in other architectures 1130+# Default is o32; arch=mips64 generates n64 syscalls 1131 1132 BEGIN { 1133 max=0; 1134@@ -31,7 +29,10 @@ BEGIN { 1135 { 1136 #debug 1137 #printf("/%s/%s/%s/%s/\n", $1, $2, $3, $4); 1138- if ($2 ~ /__NR_Linux/ && $3 ~ /4000/) { 1139+ min=4000 1140+ if (arch ~ "mips64") min=5000 1141+ 1142+ if ($2 ~ /__NR_Linux/ && $3 ~ min) { 1143 syscall=1; 1144 } 1145 if ($2 ~ /__NR_Linux_syscalls/) { 1146-- 11472.13.2 1148 1149