Linux Audio

Check our new training course

Loading...
v4.10.11
  1/*
  2 * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
  3 *
  4 * Licensed under the terms of the GNU GPL License version 2
  5 *
  6 * Selftests for breakpoints (and more generally the do_debug() path) in x86.
  7 */
  8
  9
 10#include <sys/ptrace.h>
 11#include <unistd.h>
 12#include <stddef.h>
 13#include <sys/user.h>
 14#include <stdio.h>
 15#include <stdlib.h>
 16#include <signal.h>
 17#include <sys/types.h>
 18#include <sys/wait.h>
 19
 20#include "../kselftest.h"
 21
 22
 23/* Breakpoint access modes */
 24enum {
 25	BP_X = 1,
 26	BP_RW = 2,
 27	BP_W = 4,
 28};
 29
 30static pid_t child_pid;
 31
 32/*
 33 * Ensures the child and parent are always "talking" about
 34 * the same test sequence. (ie: that we haven't forgotten
 35 * to call check_trapped() somewhere).
 36 */
 37static int nr_tests;
 38
 39static void set_breakpoint_addr(void *addr, int n)
 40{
 41	int ret;
 42
 43	ret = ptrace(PTRACE_POKEUSER, child_pid,
 44		     offsetof(struct user, u_debugreg[n]), addr);
 45	if (ret) {
 46		perror("Can't set breakpoint addr\n");
 47		ksft_exit_fail();
 48	}
 49}
 50
 51static void toggle_breakpoint(int n, int type, int len,
 52			      int local, int global, int set)
 53{
 54	int ret;
 55
 56	int xtype, xlen;
 57	unsigned long vdr7, dr7;
 58
 59	switch (type) {
 60	case BP_X:
 61		xtype = 0;
 62		break;
 63	case BP_W:
 64		xtype = 1;
 65		break;
 66	case BP_RW:
 67		xtype = 3;
 68		break;
 69	}
 70
 71	switch (len) {
 72	case 1:
 73		xlen = 0;
 74		break;
 75	case 2:
 76		xlen = 4;
 77		break;
 78	case 4:
 79		xlen = 0xc;
 80		break;
 81	case 8:
 82		xlen = 8;
 83		break;
 84	}
 85
 86	dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
 87		     offsetof(struct user, u_debugreg[7]), 0);
 88
 89	vdr7 = (xlen | xtype) << 16;
 90	vdr7 <<= 4 * n;
 91
 92	if (local) {
 93		vdr7 |= 1 << (2 * n);
 94		vdr7 |= 1 << 8;
 95	}
 96	if (global) {
 97		vdr7 |= 2 << (2 * n);
 98		vdr7 |= 1 << 9;
 99	}
100
101	if (set)
102		dr7 |= vdr7;
103	else
104		dr7 &= ~vdr7;
105
106	ret = ptrace(PTRACE_POKEUSER, child_pid,
107		     offsetof(struct user, u_debugreg[7]), dr7);
108	if (ret) {
109		perror("Can't set dr7");
110		ksft_exit_fail();
111	}
112}
113
114/* Dummy variables to test read/write accesses */
115static unsigned long long dummy_var[4];
116
117/* Dummy functions to test execution accesses */
118static void dummy_func(void) { }
119static void dummy_func1(void) { }
120static void dummy_func2(void) { }
121static void dummy_func3(void) { }
122
123static void (*dummy_funcs[])(void) = {
124	dummy_func,
125	dummy_func1,
126	dummy_func2,
127	dummy_func3,
128};
129
130static int trapped;
131
132static void check_trapped(void)
133{
134	/*
135	 * If we haven't trapped, wake up the parent
136	 * so that it notices the failure.
137	 */
138	if (!trapped)
139		kill(getpid(), SIGUSR1);
140	trapped = 0;
141
142	nr_tests++;
143}
144
145static void write_var(int len)
146{
147	char *pcval; short *psval; int *pival; long long *plval;
148	int i;
149
150	for (i = 0; i < 4; i++) {
151		switch (len) {
152		case 1:
153			pcval = (char *)&dummy_var[i];
154			*pcval = 0xff;
155			break;
156		case 2:
157			psval = (short *)&dummy_var[i];
158			*psval = 0xffff;
159			break;
160		case 4:
161			pival = (int *)&dummy_var[i];
162			*pival = 0xffffffff;
163			break;
164		case 8:
165			plval = (long long *)&dummy_var[i];
166			*plval = 0xffffffffffffffffLL;
167			break;
168		}
169		check_trapped();
170	}
171}
172
173static void read_var(int len)
174{
175	char cval; short sval; int ival; long long lval;
176	int i;
177
178	for (i = 0; i < 4; i++) {
179		switch (len) {
180		case 1:
181			cval = *(char *)&dummy_var[i];
182			break;
183		case 2:
184			sval = *(short *)&dummy_var[i];
185			break;
186		case 4:
187			ival = *(int *)&dummy_var[i];
188			break;
189		case 8:
190			lval = *(long long *)&dummy_var[i];
191			break;
192		}
193		check_trapped();
194	}
195}
196
197/*
198 * Do the r/w/x accesses to trigger the breakpoints. And run
199 * the usual traps.
200 */
201static void trigger_tests(void)
202{
203	int len, local, global, i;
204	char val;
205	int ret;
206
207	ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
208	if (ret) {
209		perror("Can't be traced?\n");
210		return;
211	}
212
213	/* Wake up father so that it sets up the first test */
214	kill(getpid(), SIGUSR1);
215
216	/* Test instruction breakpoints */
217	for (local = 0; local < 2; local++) {
218		for (global = 0; global < 2; global++) {
219			if (!local && !global)
220				continue;
221
222			for (i = 0; i < 4; i++) {
223				dummy_funcs[i]();
224				check_trapped();
225			}
226		}
227	}
228
229	/* Test write watchpoints */
230	for (len = 1; len <= sizeof(long); len <<= 1) {
231		for (local = 0; local < 2; local++) {
232			for (global = 0; global < 2; global++) {
233				if (!local && !global)
234					continue;
235				write_var(len);
236			}
237		}
238	}
239
240	/* Test read/write watchpoints (on read accesses) */
241	for (len = 1; len <= sizeof(long); len <<= 1) {
242		for (local = 0; local < 2; local++) {
243			for (global = 0; global < 2; global++) {
244				if (!local && !global)
245					continue;
246				read_var(len);
247			}
248		}
249	}
250
251	/* Icebp trap */
252	asm(".byte 0xf1\n");
253	check_trapped();
254
255	/* Int 3 trap */
256	asm("int $3\n");
257	check_trapped();
258
259	kill(getpid(), SIGUSR1);
260}
261
262static void check_success(const char *msg)
263{
264	const char *msg2;
265	int child_nr_tests;
266	int status;
267
268	/* Wait for the child to SIGTRAP */
269	wait(&status);
270
271	msg2 = "Failed";
272
273	if (WSTOPSIG(status) == SIGTRAP) {
274		child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
275					&nr_tests, 0);
276		if (child_nr_tests == nr_tests)
277			msg2 = "Ok";
278		if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
279			perror("Can't poke\n");
280			ksft_exit_fail();
281		}
282	}
283
284	nr_tests++;
285
286	printf("%s [%s]\n", msg, msg2);
287}
288
289static void launch_instruction_breakpoints(char *buf, int local, int global)
290{
291	int i;
292
293	for (i = 0; i < 4; i++) {
294		set_breakpoint_addr(dummy_funcs[i], i);
295		toggle_breakpoint(i, BP_X, 1, local, global, 1);
296		ptrace(PTRACE_CONT, child_pid, NULL, 0);
297		sprintf(buf, "Test breakpoint %d with local: %d global: %d",
298			i, local, global);
299		check_success(buf);
300		toggle_breakpoint(i, BP_X, 1, local, global, 0);
301	}
302}
303
304static void launch_watchpoints(char *buf, int mode, int len,
305			       int local, int global)
306{
307	const char *mode_str;
308	int i;
309
310	if (mode == BP_W)
311		mode_str = "write";
312	else
313		mode_str = "read";
314
315	for (i = 0; i < 4; i++) {
316		set_breakpoint_addr(&dummy_var[i], i);
317		toggle_breakpoint(i, mode, len, local, global, 1);
318		ptrace(PTRACE_CONT, child_pid, NULL, 0);
319		sprintf(buf, "Test %s watchpoint %d with len: %d local: "
320			"%d global: %d", mode_str, i, len, local, global);
321		check_success(buf);
322		toggle_breakpoint(i, mode, len, local, global, 0);
323	}
324}
325
326/* Set the breakpoints and check the child successfully trigger them */
327static void launch_tests(void)
328{
329	char buf[1024];
330	int len, local, global, i;
331
332	/* Instruction breakpoints */
333	for (local = 0; local < 2; local++) {
334		for (global = 0; global < 2; global++) {
335			if (!local && !global)
336				continue;
337			launch_instruction_breakpoints(buf, local, global);
338		}
339	}
340
341	/* Write watchpoint */
342	for (len = 1; len <= sizeof(long); len <<= 1) {
343		for (local = 0; local < 2; local++) {
344			for (global = 0; global < 2; global++) {
345				if (!local && !global)
346					continue;
347				launch_watchpoints(buf, BP_W, len,
348						   local, global);
349			}
350		}
351	}
352
353	/* Read-Write watchpoint */
354	for (len = 1; len <= sizeof(long); len <<= 1) {
355		for (local = 0; local < 2; local++) {
356			for (global = 0; global < 2; global++) {
357				if (!local && !global)
358					continue;
359				launch_watchpoints(buf, BP_RW, len,
360						   local, global);
361			}
362		}
363	}
364
365	/* Icebp traps */
366	ptrace(PTRACE_CONT, child_pid, NULL, 0);
367	check_success("Test icebp");
368
369	/* Int 3 traps */
370	ptrace(PTRACE_CONT, child_pid, NULL, 0);
371	check_success("Test int 3 trap");
372
373	ptrace(PTRACE_CONT, child_pid, NULL, 0);
374}
375
376int main(int argc, char **argv)
377{
378	pid_t pid;
379	int ret;
380
381	pid = fork();
382	if (!pid) {
383		trigger_tests();
384		return 0;
385	}
386
387	child_pid = pid;
388
389	wait(NULL);
390
391	launch_tests();
392
393	wait(NULL);
394
395	return ksft_exit_pass();
396}
v3.15
  1/*
  2 * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
  3 *
  4 * Licensed under the terms of the GNU GPL License version 2
  5 *
  6 * Selftests for breakpoints (and more generally the do_debug() path) in x86.
  7 */
  8
  9
 10#include <sys/ptrace.h>
 11#include <unistd.h>
 12#include <stddef.h>
 13#include <sys/user.h>
 14#include <stdio.h>
 15#include <stdlib.h>
 16#include <signal.h>
 17#include <sys/types.h>
 18#include <sys/wait.h>
 19
 
 
 20
 21/* Breakpoint access modes */
 22enum {
 23	BP_X = 1,
 24	BP_RW = 2,
 25	BP_W = 4,
 26};
 27
 28static pid_t child_pid;
 29
 30/*
 31 * Ensures the child and parent are always "talking" about
 32 * the same test sequence. (ie: that we haven't forgotten
 33 * to call check_trapped() somewhere).
 34 */
 35static int nr_tests;
 36
 37static void set_breakpoint_addr(void *addr, int n)
 38{
 39	int ret;
 40
 41	ret = ptrace(PTRACE_POKEUSER, child_pid,
 42		     offsetof(struct user, u_debugreg[n]), addr);
 43	if (ret) {
 44		perror("Can't set breakpoint addr\n");
 45		exit(-1);
 46	}
 47}
 48
 49static void toggle_breakpoint(int n, int type, int len,
 50			      int local, int global, int set)
 51{
 52	int ret;
 53
 54	int xtype, xlen;
 55	unsigned long vdr7, dr7;
 56
 57	switch (type) {
 58	case BP_X:
 59		xtype = 0;
 60		break;
 61	case BP_W:
 62		xtype = 1;
 63		break;
 64	case BP_RW:
 65		xtype = 3;
 66		break;
 67	}
 68
 69	switch (len) {
 70	case 1:
 71		xlen = 0;
 72		break;
 73	case 2:
 74		xlen = 4;
 75		break;
 76	case 4:
 77		xlen = 0xc;
 78		break;
 79	case 8:
 80		xlen = 8;
 81		break;
 82	}
 83
 84	dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
 85		     offsetof(struct user, u_debugreg[7]), 0);
 86
 87	vdr7 = (xlen | xtype) << 16;
 88	vdr7 <<= 4 * n;
 89
 90	if (local) {
 91		vdr7 |= 1 << (2 * n);
 92		vdr7 |= 1 << 8;
 93	}
 94	if (global) {
 95		vdr7 |= 2 << (2 * n);
 96		vdr7 |= 1 << 9;
 97	}
 98
 99	if (set)
100		dr7 |= vdr7;
101	else
102		dr7 &= ~vdr7;
103
104	ret = ptrace(PTRACE_POKEUSER, child_pid,
105		     offsetof(struct user, u_debugreg[7]), dr7);
106	if (ret) {
107		perror("Can't set dr7");
108		exit(-1);
109	}
110}
111
112/* Dummy variables to test read/write accesses */
113static unsigned long long dummy_var[4];
114
115/* Dummy functions to test execution accesses */
116static void dummy_func(void) { }
117static void dummy_func1(void) { }
118static void dummy_func2(void) { }
119static void dummy_func3(void) { }
120
121static void (*dummy_funcs[])(void) = {
122	dummy_func,
123	dummy_func1,
124	dummy_func2,
125	dummy_func3,
126};
127
128static int trapped;
129
130static void check_trapped(void)
131{
132	/*
133	 * If we haven't trapped, wake up the parent
134	 * so that it notices the failure.
135	 */
136	if (!trapped)
137		kill(getpid(), SIGUSR1);
138	trapped = 0;
139
140	nr_tests++;
141}
142
143static void write_var(int len)
144{
145	char *pcval; short *psval; int *pival; long long *plval;
146	int i;
147
148	for (i = 0; i < 4; i++) {
149		switch (len) {
150		case 1:
151			pcval = (char *)&dummy_var[i];
152			*pcval = 0xff;
153			break;
154		case 2:
155			psval = (short *)&dummy_var[i];
156			*psval = 0xffff;
157			break;
158		case 4:
159			pival = (int *)&dummy_var[i];
160			*pival = 0xffffffff;
161			break;
162		case 8:
163			plval = (long long *)&dummy_var[i];
164			*plval = 0xffffffffffffffffLL;
165			break;
166		}
167		check_trapped();
168	}
169}
170
171static void read_var(int len)
172{
173	char cval; short sval; int ival; long long lval;
174	int i;
175
176	for (i = 0; i < 4; i++) {
177		switch (len) {
178		case 1:
179			cval = *(char *)&dummy_var[i];
180			break;
181		case 2:
182			sval = *(short *)&dummy_var[i];
183			break;
184		case 4:
185			ival = *(int *)&dummy_var[i];
186			break;
187		case 8:
188			lval = *(long long *)&dummy_var[i];
189			break;
190		}
191		check_trapped();
192	}
193}
194
195/*
196 * Do the r/w/x accesses to trigger the breakpoints. And run
197 * the usual traps.
198 */
199static void trigger_tests(void)
200{
201	int len, local, global, i;
202	char val;
203	int ret;
204
205	ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
206	if (ret) {
207		perror("Can't be traced?\n");
208		return;
209	}
210
211	/* Wake up father so that it sets up the first test */
212	kill(getpid(), SIGUSR1);
213
214	/* Test instruction breakpoints */
215	for (local = 0; local < 2; local++) {
216		for (global = 0; global < 2; global++) {
217			if (!local && !global)
218				continue;
219
220			for (i = 0; i < 4; i++) {
221				dummy_funcs[i]();
222				check_trapped();
223			}
224		}
225	}
226
227	/* Test write watchpoints */
228	for (len = 1; len <= sizeof(long); len <<= 1) {
229		for (local = 0; local < 2; local++) {
230			for (global = 0; global < 2; global++) {
231				if (!local && !global)
232					continue;
233				write_var(len);
234			}
235		}
236	}
237
238	/* Test read/write watchpoints (on read accesses) */
239	for (len = 1; len <= sizeof(long); len <<= 1) {
240		for (local = 0; local < 2; local++) {
241			for (global = 0; global < 2; global++) {
242				if (!local && !global)
243					continue;
244				read_var(len);
245			}
246		}
247	}
248
249	/* Icebp trap */
250	asm(".byte 0xf1\n");
251	check_trapped();
252
253	/* Int 3 trap */
254	asm("int $3\n");
255	check_trapped();
256
257	kill(getpid(), SIGUSR1);
258}
259
260static void check_success(const char *msg)
261{
262	const char *msg2;
263	int child_nr_tests;
264	int status;
265
266	/* Wait for the child to SIGTRAP */
267	wait(&status);
268
269	msg2 = "Failed";
270
271	if (WSTOPSIG(status) == SIGTRAP) {
272		child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
273					&nr_tests, 0);
274		if (child_nr_tests == nr_tests)
275			msg2 = "Ok";
276		if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
277			perror("Can't poke\n");
278			exit(-1);
279		}
280	}
281
282	nr_tests++;
283
284	printf("%s [%s]\n", msg, msg2);
285}
286
287static void launch_instruction_breakpoints(char *buf, int local, int global)
288{
289	int i;
290
291	for (i = 0; i < 4; i++) {
292		set_breakpoint_addr(dummy_funcs[i], i);
293		toggle_breakpoint(i, BP_X, 1, local, global, 1);
294		ptrace(PTRACE_CONT, child_pid, NULL, 0);
295		sprintf(buf, "Test breakpoint %d with local: %d global: %d",
296			i, local, global);
297		check_success(buf);
298		toggle_breakpoint(i, BP_X, 1, local, global, 0);
299	}
300}
301
302static void launch_watchpoints(char *buf, int mode, int len,
303			       int local, int global)
304{
305	const char *mode_str;
306	int i;
307
308	if (mode == BP_W)
309		mode_str = "write";
310	else
311		mode_str = "read";
312
313	for (i = 0; i < 4; i++) {
314		set_breakpoint_addr(&dummy_var[i], i);
315		toggle_breakpoint(i, mode, len, local, global, 1);
316		ptrace(PTRACE_CONT, child_pid, NULL, 0);
317		sprintf(buf, "Test %s watchpoint %d with len: %d local: "
318			"%d global: %d", mode_str, i, len, local, global);
319		check_success(buf);
320		toggle_breakpoint(i, mode, len, local, global, 0);
321	}
322}
323
324/* Set the breakpoints and check the child successfully trigger them */
325static void launch_tests(void)
326{
327	char buf[1024];
328	int len, local, global, i;
329
330	/* Instruction breakpoints */
331	for (local = 0; local < 2; local++) {
332		for (global = 0; global < 2; global++) {
333			if (!local && !global)
334				continue;
335			launch_instruction_breakpoints(buf, local, global);
336		}
337	}
338
339	/* Write watchpoint */
340	for (len = 1; len <= sizeof(long); len <<= 1) {
341		for (local = 0; local < 2; local++) {
342			for (global = 0; global < 2; global++) {
343				if (!local && !global)
344					continue;
345				launch_watchpoints(buf, BP_W, len,
346						   local, global);
347			}
348		}
349	}
350
351	/* Read-Write watchpoint */
352	for (len = 1; len <= sizeof(long); len <<= 1) {
353		for (local = 0; local < 2; local++) {
354			for (global = 0; global < 2; global++) {
355				if (!local && !global)
356					continue;
357				launch_watchpoints(buf, BP_RW, len,
358						   local, global);
359			}
360		}
361	}
362
363	/* Icebp traps */
364	ptrace(PTRACE_CONT, child_pid, NULL, 0);
365	check_success("Test icebp");
366
367	/* Int 3 traps */
368	ptrace(PTRACE_CONT, child_pid, NULL, 0);
369	check_success("Test int 3 trap");
370
371	ptrace(PTRACE_CONT, child_pid, NULL, 0);
372}
373
374int main(int argc, char **argv)
375{
376	pid_t pid;
377	int ret;
378
379	pid = fork();
380	if (!pid) {
381		trigger_tests();
382		return 0;
383	}
384
385	child_pid = pid;
386
387	wait(NULL);
388
389	launch_tests();
390
391	wait(NULL);
392
393	return 0;
394}