1290f7d8cSRavi Bangoria // SPDX-License-Identifier: GPL-2.0+
2*58709f6fSBenjamin Gray 
3290f7d8cSRavi Bangoria #include <asm/unistd.h>
4*58709f6fSBenjamin Gray #include <linux/hw_breakpoint.h>
5*58709f6fSBenjamin Gray #include <linux/ptrace.h>
6*58709f6fSBenjamin Gray #include <memory.h>
7*58709f6fSBenjamin Gray #include <stdlib.h>
8290f7d8cSRavi Bangoria #include <sys/wait.h>
9290f7d8cSRavi Bangoria 
10*58709f6fSBenjamin Gray #include "utils.h"
11290f7d8cSRavi Bangoria 
12*58709f6fSBenjamin Gray /*
13*58709f6fSBenjamin Gray  * Child subroutine that performs a load on the address, then traps
14*58709f6fSBenjamin Gray  */
15*58709f6fSBenjamin Gray void same_watch_addr_child(unsigned long *addr);
16290f7d8cSRavi Bangoria 
17*58709f6fSBenjamin Gray /* Address of the ld instruction in same_watch_addr_child() */
18*58709f6fSBenjamin Gray extern char same_watch_addr_load[];
19290f7d8cSRavi Bangoria 
20*58709f6fSBenjamin Gray /* Address of the end trap instruction in same_watch_addr_child() */
21*58709f6fSBenjamin Gray extern char same_watch_addr_trap[];
22*58709f6fSBenjamin Gray 
23*58709f6fSBenjamin Gray /*
24*58709f6fSBenjamin Gray  * Child subroutine that performs a load on the first address, then a load on
25*58709f6fSBenjamin Gray  * the second address (with no instructions separating this from the first
26*58709f6fSBenjamin Gray  * load), then traps.
27*58709f6fSBenjamin Gray  */
28*58709f6fSBenjamin Gray void perf_then_ptrace_child(unsigned long *first_addr, unsigned long *second_addr);
29*58709f6fSBenjamin Gray 
30*58709f6fSBenjamin Gray /* Address of the first ld instruction in perf_then_ptrace_child() */
31*58709f6fSBenjamin Gray extern char perf_then_ptrace_load1[];
32*58709f6fSBenjamin Gray 
33*58709f6fSBenjamin Gray /* Address of the second ld instruction in perf_then_ptrace_child() */
34*58709f6fSBenjamin Gray extern char perf_then_ptrace_load2[];
35*58709f6fSBenjamin Gray 
36*58709f6fSBenjamin Gray /* Address of the end trap instruction in perf_then_ptrace_child() */
37*58709f6fSBenjamin Gray extern char perf_then_ptrace_trap[];
38*58709f6fSBenjamin Gray 
sys_ptrace(long request,pid_t pid,unsigned long addr,unsigned long data)39*58709f6fSBenjamin Gray static inline long sys_ptrace(long request, pid_t pid, unsigned long addr, unsigned long data)
40290f7d8cSRavi Bangoria {
41*58709f6fSBenjamin Gray 	return syscall(__NR_ptrace, request, pid, addr, data);
42290f7d8cSRavi Bangoria }
43290f7d8cSRavi Bangoria 
ptrace_traceme(void)44*58709f6fSBenjamin Gray static long ptrace_traceme(void)
45*58709f6fSBenjamin Gray {
46*58709f6fSBenjamin Gray 	return sys_ptrace(PTRACE_TRACEME, 0, 0, 0);
47290f7d8cSRavi Bangoria }
48290f7d8cSRavi Bangoria 
ptrace_getregs(pid_t pid,struct pt_regs * result)49*58709f6fSBenjamin Gray static long ptrace_getregs(pid_t pid, struct pt_regs *result)
50*58709f6fSBenjamin Gray {
51*58709f6fSBenjamin Gray 	return sys_ptrace(PTRACE_GETREGS, pid, 0, (unsigned long)result);
52*58709f6fSBenjamin Gray }
53*58709f6fSBenjamin Gray 
ptrace_setregs(pid_t pid,struct pt_regs * result)54*58709f6fSBenjamin Gray static long ptrace_setregs(pid_t pid, struct pt_regs *result)
55*58709f6fSBenjamin Gray {
56*58709f6fSBenjamin Gray 	return sys_ptrace(PTRACE_SETREGS, pid, 0, (unsigned long)result);
57*58709f6fSBenjamin Gray }
58*58709f6fSBenjamin Gray 
ptrace_cont(pid_t pid,long signal)59*58709f6fSBenjamin Gray static long ptrace_cont(pid_t pid, long signal)
60*58709f6fSBenjamin Gray {
61*58709f6fSBenjamin Gray 	return sys_ptrace(PTRACE_CONT, pid, 0, signal);
62*58709f6fSBenjamin Gray }
63*58709f6fSBenjamin Gray 
ptrace_singlestep(pid_t pid,long signal)64*58709f6fSBenjamin Gray static long ptrace_singlestep(pid_t pid, long signal)
65*58709f6fSBenjamin Gray {
66*58709f6fSBenjamin Gray 	return sys_ptrace(PTRACE_SINGLESTEP, pid, 0, signal);
67*58709f6fSBenjamin Gray }
68*58709f6fSBenjamin Gray 
ppc_ptrace_gethwdbginfo(pid_t pid,struct ppc_debug_info * dbginfo)69*58709f6fSBenjamin Gray static long ppc_ptrace_gethwdbginfo(pid_t pid, struct ppc_debug_info *dbginfo)
70*58709f6fSBenjamin Gray {
71*58709f6fSBenjamin Gray 	return sys_ptrace(PPC_PTRACE_GETHWDBGINFO, pid, 0, (unsigned long)dbginfo);
72*58709f6fSBenjamin Gray }
73*58709f6fSBenjamin Gray 
ppc_ptrace_sethwdbg(pid_t pid,struct ppc_hw_breakpoint * bp_info)74*58709f6fSBenjamin Gray static long ppc_ptrace_sethwdbg(pid_t pid, struct ppc_hw_breakpoint *bp_info)
75*58709f6fSBenjamin Gray {
76*58709f6fSBenjamin Gray 	return sys_ptrace(PPC_PTRACE_SETHWDEBUG, pid, 0, (unsigned long)bp_info);
77*58709f6fSBenjamin Gray }
78*58709f6fSBenjamin Gray 
ppc_ptrace_delhwdbg(pid_t pid,int bp_id)79*58709f6fSBenjamin Gray static long ppc_ptrace_delhwdbg(pid_t pid, int bp_id)
80*58709f6fSBenjamin Gray {
81*58709f6fSBenjamin Gray 	return sys_ptrace(PPC_PTRACE_DELHWDEBUG, pid, 0L, bp_id);
82*58709f6fSBenjamin Gray }
83*58709f6fSBenjamin Gray 
ptrace_getreg_pc(pid_t pid,void ** pc)84*58709f6fSBenjamin Gray static long ptrace_getreg_pc(pid_t pid, void **pc)
85*58709f6fSBenjamin Gray {
86*58709f6fSBenjamin Gray 	struct pt_regs regs;
87*58709f6fSBenjamin Gray 	long err;
88*58709f6fSBenjamin Gray 
89*58709f6fSBenjamin Gray 	err = ptrace_getregs(pid, &regs);
90*58709f6fSBenjamin Gray 	if (err)
91*58709f6fSBenjamin Gray 		return err;
92*58709f6fSBenjamin Gray 
93*58709f6fSBenjamin Gray 	*pc = (void *)regs.nip;
94*58709f6fSBenjamin Gray 
95*58709f6fSBenjamin Gray 	return 0;
96*58709f6fSBenjamin Gray }
97*58709f6fSBenjamin Gray 
ptrace_setreg_pc(pid_t pid,void * pc)98*58709f6fSBenjamin Gray static long ptrace_setreg_pc(pid_t pid, void *pc)
99*58709f6fSBenjamin Gray {
100*58709f6fSBenjamin Gray 	struct pt_regs regs;
101*58709f6fSBenjamin Gray 	long err;
102*58709f6fSBenjamin Gray 
103*58709f6fSBenjamin Gray 	err = ptrace_getregs(pid, &regs);
104*58709f6fSBenjamin Gray 	if (err)
105*58709f6fSBenjamin Gray 		return err;
106*58709f6fSBenjamin Gray 
107*58709f6fSBenjamin Gray 	regs.nip = (unsigned long)pc;
108*58709f6fSBenjamin Gray 
109*58709f6fSBenjamin Gray 	err = ptrace_setregs(pid, &regs);
110*58709f6fSBenjamin Gray 	if (err)
111*58709f6fSBenjamin Gray 		return err;
112*58709f6fSBenjamin Gray 
113*58709f6fSBenjamin Gray 	return 0;
114*58709f6fSBenjamin Gray }
115*58709f6fSBenjamin Gray 
perf_event_open(struct perf_event_attr * attr,pid_t pid,int cpu,int group_fd,unsigned long flags)116*58709f6fSBenjamin Gray static int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
117*58709f6fSBenjamin Gray 			   int group_fd, unsigned long flags)
118*58709f6fSBenjamin Gray {
119*58709f6fSBenjamin Gray 	return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
120*58709f6fSBenjamin Gray }
121*58709f6fSBenjamin Gray 
perf_user_event_attr_set(struct perf_event_attr * attr,void * addr,u64 len)122*58709f6fSBenjamin Gray static void perf_user_event_attr_set(struct perf_event_attr *attr, void *addr, u64 len)
123290f7d8cSRavi Bangoria {
124290f7d8cSRavi Bangoria 	memset(attr, 0, sizeof(struct perf_event_attr));
125*58709f6fSBenjamin Gray 
126290f7d8cSRavi Bangoria 	attr->type		= PERF_TYPE_BREAKPOINT;
127290f7d8cSRavi Bangoria 	attr->size		= sizeof(struct perf_event_attr);
128290f7d8cSRavi Bangoria 	attr->bp_type		= HW_BREAKPOINT_R;
129*58709f6fSBenjamin Gray 	attr->bp_addr		= (u64)addr;
130290f7d8cSRavi Bangoria 	attr->bp_len		= len;
131290f7d8cSRavi Bangoria 	attr->exclude_kernel	= 1;
132290f7d8cSRavi Bangoria 	attr->exclude_hv	= 1;
133290f7d8cSRavi Bangoria }
134290f7d8cSRavi Bangoria 
perf_watchpoint_open(pid_t child_pid,void * addr,u64 len)135*58709f6fSBenjamin Gray static int perf_watchpoint_open(pid_t child_pid, void *addr, u64 len)
136290f7d8cSRavi Bangoria {
137290f7d8cSRavi Bangoria 	struct perf_event_attr attr;
138290f7d8cSRavi Bangoria 
139290f7d8cSRavi Bangoria 	perf_user_event_attr_set(&attr, addr, len);
140*58709f6fSBenjamin Gray 	return perf_event_open(&attr, child_pid, -1, -1, 0);
141290f7d8cSRavi Bangoria }
142290f7d8cSRavi Bangoria 
perf_read_counter(int perf_fd,u64 * count)143*58709f6fSBenjamin Gray static int perf_read_counter(int perf_fd, u64 *count)
144290f7d8cSRavi Bangoria {
145*58709f6fSBenjamin Gray 	/*
146*58709f6fSBenjamin Gray 	 * A perf counter is retrieved by the read() syscall. It contains
147*58709f6fSBenjamin Gray 	 * the current count as 8 bytes that are interpreted as a u64
148*58709f6fSBenjamin Gray 	 */
149*58709f6fSBenjamin Gray 	ssize_t len = read(perf_fd, count, sizeof(*count));
150290f7d8cSRavi Bangoria 
151*58709f6fSBenjamin Gray 	if (len != sizeof(*count))
152*58709f6fSBenjamin Gray 		return -1;
153290f7d8cSRavi Bangoria 
154290f7d8cSRavi Bangoria 	return 0;
155290f7d8cSRavi Bangoria }
156290f7d8cSRavi Bangoria 
ppc_ptrace_init_breakpoint(struct ppc_hw_breakpoint * info,int type,void * addr,int len)157*58709f6fSBenjamin Gray static void ppc_ptrace_init_breakpoint(struct ppc_hw_breakpoint *info,
158*58709f6fSBenjamin Gray 				       int type, void *addr, int len)
159290f7d8cSRavi Bangoria {
160290f7d8cSRavi Bangoria 	info->version = 1;
161290f7d8cSRavi Bangoria 	info->trigger_type = type;
162290f7d8cSRavi Bangoria 	info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
163*58709f6fSBenjamin Gray 	info->addr = (u64)addr;
164*58709f6fSBenjamin Gray 	info->addr2 = (u64)addr + len;
165290f7d8cSRavi Bangoria 	info->condition_value = 0;
166290f7d8cSRavi Bangoria 	if (!len)
167290f7d8cSRavi Bangoria 		info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
168290f7d8cSRavi Bangoria 	else
169290f7d8cSRavi Bangoria 		info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
170290f7d8cSRavi Bangoria }
171290f7d8cSRavi Bangoria 
172*58709f6fSBenjamin Gray /*
173*58709f6fSBenjamin Gray  * Checks if we can place at least 2 watchpoints on the child process
174290f7d8cSRavi Bangoria  */
check_watchpoints(pid_t pid)175*58709f6fSBenjamin Gray static int check_watchpoints(pid_t pid)
176290f7d8cSRavi Bangoria {
177290f7d8cSRavi Bangoria 	struct ppc_debug_info dbginfo;
178290f7d8cSRavi Bangoria 
179*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ppc_ptrace_gethwdbginfo(pid, &dbginfo), "PPC_PTRACE_GETHWDBGINFO failed");
18068877ff2SBenjamin Gray 	SKIP_IF_MSG(dbginfo.num_data_bps <= 1, "Not enough data watchpoints (need at least 2)");
181290f7d8cSRavi Bangoria 
182*58709f6fSBenjamin Gray 	return 0;
183*58709f6fSBenjamin Gray }
184290f7d8cSRavi Bangoria 
185*58709f6fSBenjamin Gray /*
186*58709f6fSBenjamin Gray  * Wrapper around a plain fork() call that sets up the child for
187*58709f6fSBenjamin Gray  * ptrace-ing. Both the parent and child return from this, though
188*58709f6fSBenjamin Gray  * the child is stopped until ptrace_cont(pid) is run by the parent.
189*58709f6fSBenjamin Gray  */
ptrace_fork_child(pid_t * pid)190*58709f6fSBenjamin Gray static int ptrace_fork_child(pid_t *pid)
191*58709f6fSBenjamin Gray {
192*58709f6fSBenjamin Gray 	int status;
193290f7d8cSRavi Bangoria 
194*58709f6fSBenjamin Gray 	*pid = fork();
195*58709f6fSBenjamin Gray 
196*58709f6fSBenjamin Gray 	if (*pid < 0)
197*58709f6fSBenjamin Gray 		FAIL_IF_MSG(1, "Failed to fork child");
198*58709f6fSBenjamin Gray 
199*58709f6fSBenjamin Gray 	if (!*pid) {
200*58709f6fSBenjamin Gray 		FAIL_IF_EXIT_MSG(ptrace_traceme(), "PTRACE_TRACEME failed");
201*58709f6fSBenjamin Gray 		FAIL_IF_EXIT_MSG(raise(SIGSTOP), "Child failed to raise SIGSTOP");
202*58709f6fSBenjamin Gray 	} else {
203*58709f6fSBenjamin Gray 		/* Synchronise on child SIGSTOP */
204*58709f6fSBenjamin Gray 		FAIL_IF_MSG(waitpid(*pid, &status, 0) == -1, "Failed to wait for child");
205*58709f6fSBenjamin Gray 		FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
206*58709f6fSBenjamin Gray 	}
207*58709f6fSBenjamin Gray 
208*58709f6fSBenjamin Gray 	return 0;
209*58709f6fSBenjamin Gray }
210*58709f6fSBenjamin Gray 
211*58709f6fSBenjamin Gray /*
212*58709f6fSBenjamin Gray  * Tests the interaction between ptrace and perf watching the same data.
213*58709f6fSBenjamin Gray  *
214*58709f6fSBenjamin Gray  * We expect ptrace to take 'priority', as it is has before-execute
215*58709f6fSBenjamin Gray  * semantics.
216*58709f6fSBenjamin Gray  *
217*58709f6fSBenjamin Gray  * The perf counter should not be incremented yet because perf has after-execute
218*58709f6fSBenjamin Gray  * semantics. E.g., if ptrace changes the child PC, we don't even execute the
219*58709f6fSBenjamin Gray  * instruction at all.
220*58709f6fSBenjamin Gray  *
221*58709f6fSBenjamin Gray  * When the child is stopped for ptrace, we test both continue and single step.
222*58709f6fSBenjamin Gray  * Both should increment the perf counter. We also test changing the PC somewhere
223*58709f6fSBenjamin Gray  * different and stepping, which should not increment the perf counter.
224*58709f6fSBenjamin Gray  */
same_watch_addr_test(void)225*58709f6fSBenjamin Gray int same_watch_addr_test(void)
226*58709f6fSBenjamin Gray {
227*58709f6fSBenjamin Gray 	struct ppc_hw_breakpoint bp_info;	/* ptrace breakpoint info */
228*58709f6fSBenjamin Gray 	int bp_id;	/* Breakpoint handle of ptrace watchpoint */
229*58709f6fSBenjamin Gray 	int perf_fd;	/* File descriptor of perf performance counter */
230*58709f6fSBenjamin Gray 	u64 perf_count;	/* Most recently fetched perf performance counter value */
231*58709f6fSBenjamin Gray 	pid_t pid;	/* PID of child process */
232*58709f6fSBenjamin Gray 	void *pc;	/* Most recently fetched child PC value */
233*58709f6fSBenjamin Gray 	int status;	/* Stop status of child after waitpid */
234*58709f6fSBenjamin Gray 	unsigned long value;	/* Dummy value to be read/written to by child */
235*58709f6fSBenjamin Gray 	int err;
236*58709f6fSBenjamin Gray 
237*58709f6fSBenjamin Gray 	err = ptrace_fork_child(&pid);
238*58709f6fSBenjamin Gray 	if (err)
239*58709f6fSBenjamin Gray 		return err;
240*58709f6fSBenjamin Gray 
241*58709f6fSBenjamin Gray 	if (!pid) {
242*58709f6fSBenjamin Gray 		same_watch_addr_child(&value);
243*58709f6fSBenjamin Gray 		exit(1);
244*58709f6fSBenjamin Gray 	}
245*58709f6fSBenjamin Gray 
246*58709f6fSBenjamin Gray 	err = check_watchpoints(pid);
247*58709f6fSBenjamin Gray 	if (err)
248*58709f6fSBenjamin Gray 		return err;
249*58709f6fSBenjamin Gray 
250*58709f6fSBenjamin Gray 	/* Place a perf watchpoint counter on value */
251*58709f6fSBenjamin Gray 	perf_fd = perf_watchpoint_open(pid, &value, sizeof(value));
252*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_fd < 0, "Failed to open perf performance counter");
253*58709f6fSBenjamin Gray 
254*58709f6fSBenjamin Gray 	/* Place a ptrace watchpoint on value */
255*58709f6fSBenjamin Gray 	ppc_ptrace_init_breakpoint(&bp_info, PPC_BREAKPOINT_TRIGGER_READ, &value, sizeof(value));
256*58709f6fSBenjamin Gray 	bp_id = ppc_ptrace_sethwdbg(pid, &bp_info);
257*58709f6fSBenjamin Gray 	FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint");
258*58709f6fSBenjamin Gray 
259*58709f6fSBenjamin Gray 	/* Let the child run. It should stop on the ptrace watchpoint */
260*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
261*58709f6fSBenjamin Gray 
262*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
263*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
264*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
265*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load instruction");
266*58709f6fSBenjamin Gray 
267*58709f6fSBenjamin Gray 	/*
268*58709f6fSBenjamin Gray 	 * We stopped before executing the load, so perf should not have
269*58709f6fSBenjamin Gray 	 * recorded any events yet
270*58709f6fSBenjamin Gray 	 */
271*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
272*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 0, "perf recorded unexpected event");
273*58709f6fSBenjamin Gray 
274*58709f6fSBenjamin Gray 	/* Single stepping over the load should increment the perf counter */
275*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_singlestep(pid, 0), "Failed to single step child");
276*58709f6fSBenjamin Gray 
277*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
278*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
279*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
280*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_load + 4, "Failed to single step load instruction");
281*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
282*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 1, "perf counter did not increment");
283*58709f6fSBenjamin Gray 
284*58709f6fSBenjamin Gray 	/*
285*58709f6fSBenjamin Gray 	 * Set up a ptrace watchpoint on the value again and trigger it.
286*58709f6fSBenjamin Gray 	 * The perf counter should not have incremented because we do not
287*58709f6fSBenjamin Gray 	 * execute the load yet.
288*58709f6fSBenjamin Gray 	 */
289*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ppc_ptrace_delhwdbg(pid, bp_id), "Failed to remove old ptrace watchpoint");
290*58709f6fSBenjamin Gray 	bp_id = ppc_ptrace_sethwdbg(pid, &bp_info);
291*58709f6fSBenjamin Gray 	FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint");
292*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC");
293*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
294*58709f6fSBenjamin Gray 
295*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
296*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
297*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
298*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load trap");
299*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
300*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 1, "perf counter should not have changed");
301*58709f6fSBenjamin Gray 
302*58709f6fSBenjamin Gray 	/* Continuing over the load should increment the perf counter */
303*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
304*58709f6fSBenjamin Gray 
305*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
306*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
307*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
308*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap");
309*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
310*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 2, "perf counter did not increment");
311*58709f6fSBenjamin Gray 
312*58709f6fSBenjamin Gray 	/*
313*58709f6fSBenjamin Gray 	 * If we set the child PC back to the load instruction, then continue,
314*58709f6fSBenjamin Gray 	 * we should reach the end trap (because ptrace is one-shot) and have
315*58709f6fSBenjamin Gray 	 * another perf event.
316*58709f6fSBenjamin Gray 	 */
317*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC");
318*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
319*58709f6fSBenjamin Gray 
320*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
321*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
322*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
323*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap");
324*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
325*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 3, "perf counter did not increment");
326*58709f6fSBenjamin Gray 
327*58709f6fSBenjamin Gray 	/*
328*58709f6fSBenjamin Gray 	 * If we set the child PC back to the load instruction, set a ptrace
329*58709f6fSBenjamin Gray 	 * watchpoint on the load, then continue, we should immediately get
330*58709f6fSBenjamin Gray 	 * the ptrace trap without incrementing the perf counter
331*58709f6fSBenjamin Gray 	 */
332*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ppc_ptrace_delhwdbg(pid, bp_id), "Failed to remove old ptrace watchpoint");
333*58709f6fSBenjamin Gray 	bp_id = ppc_ptrace_sethwdbg(pid, &bp_info);
334*58709f6fSBenjamin Gray 	FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint");
335*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load), "Failed to set child PC");
336*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
337*58709f6fSBenjamin Gray 
338*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
339*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
340*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
341*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_load, "Child did not stop on load instruction");
342*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
343*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 3, "perf counter should not have changed");
344*58709f6fSBenjamin Gray 
345*58709f6fSBenjamin Gray 	/*
346*58709f6fSBenjamin Gray 	 * If we change the PC while stopped on the load instruction, we should
347*58709f6fSBenjamin Gray 	 * not increment the perf counter (because ptrace is before-execute,
348*58709f6fSBenjamin Gray 	 * perf is after-execute).
349*58709f6fSBenjamin Gray 	 */
350*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_setreg_pc(pid, same_watch_addr_load + 4), "Failed to set child PC");
351*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
352*58709f6fSBenjamin Gray 
353*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
354*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
355*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
356*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != same_watch_addr_trap, "Child did not stop on end trap");
357*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
358*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 3, "perf counter should not have changed");
359*58709f6fSBenjamin Gray 
360*58709f6fSBenjamin Gray 	/* Clean up child */
361*58709f6fSBenjamin Gray 	FAIL_IF_MSG(kill(pid, SIGKILL) != 0, "Failed to kill child");
362*58709f6fSBenjamin Gray 
363*58709f6fSBenjamin Gray 	return 0;
364*58709f6fSBenjamin Gray }
365*58709f6fSBenjamin Gray 
366*58709f6fSBenjamin Gray /*
367*58709f6fSBenjamin Gray  * Tests the interaction between ptrace and perf when:
368*58709f6fSBenjamin Gray  * 1. perf watches a value
369*58709f6fSBenjamin Gray  * 2. ptrace watches a different value
370*58709f6fSBenjamin Gray  * 3. The perf value is read, then the ptrace value is read immediately after
371*58709f6fSBenjamin Gray  *
372*58709f6fSBenjamin Gray  * A breakpoint implementation may accidentally misattribute/skip one of
373*58709f6fSBenjamin Gray  * the ptrace or perf handlers, as interrupt based work is done after perf
374*58709f6fSBenjamin Gray  * and before ptrace.
375*58709f6fSBenjamin Gray  *
376*58709f6fSBenjamin Gray  * We expect the perf counter to increment before the ptrace watchpoint
377*58709f6fSBenjamin Gray  * triggers.
378*58709f6fSBenjamin Gray  */
perf_then_ptrace_test(void)379*58709f6fSBenjamin Gray int perf_then_ptrace_test(void)
380*58709f6fSBenjamin Gray {
381*58709f6fSBenjamin Gray 	struct ppc_hw_breakpoint bp_info;	/* ptrace breakpoint info */
382*58709f6fSBenjamin Gray 	int bp_id;	/* Breakpoint handle of ptrace watchpoint */
383*58709f6fSBenjamin Gray 	int perf_fd;	/* File descriptor of perf performance counter */
384*58709f6fSBenjamin Gray 	u64 perf_count;	/* Most recently fetched perf performance counter value */
385*58709f6fSBenjamin Gray 	pid_t pid;	/* PID of child process */
386*58709f6fSBenjamin Gray 	void *pc;	/* Most recently fetched child PC value */
387*58709f6fSBenjamin Gray 	int status;	/* Stop status of child after waitpid */
388*58709f6fSBenjamin Gray 	unsigned long perf_value;	/* Dummy value to be watched by perf */
389*58709f6fSBenjamin Gray 	unsigned long ptrace_value;	/* Dummy value to be watched by ptrace */
390*58709f6fSBenjamin Gray 	int err;
391*58709f6fSBenjamin Gray 
392*58709f6fSBenjamin Gray 	err = ptrace_fork_child(&pid);
393*58709f6fSBenjamin Gray 	if (err)
394*58709f6fSBenjamin Gray 		return err;
395*58709f6fSBenjamin Gray 
396*58709f6fSBenjamin Gray 	/*
397*58709f6fSBenjamin Gray 	 * If we are the child, run a subroutine that reads the perf value,
398*58709f6fSBenjamin Gray 	 * then reads the ptrace value with consecutive load instructions
399*58709f6fSBenjamin Gray 	 */
400*58709f6fSBenjamin Gray 	if (!pid) {
401*58709f6fSBenjamin Gray 		perf_then_ptrace_child(&perf_value, &ptrace_value);
402*58709f6fSBenjamin Gray 		exit(0);
403*58709f6fSBenjamin Gray 	}
404*58709f6fSBenjamin Gray 
405*58709f6fSBenjamin Gray 	err = check_watchpoints(pid);
406*58709f6fSBenjamin Gray 	if (err)
407*58709f6fSBenjamin Gray 		return err;
408*58709f6fSBenjamin Gray 
409*58709f6fSBenjamin Gray 	/* Place a perf watchpoint counter */
410*58709f6fSBenjamin Gray 	perf_fd = perf_watchpoint_open(pid, &perf_value, sizeof(perf_value));
411*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_fd < 0, "Failed to open perf performance counter");
412*58709f6fSBenjamin Gray 
413*58709f6fSBenjamin Gray 	/* Place a ptrace watchpoint */
414*58709f6fSBenjamin Gray 	ppc_ptrace_init_breakpoint(&bp_info, PPC_BREAKPOINT_TRIGGER_READ,
415*58709f6fSBenjamin Gray 				   &ptrace_value, sizeof(ptrace_value));
416*58709f6fSBenjamin Gray 	bp_id = ppc_ptrace_sethwdbg(pid, &bp_info);
417*58709f6fSBenjamin Gray 	FAIL_IF_MSG(bp_id < 0, "Failed to set ptrace watchpoint");
418*58709f6fSBenjamin Gray 
419*58709f6fSBenjamin Gray 	/* Let the child run. It should stop on the ptrace watchpoint */
420*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_cont(pid, 0), "Failed to continue child");
421*58709f6fSBenjamin Gray 
422*58709f6fSBenjamin Gray 	FAIL_IF_MSG(waitpid(pid, &status, 0) == -1, "Failed to wait for child");
423*58709f6fSBenjamin Gray 	FAIL_IF_MSG(!WIFSTOPPED(status), "Child is not stopped");
424*58709f6fSBenjamin Gray 	FAIL_IF_MSG(ptrace_getreg_pc(pid, &pc), "Failed to get child PC");
425*58709f6fSBenjamin Gray 	FAIL_IF_MSG(pc != perf_then_ptrace_load2, "Child did not stop on ptrace load");
426*58709f6fSBenjamin Gray 
427*58709f6fSBenjamin Gray 	/* perf should have recorded the first load */
428*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_read_counter(perf_fd, &perf_count), "Failed to read perf counter");
429*58709f6fSBenjamin Gray 	FAIL_IF_MSG(perf_count != 1, "perf counter did not increment");
430*58709f6fSBenjamin Gray 
431*58709f6fSBenjamin Gray 	/* Clean up child */
432*58709f6fSBenjamin Gray 	FAIL_IF_MSG(kill(pid, SIGKILL) != 0, "Failed to kill child");
433*58709f6fSBenjamin Gray 
434*58709f6fSBenjamin Gray 	return 0;
435290f7d8cSRavi Bangoria }
436290f7d8cSRavi Bangoria 
main(int argc,char * argv[])437290f7d8cSRavi Bangoria int main(int argc, char *argv[])
438290f7d8cSRavi Bangoria {
439*58709f6fSBenjamin Gray 	int err = 0;
440*58709f6fSBenjamin Gray 
441*58709f6fSBenjamin Gray 	err |= test_harness(same_watch_addr_test, "same_watch_addr");
442*58709f6fSBenjamin Gray 	err |= test_harness(perf_then_ptrace_test, "perf_then_ptrace");
443*58709f6fSBenjamin Gray 
444*58709f6fSBenjamin Gray 	return err;
445290f7d8cSRavi Bangoria }
446