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
get_arch_dep(struct process * proc)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
syscall_p(struct process * proc,int status,int * sysnum)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