// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> * * Selftests for breakpoints (and more generally the do_debug() path) in x86.
*/
/* * Ensures the child and parent are always "talking" about * the same test sequence. (ie: that we haven't forgotten * to call check_trapped() somewhere).
*/ staticint nr_tests;
staticvoid set_breakpoint_addr(void *addr, int n)
{ int ret;
ret = ptrace(PTRACE_POKEUSER, child_pid,
offsetof(struct user, u_debugreg[n]), addr); if (ret)
ksft_exit_fail_msg("Can't set breakpoint addr: %s\n",
strerror(errno));
}
staticvoid toggle_breakpoint(int n, int type, int len, int local, int global, int set)
{ int ret;
int xtype, xlen; unsignedlong vdr7, dr7;
switch (type) { case BP_X:
xtype = 0; break; case BP_W:
xtype = 1; break; case BP_RW:
xtype = 3; break;
}
staticvoid check_trapped(void)
{ /* * If we haven't trapped, wake up the parent * so that it notices the failure.
*/ if (!trapped)
kill(getpid(), SIGUSR1);
trapped = 0;
nr_tests++;
}
staticvoid write_var(int len)
{ char *pcval; short *psval; int *pival; longlong *plval; int i;
/* * Do the r/w/x accesses to trigger the breakpoints. And run * the usual traps.
*/ staticvoid trigger_tests(void)
{ int len, local, global, i; char val; int ret;
ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); if (ret) {
ksft_print_msg("Can't be traced? %s\n", strerror(errno)); return;
}
/* Wake up father so that it sets up the first test */
kill(getpid(), SIGUSR1);
/* Test instruction breakpoints */ for (local = 0; local < 2; local++) { for (global = 0; global < 2; global++) { if (!local && !global) continue;
for (i = 0; i < COUNT_ISN_BPS; i++) {
dummy_funcs[i]();
check_trapped();
}
}
}
/* Test write watchpoints */ for (len = 1; len <= sizeof(long); len <<= 1) { for (local = 0; local < 2; local++) { for (global = 0; global < 2; global++) { if (!local && !global) continue;
write_var(len);
}
}
}
/* Test read/write watchpoints (on read accesses) */ for (len = 1; len <= sizeof(long); len <<= 1) { for (local = 0; local < 2; local++) { for (global = 0; global < 2; global++) { if (!local && !global) continue;
read_var(len);
}
}
}
for (i = 0; i < COUNT_WPS; i++) {
set_breakpoint_addr(&dummy_var[i], i);
toggle_breakpoint(i, mode, len, local, global, 1);
ptrace(PTRACE_CONT, child_pid, NULL, 0);
sprintf(buf, "Test %s watchpoint %d with len: %d local: %d global: %d\n",
mode_str, i, len, local, global);
check_success(buf);
toggle_breakpoint(i, mode, len, local, global, 0);
}
}
/* Set the breakpoints and check the child successfully trigger them */ staticvoid launch_tests(void)
{ char buf[1024]; unsignedint tests = 0; int len, local, global, i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.