From 69499587c60a2ae24aa358f40e17ae8f92750d0a Mon Sep 17 00:00:00 2001 From: Weimin Pan Date: Mon, 11 Feb 2019 16:07:09 -0800 Subject: [PATCH PR gdb/21870] aarch64: Leftover uncleared debug registers Adding a test case gdb/testsuite/ChangeLog 2019-02-11 Weimin Pan PR breakpoints/21870 * gdb.arch/aarch64-dbreg-contents.exp: New file. * gdb.arch/aarch64-dbreg-contents.c: New file. --- gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c | 129 ++++++++++++++++++++++ gdb/testsuite/gdb.arch/aarch64-dbreg-contents.exp | 46 ++++++++ 2 files changed, 175 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-dbreg-contents.exp diff --git a/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c b/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c new file mode 100644 index 0000000..753037d --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c @@ -0,0 +1,129 @@ + +/* Test case for setting a memory-write unaligned watchpoint on aarch64. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. */ + +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include +#include + +static __attribute__((unused)) pid_t child; + +static __attribute__((unused)) void +cleanup (void) +{ + if (child > 0) + kill (child, SIGKILL); + child = 0; +} + +#define SET_WATCHPOINT set_watchpoint + +/* Macros to extract fields from the hardware debug information word. */ +#define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff) +#define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff) +/* Macro for the expected version of the ARMv8-A debug architecture. */ +#define AARCH64_DEBUG_ARCH_V8 0x6 +#define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1) +#define DR_CONTROL_LENGTH(ctrl) (((ctrl) >> 5) & 0xff) + +static void +set_watchpoint (pid_t pid, volatile void *addr, unsigned len_mask) +{ + struct user_hwdebug_state dreg_state; + struct iovec iov; + long l; + + assert (len_mask >= 0x01); + assert (len_mask <= 0xff); + + iov.iov_base = &dreg_state; + iov.iov_len = sizeof (dreg_state); + errno = 0; + l = ptrace (PTRACE_GETREGSET, pid, NT_ARM_HW_WATCH, &iov); + assert (l == 0); + assert (AARCH64_DEBUG_ARCH (dreg_state.dbg_info) == AARCH64_DEBUG_ARCH_V8); + assert (AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info) >= 1); + + assert (!DR_CONTROL_ENABLED (dreg_state.dbg_regs[0].ctrl)); + dreg_state.dbg_regs[0].ctrl |= 1; + assert ( DR_CONTROL_ENABLED (dreg_state.dbg_regs[0].ctrl)); + + assert (DR_CONTROL_LENGTH (dreg_state.dbg_regs[0].ctrl) == 0); + dreg_state.dbg_regs[0].ctrl |= len_mask << 5; + assert (DR_CONTROL_LENGTH (dreg_state.dbg_regs[0].ctrl) == len_mask); + + dreg_state.dbg_regs[0].ctrl |= 2 << 3; // write + dreg_state.dbg_regs[0].ctrl |= 2 << 1; // GDB: ???: enabled at el0 + dreg_state.dbg_regs[0].addr = (uintptr_t) addr; + + iov.iov_base = &dreg_state; + iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs) + + sizeof (dreg_state.dbg_regs[0])); + errno = 0; + l = ptrace (PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov); + if (errno != 0) + error (1, errno, "PTRACE_SETREGSET: NT_ARM_HW_WATCH"); + assert (l == 0); +} + +static volatile long long check; + +int +main (void) +{ + pid_t got_pid; + int i, status; + long l; + + atexit (cleanup); + + child = fork (); + assert (child >= 0); + if (child == 0) + { + l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + assert (l == 0); + i = raise (SIGUSR1); + assert (i == 0); + check = -1; + i = raise (SIGUSR2); + /* NOTREACHED */ + assert (0); + } + + got_pid = waitpid (child, &status, 0); + assert (got_pid == child); + assert (WIFSTOPPED (status)); + assert (WSTOPSIG (status) == SIGUSR1); + + errno = 0; + l = ptrace (PTRACE_CONT, child, 0l, 0l); + assert_perror (errno); + assert (l == 0); + + got_pid = waitpid (child, &status, 0); + assert (got_pid == child); + assert (WIFSTOPPED (status)); + if (WSTOPSIG (status) == SIGUSR2) + { + /* We missed the watchpoint - unsupported by hardware? */ + cleanup (); + return 2; + } + assert (WSTOPSIG (status) == SIGTRAP); + + cleanup (); + return 0; +} diff --git a/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.exp b/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.exp new file mode 100644 index 0000000..f6bee02 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.exp @@ -0,0 +1,46 @@ +# Copyright 2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Make sure that the inferior doesn't assert and exits successfully. +# +# This test checks that GDB does not alter watchpoints set by an inferior. +# It sets a watchpoint on memory then writes to the watched memory. +# It will exit with 1 if the watchpoint is not reached. +# +# See PR breakpoints/21870. + +if {![is_aarch64_target]} { + verbose "Skipping ${gdb_test_file_name}." + return +} + +standard_testfile .c + +if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable {debug}] != "" } { + untested "failed to compile" + return -1 +} + +clean_restart $testfile + +set test "run to exit" +gdb_test_multiple "run" "$test" { + -re "exited with code 01.*$gdb_prompt $" { + pass "$test" + } + -re "exited normally.*$gdb_prompt $" { + pass "$test" + } +} -- 1.9.1