Home | History | Annotate | Download | only in aarch64
      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, &regs) < 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