1 /* 2 * This file is part of ltrace. 3 * Copyright (C) 2014 Petr Machata, Red Hat, Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 */ 20 21 #include <sys/ptrace.h> 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 #include <asm/ptrace.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <errno.h> 28 29 #include "backend.h" 30 #include "proc.h" 31 32 void 33 get_arch_dep(struct process *proc) 34 { 35 } 36 37 int aarch64_read_gregs(struct process *proc, struct user_pt_regs *regs); 38 39 /* The syscall instruction is: 40 * | 31 21 | 20 5 | 4 0 | 41 * | 1 1 0 1 0 1 0 0 | 0 0 0 | imm16 | 0 0 0 0 1 | */ 42 #define SVC_MASK 0xffe0001f 43 #define SVC_VALUE 0xd4000001 44 45 int 46 syscall_p(struct process *proc, int status, int *sysnum) 47 { 48 if (WIFSTOPPED(status) 49 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 50 51 struct user_pt_regs regs; 52 if (aarch64_read_gregs(proc, ®s) < 0) { 53 fprintf(stderr, "syscall_p: " 54 "Couldn't read registers of %d.\n", proc->pid); 55 return -1; 56 } 57 58 errno = 0; 59 unsigned long insn = (unsigned long) ptrace(PTRACE_PEEKTEXT, 60 proc->pid, 61 regs.pc - 4, 0); 62 if (insn == -1UL && errno != 0) { 63 fprintf(stderr, "syscall_p: " 64 "Couldn't peek into %d: %s\n", proc->pid, 65 strerror(errno)); 66 return -1; 67 } 68 69 insn &= 0xffffffffUL; 70 if ((insn & SVC_MASK) == SVC_VALUE) { 71 *sysnum = regs.regs[8]; 72 73 size_t d1 = proc->callstack_depth - 1; 74 if (proc->callstack_depth > 0 75 && proc->callstack[d1].is_syscall 76 && proc->callstack[d1].c_un.syscall == *sysnum) 77 return 2; 78 79 return 1; 80 } 81 } 82 83 return 0; 84 } 85