Linux Audio

Check our new training course

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