Use breakpad_getcontext on all Linux platforms missing getcontext

getcontext is also not available on musl libc, so generalize
breakpad_getcontext so it can be used as a fallback for non-Android
platforms as well.

On x86_64 and i386, ucontext_t uses an Android-specific offset for
storage of FP registers, since its sigset_t differs in size. So,
make the definition of MCONTEXT_FPREGS_MEM and UCONTEXT_FPREGS_MEM_OFFSET
conditional on whether we are building for Android.

On glibc and musl, signal.h and asm/sigcontext.h can't be included
together, so in breakpad_context_unittest.cc, only compare the libc
and kernel _fpstate when on Android.

Bug: google-breakpad:631
Change-Id: If81d73c4101bae946e9a3655b8d1c40a34ab6c38
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2102135
Reviewed-by: Mike Frysinger <vapier@chromium.org>
This commit is contained in:
Michael Forney 2020-03-16 12:56:56 -07:00 committed by Mike Frysinger
parent 02b7be4065
commit e780d58fd7
14 changed files with 124 additions and 87 deletions

View file

@ -87,6 +87,7 @@
#include <vector>
#include "common/basictypes.h"
#include "common/linux/breakpad_getcontext.h"
#include "common/linux/linux_libc_support.h"
#include "common/memory_allocator.h"
#include "client/linux/log/log.h"

View file

@ -40,6 +40,7 @@
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/microdump_extra_info.h"
#include "client/linux/microdump_writer/microdump_writer.h"
#include "common/linux/breakpad_getcontext.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/ignore_ret.h"
#include "common/scoped_ptr.h"

View file

@ -42,6 +42,7 @@
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
#include "common/linux/breakpad_getcontext.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "common/linux/ignore_ret.h"

View file

@ -33,7 +33,13 @@
'defines': ['HAVE_MACH_O_NLIST_H'],
}],
['OS=="linux"', {
'defines': ['HAVE_A_OUT_H'],
# Assume glibc.
'defines': ['HAVE_A_OUT_H', 'HAVE_GETCONTEXT'],
'sources!': [
'linux/breakpad_getcontext.S',
'linux/breakpad_getcontext.h',
'linux/breakpad_getcontext_unittest.cc',
],
}],
['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}],
['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}],
@ -47,13 +53,11 @@
'target_name': 'common',
'type': 'static_library',
'sources': [
'android/breakpad_getcontext.S',
'android/include/elf.h',
'android/include/link.h',
'android/include/stab.h',
'android/include/sys/procfs.h',
'android/include/sys/user.h',
'android/include/ucontext.h',
'android/testing/include/wchar.h',
'android/testing/mkdtemp.h',
'android/testing/pthread_fixes.h',
@ -87,6 +91,8 @@
'dwarf_line_to_module.h',
'language.cc',
'language.h',
'linux/breakpad_getcontext.S',
'linux/breakpad_getcontext.h',
'linux/crc32.cc',
'linux/crc32.h',
'linux/dump_symbols.cc',
@ -201,7 +207,6 @@
'target_name': 'common_unittests',
'type': 'executable',
'sources': [
'android/breakpad_getcontext_unittest.cc',
'byte_cursor_unittest.cc',
'dwarf/bytereader_unittest.cc',
'dwarf/dwarf2diehandler_unittest.cc',
@ -210,6 +215,7 @@
'dwarf_cfi_to_module_unittest.cc',
'dwarf_cu_to_module_unittest.cc',
'dwarf_line_to_module_unittest.cc',
'linux/breakpad_getcontext_unittest.cc',
'linux/dump_symbols_unittest.cc',
'linux/elf_core_dump_unittest.cc',
'linux/elf_symbols_to_module_unittest.cc',

View file

@ -28,9 +28,9 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A minimalistic implementation of getcontext() to be used by
// Google Breakpad on Android.
// Google Breakpad when getcontext() is not available in libc.
#include "common/android/ucontext_constants.h"
#include "common/linux/ucontext_constants.h"
/* int getcontext (ucontext_t *ucp) */

View file

@ -27,22 +27,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H
#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
#include <sys/cdefs.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef __BIONIC_UCONTEXT_H
#include <ucontext.h>
#else
#ifndef HAVE_GETCONTEXT
#include <sys/ucontext.h>
#include <signal.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Provided by src/android/common/breakpad_getcontext.S
// Provided by src/common/linux/breakpad_getcontext.S
int breakpad_getcontext(ucontext_t* ucp);
#define getcontext(x) breakpad_getcontext(x)
@ -51,6 +51,6 @@ int breakpad_getcontext(ucontext_t* ucp);
} // extern "C"
#endif // __cplusplus
#endif // __BIONIC_UCONTEXT_H
#endif // HAVE_GETCONTEXT
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H
#endif // GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H

View file

@ -27,14 +27,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if defined(__x86_64__)
// asm/sigcontext.h can't be included with signal.h on glibc or
// musl, so only compare _libc_fpstate and _fpstate on Android.
#if defined(__ANDROID__) && defined(__x86_64__)
#include <asm/sigcontext.h>
#endif
#include <sys/ucontext.h>
#include <type_traits>
#include "breakpad_googletest_includes.h"
#include "common/android/ucontext_constants.h"
#include "common/linux/ucontext_constants.h"
template <int left, int right>
struct CompileAssertEquals {
@ -139,6 +143,8 @@ TEST(AndroidUContext, GRegsOffset) {
// sigcontext is an analog to mcontext_t. The layout should be the same.
COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs),
offsetof(sigcontext,fpstate), sigcontext_fpstate);
#if defined(__ANDROID__)
// Check that _fpstate from asm/sigcontext.h is essentially the same
// as _libc_fpstate.
COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate),
@ -164,13 +170,15 @@ TEST(AndroidUContext, GRegsOffset) {
sigcontext_fpstate_stspace);
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space),
sigcontext_fpstate_xmm_space);
#endif
COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR,
offsetof(ucontext_t,uc_mcontext.fpregs),
mcontext_fpregs_ptr);
COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem),
mcontext_fpregs_mem);
COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR, offsetof(_libc_fpstate,mxcsr),
COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR,
offsetof(std::remove_pointer<fpregset_t>::type,mxcsr),
fpregs_offset_mxcsr);
COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask),
ucontext_sigmask);

View file

@ -31,14 +31,15 @@
// Its purpose is to contain constants that must match the offsets of
// various fields in ucontext_t.
//
// They should match the definitions from
// src/common/android/include/sys/ucontext.h
// They should match the definitions from signal.h.
//
// Used by src/common/android/breakpad_getcontext.S
// Tested by src/common/android/testing/breakpad_getcontext_unittest.cc
// Used by src/common/linux/breakpad_getcontext.S
// Tested by src/common/linux/breakpad_getcontext_unittest.cc
//
// This header should not be used by anything else.
#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H
#define GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H
#ifndef GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H
#define GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H
#if defined(__arm__)
@ -93,7 +94,11 @@
#define UCONTEXT_SIGMASK_OFFSET 108
#define UCONTEXT_FPREGS_OFFSET 96
#if defined(__BIONIC__)
#define UCONTEXT_FPREGS_MEM_OFFSET 116
#else
#define UCONTEXT_FPREGS_MEM_OFFSET 236
#endif
#elif defined(__mips__)
@ -134,7 +139,11 @@
#define MCONTEXT_GREGS_RSP 160
#define MCONTEXT_GREGS_RIP 168
#define MCONTEXT_FPREGS_PTR 224
#if defined(__BIONIC__)
#define MCONTEXT_FPREGS_MEM 304
#else
#define MCONTEXT_FPREGS_MEM 424
#endif
#define FPREGS_OFFSET_MXCSR 24
#else

View file

@ -9,6 +9,9 @@
/* define if the compiler supports basic C++11 syntax */
#undef HAVE_CXX11
/* Define to 1 if you have the `getcontext' function. */
#undef HAVE_GETCONTEXT
/* Define to 1 if you have the `getrandom' function. */
#undef HAVE_GETRANDOM