Merge "Update to kernel headers v4.9.3."
diff --git a/libc/Android.bp b/libc/Android.bp
index 4df94a0..ec00f28 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1869,6 +1869,21 @@
],
}
+cc_object {
+ name: "kuser_helper_on",
+ local_include_dirs: ["include"],
+ arch: {
+ arm: {
+ srcs: ["arch-arm/bionic/kuser_helper_on.S"],
+ },
+ },
+
+ defaults: [
+ "crt_defaults",
+ "crt_so_defaults",
+ ],
+}
+
// Android.mk:ignore
cc_object {
name: "crtbegin_so1",
@@ -1893,6 +1908,11 @@
"crtbegin_so1",
"crtbrand",
],
+ arch: {
+ arm: {
+ objs: ["kuser_helper_on"],
+ },
+ },
}
// Android.mk:ignore
@@ -1951,6 +1971,11 @@
"crtbegin_static1",
"crtbrand",
],
+ arch: {
+ arm: {
+ objs: ["kuser_helper_on"],
+ },
+ },
defaults: ["crt_defaults"],
}
@@ -1997,6 +2022,11 @@
"crtbegin_dynamic1",
"crtbrand",
],
+ arch: {
+ arm: {
+ objs: ["kuser_helper_on"],
+ },
+ },
defaults: ["crt_defaults"],
}
diff --git a/libc/NOTICE b/libc/NOTICE
index fd6cee6..1b996e9 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -932,6 +932,50 @@
-------------------------------------------------------------------
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2017 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
Copyright (c) 1980, 1983, 1988, 1993
The Regents of the University of California. All rights reserved.
diff --git a/libc/arch-arm/bionic/kuser_helper_on.S b/libc/arch-arm/bionic/kuser_helper_on.S
new file mode 100644
index 0000000..e59d0d5
--- /dev/null
+++ b/libc/arch-arm/bionic/kuser_helper_on.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+ .section .note.android.kuser_helper_off,"a",%note
+ .align 2
+ .type abitag, %object
+abitag:
+ .long 2f-1f /* int32_t namesz */
+ .long 3f-2f /* int32_t descsz */
+ .long 3 /* int32_t type */
+1: .ascii "Android\0" /* char name[] */
+2: .long 1 /* int32_t on */
+3:
+ .size abitag, .-abitag
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index 7182ca6..37c1891 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -71,7 +71,7 @@
unsigned dns_netid;
unsigned dns_mark;
uid_t uid;
-} __attribute__((packed));
+};
#define NET_CONTEXT_INVALID_UID ((uid_t)-1)
diff --git a/libc/dns/include/resolv_params.h b/libc/dns/include/resolv_params.h
index 5ee265f..49ae691 100644
--- a/libc/dns/include/resolv_params.h
+++ b/libc/dns/include/resolv_params.h
@@ -41,6 +41,6 @@
uint8_t success_threshold; // 0: disable, value / 100 otherwise
uint8_t min_samples; // min # samples needed for statistics to be considered meaningful
uint8_t max_samples; // max # samples taken into account for statistics
-} __attribute__((__packed__));
+};
#endif // _RESOLV_PARAMS_H
diff --git a/libc/seccomp/arm64_policy.c b/libc/seccomp/arm64_policy.c
index d5a87d6..6a8bda0 100644
--- a/libc/seccomp/arm64_policy.c
+++ b/libc/seccomp/arm64_policy.c
@@ -41,7 +41,7 @@
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 268, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 267, 1, 2), //clock_adjtime
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 272, 0, 1), //setns|sendmmsg|process_vm_readv|process_vm_writev
-BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
diff --git a/libc/seccomp/arm_policy.c b/libc/seccomp/arm_policy.c
index 44e734e..de03f45 100644
--- a/libc/seccomp/arm_policy.c
+++ b/libc/seccomp/arm_policy.c
@@ -139,7 +139,7 @@
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983045, 1, 0),
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983043, 1, 2), //__ARM_NR_cacheflush
BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 983046, 0, 1), //__ARM_NR_set_tls
-BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
+BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index b82bb12..bd003a3 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -126,7 +126,7 @@
", 0, " + str(len(bpf)) + "),")
# Add the error and allow calls at the end
- bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),")
+ bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP),")
bpf.append("BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),")
# And output policy
diff --git a/linker/Android.bp b/linker/Android.bp
index 6d93571..5c205d5 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -22,6 +22,7 @@
"linker_gdb_support.cpp",
"linker_globals.cpp",
"linker_libc_support.c",
+ "linker_libcxx_support.cpp",
"linker_main.cpp",
"linker_namespaces.cpp",
"linker_logger.cpp",
@@ -111,6 +112,7 @@
static_libs: [
"libc_nomalloc",
+ "libm",
"libziparchive",
"libutils",
"libbase",
diff --git a/linker/linker_libcxx_support.cpp b/linker/linker_libcxx_support.cpp
new file mode 100644
index 0000000..0efe4d8
--- /dev/null
+++ b/linker/linker_libcxx_support.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "private/libc_logging.h"
+
+void* __find_icu_symbol(const char* symbol_name __attribute__((__unused__))) {
+ __libc_fatal("__find_icu_symbol should not be called in the linker");
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index 64a5c30..2ccdbf8 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -179,32 +179,6 @@
}
cc_test_library {
- name: "libfortify1-tests-gcc",
- defaults: ["bionic_fortify_tests_defaults", "bionic_tests_defaults"],
- clang: false,
- cflags: [
- "-D_FORTIFY_SOURCE=1",
- "-DTEST_NAME=Fortify1_gcc"
- ],
- shared: {
- enabled: false,
- },
-}
-
-cc_test_library {
- name: "libfortify2-tests-gcc",
- defaults: ["bionic_fortify_tests_defaults", "bionic_tests_defaults"],
- clang: false,
- cflags: [
- "-D_FORTIFY_SOURCE=2",
- "-DTEST_NAME=Fortify2_gcc"
- ],
- shared: {
- enabled: false,
- },
-}
-
-cc_test_library {
name: "libfortify1-tests-clang",
defaults: ["bionic_fortify_tests_defaults", "bionic_tests_defaults"],
clang: true,
@@ -238,8 +212,6 @@
defaults: ["bionic_tests_defaults"],
whole_static_libs: [
"libBionicStandardTests",
- "libfortify1-tests-gcc",
- "libfortify2-tests-gcc",
"libfortify1-tests-clang",
"libfortify2-tests-clang",
],
@@ -412,12 +384,6 @@
},
}
-cc_test {
- name: "bionic-unit-tests-gcc",
- defaults: ["bionic_unit_tests_defaults", "bionic_tests_defaults"],
- clang: false,
-}
-
// -----------------------------------------------------------------------------
// Tests for the device linked against bionic's static library. Run with:
// adb shell /data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static32
@@ -484,8 +450,6 @@
whole_static_libs: [
"libBionicStandardTests",
"libBionicGtestMain",
- "libfortify1-tests-gcc",
- "libfortify2-tests-gcc",
"libfortify1-tests-clang",
"libfortify2-tests-clang",
],
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 2e4d635..a56e3a7 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -921,7 +921,25 @@
#else
#define PATH_TO_SYSTEM_LIB "/system/lib/"
#endif
+#if defined (__aarch64__)
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm64/"
+#elif defined (__arm__)
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/arm/"
+#elif defined (__i386__)
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86/"
+#elif defined (__x86_64__)
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/x86_64/"
+#elif defined (__mips__)
+#if defined(__LP64__)
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips64/"
+#else
+#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib/mips/"
+#endif
+#else
+#error "Unknown architecture"
+#endif
#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
+#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
TEST(dlfcn, dladdr_libc) {
#if defined(__BIONIC__)
@@ -929,9 +947,18 @@
void* addr = reinterpret_cast<void*>(puts); // well-known libc function
ASSERT_TRUE(dladdr(addr, &info) != 0);
- // /system/lib is symlink when this test is executed on host.
char libc_realpath[PATH_MAX];
- ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
+
+ // Check if libc is in canonical path or in alternate path.
+ if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB,
+ info.dli_fname,
+ sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) {
+ // Platform with emulated architecture. Symlink on ARC++.
+ ASSERT_TRUE(realpath(ALTERNATE_PATH_TO_LIBC, libc_realpath) == libc_realpath);
+ } else {
+ // /system/lib is symlink when this test is executed on host.
+ ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath);
+ }
ASSERT_STREQ(libc_realpath, info.dli_fname);
// TODO: add check for dfi_fbase
@@ -1248,8 +1275,14 @@
}
void validate_compatibility_of_native_library(const char* soname) {
- std::string path = std::string(PATH_TO_SYSTEM_LIB) + soname;
+ // On the systems with emulation system libraries would be of different
+ // architecture. Try to use alternate paths first.
+ std::string path = std::string(ALTERNATE_PATH_TO_SYSTEM_LIB) + soname;
auto binary_or_error = llvm::object::createBinary(path);
+ if (!binary_or_error) {
+ path = std::string(PATH_TO_SYSTEM_LIB) + soname;
+ binary_or_error = llvm::object::createBinary(path);
+ }
ASSERT_FALSE(!binary_or_error);
llvm::object::Binary* binary = binary_or_error.get().getBinary();
diff --git a/tests/sys_ptrace_test.cpp b/tests/sys_ptrace_test.cpp
index bdd6a89..7483754 100644
--- a/tests/sys_ptrace_test.cpp
+++ b/tests/sys_ptrace_test.cpp
@@ -30,8 +30,8 @@
#define TRAP_HWBKPT 4
#endif
-template<typename T>
-static void __attribute__((noreturn)) fork_child(unsigned cpu, T &data) {
+template <typename T>
+static void __attribute__((noreturn)) watchpoint_fork_child(unsigned cpu, T& data) {
// Extra precaution: make sure we go away if anything happens to our parent.
if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) == -1) {
perror("prctl(PR_SET_PDEATHSIG)");
@@ -71,7 +71,9 @@
pid_t pid;
};
-static bool are_watchpoints_supported(pid_t child) {
+enum class HwFeature { Watchpoint, Breakpoint };
+
+static bool is_hw_feature_supported(pid_t child, HwFeature feature) {
#if defined(__arm__)
long capabilities;
long result = ptrace(PTRACE_GETHBPREGS, child, 0, &capabilities);
@@ -79,26 +81,34 @@
EXPECT_EQ(EIO, errno);
return false;
}
- return ((capabilities >> 8) & 0xff) > 0;
+ switch (feature) {
+ case HwFeature::Watchpoint:
+ return ((capabilities >> 8) & 0xff) > 0;
+ case HwFeature::Breakpoint:
+ return (capabilities & 0xff) > 0;
+ }
#elif defined(__aarch64__)
user_hwdebug_state dreg_state;
iovec iov;
iov.iov_base = &dreg_state;
iov.iov_len = sizeof(dreg_state);
- long result = ptrace(PTRACE_GETREGSET, child, NT_ARM_HW_WATCH, &iov);
+ long result = ptrace(PTRACE_GETREGSET, child,
+ feature == HwFeature::Watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK, &iov);
if (result == -1) {
EXPECT_EQ(EINVAL, errno);
return false;
}
return (dreg_state.dbg_info & 0xff) > 0;
#elif defined(__i386__) || defined(__x86_64__)
- // We assume watchpoints are always supported on x86.
+ // We assume watchpoints and breakpoints are always supported on x86.
(void) child;
+ (void)feature;
return true;
#else
// TODO: mips support.
(void) child;
+ (void)feature;
return false;
#endif
}
@@ -153,7 +163,7 @@
pid_t child = fork();
ASSERT_NE(-1, child) << strerror(errno);
- if (child == 0) fork_child(cpu, data);
+ if (child == 0) watchpoint_fork_child(cpu, data);
ChildGuard guard(child);
@@ -162,7 +172,10 @@
ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
- if (!are_watchpoints_supported(child)) return;
+ if (!is_hw_feature_supported(child, HwFeature::Watchpoint)) {
+ GTEST_LOG_(INFO) << "Skipping test because hardware support is not available.\n";
+ return;
+ }
set_watchpoint(child, &data, sizeof data);
@@ -191,7 +204,7 @@
// Test watchpoint API. The test is considered successful if our watchpoints get hit OR the
// system reports that watchpoint support is not present. We run the test for different
// watchpoint sizes, while pinning the process to each cpu in turn, for better coverage.
-TEST(ptrace, watchpoint_stress) {
+TEST(sys_ptrace, watchpoint_stress) {
cpu_set_t available_cpus;
ASSERT_EQ(0, sched_getaffinity(0, sizeof available_cpus, &available_cpus));
@@ -200,3 +213,103 @@
run_watchpoint_test(cpu);
}
}
+
+static void __attribute__((noinline)) breakpoint_func() {
+ asm volatile("");
+}
+
+static void __attribute__((noreturn)) breakpoint_fork_child() {
+ // Extra precaution: make sure we go away if anything happens to our parent.
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) == -1) {
+ perror("prctl(PR_SET_PDEATHSIG)");
+ _exit(1);
+ }
+
+ if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) {
+ perror("ptrace(PTRACE_TRACEME)");
+ _exit(2);
+ }
+
+ raise(SIGSTOP); // Synchronize with the tracer, let it set the breakpoint.
+
+ breakpoint_func(); // Now trigger the breakpoint.
+
+ _exit(0);
+}
+
+static void set_breakpoint(pid_t child) {
+ uintptr_t address = uintptr_t(breakpoint_func);
+#if defined(__arm__) || defined(__aarch64__)
+ address &= ~3;
+ const unsigned byte_mask = 0xf;
+ const unsigned enable = 1;
+ const unsigned control = byte_mask << 5 | enable;
+
+#ifdef __arm__
+ ASSERT_EQ(0, ptrace(PTRACE_SETHBPREGS, child, 1, &address)) << strerror(errno);
+ ASSERT_EQ(0, ptrace(PTRACE_SETHBPREGS, child, 2, &control)) << strerror(errno);
+#else // aarch64
+ user_hwdebug_state dreg_state;
+ memset(&dreg_state, 0, sizeof dreg_state);
+ dreg_state.dbg_regs[0].addr = reinterpret_cast<uintptr_t>(address);
+ dreg_state.dbg_regs[0].ctrl = control;
+
+ iovec iov;
+ iov.iov_base = &dreg_state;
+ iov.iov_len = offsetof(user_hwdebug_state, dbg_regs) + sizeof(dreg_state.dbg_regs[0]);
+
+ ASSERT_EQ(0, ptrace(PTRACE_SETREGSET, child, NT_ARM_HW_BREAK, &iov)) << strerror(errno);
+#endif
+#elif defined(__i386__) || defined(__x86_64__)
+ ASSERT_EQ(0, ptrace(PTRACE_POKEUSER, child, offsetof(user, u_debugreg[0]), address))
+ << strerror(errno);
+ errno = 0;
+ unsigned data = ptrace(PTRACE_PEEKUSER, child, offsetof(user, u_debugreg[7]), nullptr);
+ ASSERT_EQ(0, errno);
+
+ const unsigned size = 0;
+ const unsigned enable = 1;
+ const unsigned type = 0; // Execute
+
+ const unsigned mask = 3 << 18 | 3 << 16 | 1;
+ const unsigned value = size << 18 | type << 16 | enable;
+ data &= mask;
+ data |= value;
+ ASSERT_EQ(0, ptrace(PTRACE_POKEUSER, child, offsetof(user, u_debugreg[7]), data))
+ << strerror(errno);
+#else
+ (void)child;
+ (void)address;
+#endif
+}
+
+// Test hardware breakpoint API. The test is considered successful if the breakpoints get hit OR the
+// system reports that hardware breakpoint support is not present.
+TEST(sys_ptrace, hardware_breakpoint) {
+ pid_t child = fork();
+ ASSERT_NE(-1, child) << strerror(errno);
+ if (child == 0) breakpoint_fork_child();
+
+ ChildGuard guard(child);
+
+ int status;
+ ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+ ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
+ ASSERT_EQ(SIGSTOP, WSTOPSIG(status)) << "Status was: " << status;
+
+ if (!is_hw_feature_supported(child, HwFeature::Breakpoint)) {
+ GTEST_LOG_(INFO) << "Skipping test because hardware support is not available.\n";
+ return;
+ }
+
+ set_breakpoint(child);
+
+ ASSERT_EQ(0, ptrace(PTRACE_CONT, child, nullptr, nullptr)) << strerror(errno);
+ ASSERT_EQ(child, waitpid(child, &status, __WALL)) << strerror(errno);
+ ASSERT_TRUE(WIFSTOPPED(status)) << "Status was: " << status;
+ ASSERT_EQ(SIGTRAP, WSTOPSIG(status)) << "Status was: " << status;
+
+ siginfo_t siginfo;
+ ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child, nullptr, &siginfo)) << strerror(errno);
+ ASSERT_EQ(TRAP_HWBKPT, siginfo.si_code);
+}