brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · d46962a Raw
410 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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	424#define COUNT_WPS	425 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" about37 * the same test sequence. (ie: that we haven't forgotten38 * 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	else106		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 parent138	 * 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 run201 * 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("%s", msg);288	else289		ksft_test_result_fail("%s", 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	else316		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}410