diff --git a/Makefile.am b/Makefile.am index b0a9d76c..3da90508 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,6 +128,9 @@ pkgconfig_DATA += breakpad-client.pc src_client_linux_libbreakpad_client_a_SOURCES = \ src/client/linux/crash_generation/crash_generation_client.cc \ src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/seccomp_unwinder.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ src/client/linux/handler/exception_handler.cc \ src/client/linux/handler/minidump_descriptor.cc \ src/client/linux/log/log.cc \ @@ -440,10 +443,13 @@ src_client_linux_linux_client_unittest_shlib_LDFLAGS = \ -shared \ -Wl,-h,linux_client_unittest_shlib src_client_linux_linux_client_unittest_shlib_LDADD = \ + src/client/linux/crash_generation/crash_generation_client.o \ + src/client/linux/dump_writer_common/seccomp_unwinder.o \ + src/client/linux/dump_writer_common/thread_info.o \ + src/client/linux/dump_writer_common/ucontext_reader.o \ src/client/linux/handler/exception_handler.o \ src/client/linux/handler/minidump_descriptor.o \ src/client/linux/log/log.o \ - src/client/linux/crash_generation/crash_generation_client.o \ src/client/linux/minidump_writer/linux_dumper.o \ src/client/linux/minidump_writer/linux_ptrace_dumper.o \ src/client/linux/minidump_writer/minidump_writer.o \ diff --git a/Makefile.in b/Makefile.in index 6f26fdfd..0db0d7a6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -282,6 +282,9 @@ src_client_linux_libbreakpad_client_a_LIBADD = am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \ src/client/linux/crash_generation/crash_generation_client.cc \ src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/seccomp_unwinder.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ src/client/linux/handler/exception_handler.cc \ src/client/linux/handler/minidump_descriptor.cc \ src/client/linux/log/log.cc \ @@ -300,6 +303,9 @@ am__dirstamp = $(am__leading_dot)dirstamp @ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_1 = src/common/android/breakpad_getcontext.$(OBJEXT) @LINUX_HOST_TRUE@am_src_client_linux_libbreakpad_client_a_OBJECTS = src/client/linux/crash_generation/crash_generation_client.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/seccomp_unwinder.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/log/log.$(OBJEXT) \ @@ -1847,6 +1853,9 @@ noinst_LIBRARIES = $(am__append_7) lib_LIBRARIES = $(am__append_5) $(am__append_8) @LINUX_HOST_TRUE@src_client_linux_libbreakpad_client_a_SOURCES = src/client/linux/crash_generation/crash_generation_client.cc \ @LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.cc \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/seccomp_unwinder.cc \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.cc \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.cc \ @LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.cc \ @LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.cc \ @LINUX_HOST_TRUE@ src/client/linux/log/log.cc \ @@ -2063,10 +2072,13 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @LINUX_HOST_TRUE@ -shared -Wl,-h,linux_client_unittest_shlib \ @LINUX_HOST_TRUE@ $(am__append_19) @LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDADD = \ +@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/seccomp_unwinder.o \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.o \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.o \ @LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.o \ @LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.o \ @LINUX_HOST_TRUE@ src/client/linux/log/log.o \ -@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.o \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.o \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.o \ @@ -3026,6 +3038,21 @@ src/client/linux/crash_generation/crash_generation_client.$(OBJEXT): \ src/client/linux/crash_generation/crash_generation_server.$(OBJEXT): \ src/client/linux/crash_generation/$(am__dirstamp) \ src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/dump_writer_common + @: > src/client/linux/dump_writer_common/$(am__dirstamp) +src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/dump_writer_common/$(DEPDIR) + @: > src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/seccomp_unwinder.$(OBJEXT): \ + src/client/linux/dump_writer_common/$(am__dirstamp) \ + src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/thread_info.$(OBJEXT): \ + src/client/linux/dump_writer_common/$(am__dirstamp) \ + src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT): \ + src/client/linux/dump_writer_common/$(am__dirstamp) \ + src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) src/client/linux/handler/$(am__dirstamp): @$(MKDIR_P) src/client/linux/handler @: > src/client/linux/handler/$(am__dirstamp) @@ -4125,6 +4152,7 @@ mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f src/client/*.$(OBJEXT) -rm -f src/client/linux/crash_generation/*.$(OBJEXT) + -rm -f src/client/linux/dump_writer_common/*.$(OBJEXT) -rm -f src/client/linux/handler/*.$(OBJEXT) -rm -f src/client/linux/log/*.$(OBJEXT) -rm -f src/client/linux/minidump_writer/*.$(OBJEXT) @@ -4149,6 +4177,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/client/$(DEPDIR)/minidump_file_writer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/crash_generation/$(DEPDIR)/crash_generation_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/crash_generation/$(DEPDIR)/crash_generation_server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/dump_writer_common/$(DEPDIR)/seccomp_unwinder.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/dump_writer_common/$(DEPDIR)/thread_info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/dump_writer_common/$(DEPDIR)/ucontext_reader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/exception_handler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/minidump_descriptor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Po@am__quote@ @@ -7653,6 +7684,8 @@ distclean-generic: -rm -f src/client/linux/$(am__dirstamp) -rm -f src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) -rm -f src/client/linux/crash_generation/$(am__dirstamp) + -rm -f src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/dump_writer_common/$(am__dirstamp) -rm -f src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) -rm -f src/client/linux/handler/$(am__dirstamp) -rm -f src/client/linux/log/$(DEPDIR)/$(am__dirstamp) @@ -7699,7 +7732,7 @@ clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) + -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/dump_writer_common/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags @@ -7751,7 +7784,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) + -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/dump_writer_common/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/client/linux/dump_writer_common/mapping_info.h b/src/client/linux/dump_writer_common/mapping_info.h new file mode 100644 index 00000000..c206b504 --- /dev/null +++ b/src/client/linux/dump_writer_common/mapping_info.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ + +#include + +namespace google_breakpad { + +// One of these is produced for each mapping in the process (i.e. line in +// /proc/$x/maps). +struct MappingInfo { + uintptr_t start_addr; + size_t size; + size_t offset; // offset into the backed file. + bool exec; // true if the mapping has the execute bit set. + char name[NAME_MAX]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h new file mode 100644 index 00000000..e2ef45df --- /dev/null +++ b/src/client/linux/dump_writer_common/raw_context_cpu.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386__) +typedef MDRawContextX86 RawContextCPU; +#elif defined(__x86_64) +typedef MDRawContextAMD64 RawContextCPU; +#elif defined(__ARM_EABI__) +typedef MDRawContextARM RawContextCPU; +#elif defined(__aarch64__) +typedef MDRawContextARM64 RawContextCPU; +#elif defined(__mips__) +typedef MDRawContextMIPS RawContextCPU; +#else +#error "This code has not been ported to your platform yet." +#endif + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H diff --git a/src/client/linux/dump_writer_common/seccomp_unwinder.cc b/src/client/linux/dump_writer_common/seccomp_unwinder.cc new file mode 100644 index 00000000..49971557 --- /dev/null +++ b/src/client/linux/dump_writer_common/seccomp_unwinder.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#include "client/linux/dump_writer_common/seccomp_unwinder.h" + +#include + +#include "google_breakpad/common/minidump_format.h" +#include "common/linux/linux_libc_support.h" + +namespace google_breakpad { + +void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu, + const MDRawThread& thread, + uint8_t* stack_copy) { +#if defined(__x86_64) + uint64_t bp = cpu->rbp; + uint64_t top = thread.stack.start_of_memory_range; + for (int i = 4; i--; ) { + if (bp < top || + bp + sizeof(bp) > thread.stack.start_of_memory_range + + thread.stack.memory.data_size || + bp & 1) { + break; + } + uint64_t old_top = top; + top = bp; + uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; + my_memcpy(&bp, bp_addr, sizeof(bp)); + if (bp == 0xDEADBEEFDEADBEEFull) { + struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t deadbeef; + uint64_t rbp; + uint64_t fakeret; + uint64_t ret; + /* char redzone[128]; */ + } seccomp_stackframe; + if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || + top - offsetof(typeof(seccomp_stackframe), deadbeef) + + sizeof(seccomp_stackframe) > + thread.stack.start_of_memory_range+thread.stack.memory.data_size) { + break; + } + my_memcpy(&seccomp_stackframe, + bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), + sizeof(seccomp_stackframe)); + cpu->rbx = seccomp_stackframe.rbx; + cpu->rcx = seccomp_stackframe.rcx; + cpu->rdx = seccomp_stackframe.rdx; + cpu->rsi = seccomp_stackframe.rsi; + cpu->rdi = seccomp_stackframe.rdi; + cpu->rbp = seccomp_stackframe.rbp; + cpu->rsp = top + 4*sizeof(uint64_t) + 128; + cpu->r8 = seccomp_stackframe.r8; + cpu->r9 = seccomp_stackframe.r9; + cpu->r10 = seccomp_stackframe.r10; + cpu->r11 = seccomp_stackframe.r11; + cpu->r12 = seccomp_stackframe.r12; + cpu->r13 = seccomp_stackframe.r13; + cpu->r14 = seccomp_stackframe.r14; + cpu->r15 = seccomp_stackframe.r15; + cpu->rip = seccomp_stackframe.fakeret; + return; + } + } +#elif defined(__i386__) + uint32_t bp = cpu->ebp; + uint32_t top = thread.stack.start_of_memory_range; + for (int i = 4; i--; ) { + if (bp < top || + bp + sizeof(bp) > thread.stack.start_of_memory_range + + thread.stack.memory.data_size || + bp & 1) { + break; + } + uint32_t old_top = top; + top = bp; + uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; + my_memcpy(&bp, bp_addr, sizeof(bp)); + if (bp == 0xDEADBEEFu) { + struct { + uint32_t edi; + uint32_t esi; + uint32_t edx; + uint32_t ecx; + uint32_t ebx; + uint32_t deadbeef; + uint32_t ebp; + uint32_t fakeret; + uint32_t ret; + } seccomp_stackframe; + if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || + top - offsetof(typeof(seccomp_stackframe), deadbeef) + + sizeof(seccomp_stackframe) > + thread.stack.start_of_memory_range+thread.stack.memory.data_size) { + break; + } + my_memcpy(&seccomp_stackframe, + bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), + sizeof(seccomp_stackframe)); + cpu->ebx = seccomp_stackframe.ebx; + cpu->ecx = seccomp_stackframe.ecx; + cpu->edx = seccomp_stackframe.edx; + cpu->esi = seccomp_stackframe.esi; + cpu->edi = seccomp_stackframe.edi; + cpu->ebp = seccomp_stackframe.ebp; + cpu->esp = top + 4*sizeof(void*); + cpu->eip = seccomp_stackframe.fakeret; + return; + } + } +#endif +} + +} // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/seccomp_unwinder.h b/src/client/linux/dump_writer_common/seccomp_unwinder.h new file mode 100644 index 00000000..0f5637b6 --- /dev/null +++ b/src/client/linux/dump_writer_common/seccomp_unwinder.h @@ -0,0 +1,50 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H + +#include "client/linux/dump_writer_common/raw_context_cpu.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +struct SeccompUnwinder { + + // Check if the top of the stack is part of a system call that has been + // redirected by the seccomp sandbox. If so, try to pop the stack frames + // all the way back to the point where the interception happened. + static void PopSeccompStackFrame(RawContextCPU* cpu, + const MDRawThread& thread, + uint8_t* stack_copy); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_SECCOMP_UNWINDER_H diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc new file mode 100644 index 00000000..905941ee --- /dev/null +++ b/src/client/linux/dump_writer_common/thread_info.cc @@ -0,0 +1,263 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#include "client/linux/dump_writer_common/thread_info.h" + +#include + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace { + +#if defined(__i386__) +// Write a uint16_t to memory +// out: memory location to write to +// v: value to write. +void U16(void* out, uint16_t v) { + my_memcpy(out, &v, sizeof(v)); +} + +// Write a uint32_t to memory +// out: memory location to write to +// v: value to write. +void U32(void* out, uint32_t v) { + my_memcpy(out, &v, sizeof(v)); +} +#endif + +} + +namespace google_breakpad { + +#if defined(__i386__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.eip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_X86_ALL; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->gs = regs.xgs; + out->fs = regs.xfs; + out->es = regs.xes; + out->ds = regs.xds; + + out->edi = regs.edi; + out->esi = regs.esi; + out->ebx = regs.ebx; + out->edx = regs.edx; + out->ecx = regs.ecx; + out->eax = regs.eax; + + out->ebp = regs.ebp; + out->eip = regs.eip; + out->cs = regs.xcs; + out->eflags = regs.eflags; + out->esp = regs.esp; + out->ss = regs.xss; + + out->float_save.control_word = fpregs.cwd; + out->float_save.status_word = fpregs.swd; + out->float_save.tag_word = fpregs.twd; + out->float_save.error_offset = fpregs.fip; + out->float_save.error_selector = fpregs.fcs; + out->float_save.data_offset = fpregs.foo; + out->float_save.data_selector = fpregs.fos; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); + + // This matches the Intel fpsave format. + U16(out->extended_registers + 0, fpregs.cwd); + U16(out->extended_registers + 2, fpregs.swd); + U16(out->extended_registers + 4, fpregs.twd); + U16(out->extended_registers + 6, fpxregs.fop); + U32(out->extended_registers + 8, fpxregs.fip); + U16(out->extended_registers + 12, fpxregs.fcs); + U32(out->extended_registers + 16, fpregs.foo); + U16(out->extended_registers + 20, fpregs.fos); + U32(out->extended_registers + 24, fpxregs.mxcsr); + + my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); + my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); +} + +#elif defined(__x86_64) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.rip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_AMD64_FULL | + MD_CONTEXT_AMD64_SEGMENTS; + + out->cs = regs.cs; + + out->ds = regs.ds; + out->es = regs.es; + out->fs = regs.fs; + out->gs = regs.gs; + + out->ss = regs.ss; + out->eflags = regs.eflags; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->rax = regs.rax; + out->rcx = regs.rcx; + out->rdx = regs.rdx; + out->rbx = regs.rbx; + + out->rsp = regs.rsp; + + out->rbp = regs.rbp; + out->rsi = regs.rsi; + out->rdi = regs.rdi; + out->r8 = regs.r8; + out->r9 = regs.r9; + out->r10 = regs.r10; + out->r11 = regs.r11; + out->r12 = regs.r12; + out->r13 = regs.r13; + out->r14 = regs.r14; + out->r15 = regs.r15; + + out->rip = regs.rip; + + out->flt_save.control_word = fpregs.cwd; + out->flt_save.status_word = fpregs.swd; + out->flt_save.tag_word = fpregs.ftw; + out->flt_save.error_opcode = fpregs.fop; + out->flt_save.error_offset = fpregs.rip; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_offset = fpregs.rdp; + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs.mxcsr; + out->flt_save.mx_csr_mask = fpregs.mxcr_mask; + my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.uregs[15]; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM_FULL; + + for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) + out->iregs[i] = regs.uregs[i]; + // No CPSR register in ThreadInfo(it's not accessible via ptrace) + out->cpsr = 0; +#if !defined(__ANDROID__) + out->float_save.fpscr = fpregs.fpsr | + (static_cast(fpregs.fpcr) << 32); + // TODO: sort this out, actually collect floating point registers + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +#endif +} + +#elif defined(__aarch64__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.pc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM64_FULL; + + out->cpsr = static_cast(regs.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = regs.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc; + + out->float_save.fpsr = fpregs.fpsr; + out->float_save.fpcr = fpregs.fpcr; + my_memcpy(&out->float_save.regs, &fpregs.vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.epc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_MIPS_FULL; + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = regs.regs[i]; + + out->mdhi = regs.hi; + out->mdlo = regs.lo; + + for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) { + out->hi[i] = hi[i]; + out->lo[i] = lo[i]; + } + out->dsp_control = dsp_control; + + out->epc = regs.epc; + out->badvaddr = regs.badvaddr; + out->status = regs.status; + out->cause = regs.cause; + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + out->float_save.regs[i] = fpregs.regs[i]; + + out->float_save.fpcsr = fpregs.fpcsr; + out->float_save.fir = fpregs.fir; +} +#endif + +} // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h new file mode 100644 index 00000000..5f24fd6b --- /dev/null +++ b/src/client/linux/dump_writer_common/thread_info.h @@ -0,0 +1,88 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ + +#include +#include + +#include "client/linux/dump_writer_common/raw_context_cpu.h" +#include "common/memory.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386) || defined(__x86_64) +typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; +#endif + +// We produce one of these structures for each thread in the crashed process. +struct ThreadInfo { + pid_t tgid; // thread group id + pid_t ppid; // parent process + + uintptr_t stack_pointer; // thread stack pointer + + +#if defined(__i386) || defined(__x86_64) + user_regs_struct regs; + user_fpregs_struct fpregs; + static const unsigned kNumDebugRegisters = 8; + debugreg_t dregs[8]; +#if defined(__i386) + user_fpxregs_struct fpxregs; +#endif // defined(__i386) + +#elif defined(__ARM_EABI__) + // Mimicking how strace does this(see syscall.c, search for GETREGS) + struct user_regs regs; + struct user_fpregs fpregs; +#elif defined(__aarch64__) + // Use the structures defined in + struct user_pt_regs regs; + struct user_fpsimd_state fpregs; +#elif defined(__mips__) + user_regs_struct regs; + user_fpregs_struct fpregs; + uint32_t hi[3]; + uint32_t lo[3]; + uint32_t dsp_control; +#endif + + // Returns the instruction pointer (platform-dependent impl.). + uintptr_t GetInstructionPointer() const; + + // Fills a RawContextCPU using the context in the ThreadInfo object. + void FillCPUContext(RawContextCPU* out) const; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc new file mode 100644 index 00000000..f497ac2f --- /dev/null +++ b/src/client/linux/dump_writer_common/ucontext_reader.cc @@ -0,0 +1,255 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#include "client/linux/dump_writer_common/ucontext_reader.h" + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Minidump defines register structures which are different from the raw +// structures which we get from the kernel. These are platform specific +// functions to juggle the ucontext and user structures into minidump format. + +#if defined(__i386__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_ESP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_EIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fp) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_X86_FULL | + MD_CONTEXT_X86_FLOATING_POINT; + + out->gs = regs[REG_GS]; + out->fs = regs[REG_FS]; + out->es = regs[REG_ES]; + out->ds = regs[REG_DS]; + + out->edi = regs[REG_EDI]; + out->esi = regs[REG_ESI]; + out->ebx = regs[REG_EBX]; + out->edx = regs[REG_EDX]; + out->ecx = regs[REG_ECX]; + out->eax = regs[REG_EAX]; + + out->ebp = regs[REG_EBP]; + out->eip = regs[REG_EIP]; + out->cs = regs[REG_CS]; + out->eflags = regs[REG_EFL]; + out->esp = regs[REG_UESP]; + out->ss = regs[REG_SS]; + + out->float_save.control_word = fp->cw; + out->float_save.status_word = fp->sw; + out->float_save.tag_word = fp->tag; + out->float_save.error_offset = fp->ipoff; + out->float_save.error_selector = fp->cssel; + out->float_save.data_offset = fp->dataoff; + out->float_save.data_selector = fp->datasel; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); +} + +#elif defined(__x86_64) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_RSP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_RIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fpregs) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_AMD64_FULL; + + out->cs = regs[REG_CSGSFS] & 0xffff; + + out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; + out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; + + out->eflags = regs[REG_EFL]; + + out->rax = regs[REG_RAX]; + out->rcx = regs[REG_RCX]; + out->rdx = regs[REG_RDX]; + out->rbx = regs[REG_RBX]; + + out->rsp = regs[REG_RSP]; + out->rbp = regs[REG_RBP]; + out->rsi = regs[REG_RSI]; + out->rdi = regs[REG_RDI]; + out->r8 = regs[REG_R8]; + out->r9 = regs[REG_R9]; + out->r10 = regs[REG_R10]; + out->r11 = regs[REG_R11]; + out->r12 = regs[REG_R12]; + out->r13 = regs[REG_R13]; + out->r14 = regs[REG_R14]; + out->r15 = regs[REG_R15]; + + out->rip = regs[REG_RIP]; + + out->flt_save.control_word = fpregs->cwd; + out->flt_save.status_word = fpregs->swd; + out->flt_save.tag_word = fpregs->ftw; + out->flt_save.error_opcode = fpregs->fop; + out->flt_save.error_offset = fpregs->rip; + out->flt_save.data_offset = fpregs->rdp; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs->mxcsr; + out->flt_save.mx_csr_mask = fpregs->mxcr_mask; + my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.arm_sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.arm_pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { + out->context_flags = MD_CONTEXT_ARM_FULL; + + out->iregs[0] = uc->uc_mcontext.arm_r0; + out->iregs[1] = uc->uc_mcontext.arm_r1; + out->iregs[2] = uc->uc_mcontext.arm_r2; + out->iregs[3] = uc->uc_mcontext.arm_r3; + out->iregs[4] = uc->uc_mcontext.arm_r4; + out->iregs[5] = uc->uc_mcontext.arm_r5; + out->iregs[6] = uc->uc_mcontext.arm_r6; + out->iregs[7] = uc->uc_mcontext.arm_r7; + out->iregs[8] = uc->uc_mcontext.arm_r8; + out->iregs[9] = uc->uc_mcontext.arm_r9; + out->iregs[10] = uc->uc_mcontext.arm_r10; + + out->iregs[11] = uc->uc_mcontext.arm_fp; + out->iregs[12] = uc->uc_mcontext.arm_ip; + out->iregs[13] = uc->uc_mcontext.arm_sp; + out->iregs[14] = uc->uc_mcontext.arm_lr; + out->iregs[15] = uc->uc_mcontext.arm_pc; + + out->cpsr = uc->uc_mcontext.arm_cpsr; + + // TODO: fix this after fixing ExceptionHandler + out->float_save.fpscr = 0; + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +} + +#elif defined(__aarch64__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct fpsimd_context* fpregs) { + out->context_flags = MD_CONTEXT_ARM64_FULL; + + out->cpsr = static_cast(uc->uc_mcontext.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = uc->uc_mcontext.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; + + out->float_save.fpsr = fpregs->fpsr; + out->float_save.fpcr = fpregs->fpcr; + my_memcpy(&out->float_save.regs, &fpregs->vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { + out->context_flags = MD_CONTEXT_MIPS_FULL; + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = uc->uc_mcontext.gregs[i]; + + out->mdhi = uc->uc_mcontext.mdhi; + out->mdlo = uc->uc_mcontext.mdlo; + + out->hi[0] = uc->uc_mcontext.hi1; + out->hi[1] = uc->uc_mcontext.hi2; + out->hi[2] = uc->uc_mcontext.hi3; + out->lo[0] = uc->uc_mcontext.lo1; + out->lo[1] = uc->uc_mcontext.lo2; + out->lo[2] = uc->uc_mcontext.lo3; + out->dsp_control = uc->uc_mcontext.dsp; + + out->epc = uc->uc_mcontext.pc; + out->badvaddr = 0; // Not reported in signal context. + out->status = 0; // Not reported in signal context. + out->cause = 0; // Not reported in signal context. + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) +#if defined (__ANDROID__) + out->float_save.regs[i] = uc->uc_mcontext.fpregs[i]; +#else + out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; +#endif + + out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; + out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. +} +#endif + +} // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/ucontext_reader.h b/src/client/linux/dump_writer_common/ucontext_reader.h new file mode 100644 index 00000000..b6e77b4b --- /dev/null +++ b/src/client/linux/dump_writer_common/ucontext_reader.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014, Google Inc. +// 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H + +#include +#include + +#include "client/linux/dump_writer_common/raw_context_cpu.h" +#include "common/memory.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Wraps platform-dependent implementations of accessors to ucontext structs. +struct UContextReader { + static uintptr_t GetStackPointer(const struct ucontext* uc); + + static uintptr_t GetInstructionPointer(const struct ucontext* uc); + + // Juggle a arch-specific ucontext into a minidump format + // out: the minidump structure + // info: the collection of register structures. +#if defined(__i386__) || defined(__x86_64) + static void FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fp); +#elif defined(__aarch64__) + static void FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct fpsimd_context* fpregs); +#else + static void FillCPUContext(RawContextCPU *out, const ucontext *uc); +#endif +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index ad2af018..e37ed179 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -44,15 +44,13 @@ #include #include +#include "client/linux/dump_writer_common/mapping_info.h" +#include "client/linux/dump_writer_common/thread_info.h" #include "common/memory.h" #include "google_breakpad/common/minidump_format.h" namespace google_breakpad { -#if defined(__i386) || defined(__x86_64) -typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; -#endif - // Typedef for our parsing of the auxv variables in /proc/pid/auxv. #if defined(__i386) || defined(__ARM_EABI__) || defined(__mips__) typedef Elf32_auxv_t elf_aux_entry; @@ -67,50 +65,6 @@ typedef typeof(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; // This should always be less than NAME_MAX! const char kLinuxGateLibraryName[] = "linux-gate.so"; -// We produce one of these structures for each thread in the crashed process. -struct ThreadInfo { - pid_t tgid; // thread group id - pid_t ppid; // parent process - - uintptr_t stack_pointer; // thread stack pointer - - -#if defined(__i386) || defined(__x86_64) - user_regs_struct regs; - user_fpregs_struct fpregs; - static const unsigned kNumDebugRegisters = 8; - debugreg_t dregs[8]; -#if defined(__i386) - user_fpxregs_struct fpxregs; -#endif // defined(__i386) - -#elif defined(__ARM_EABI__) - // Mimicking how strace does this(see syscall.c, search for GETREGS) - struct user_regs regs; - struct user_fpregs fpregs; -#elif defined(__aarch64__) - // Use the structures defined in - struct user_pt_regs regs; - struct user_fpsimd_state fpregs; -#elif defined(__mips__) - user_regs_struct regs; - user_fpregs_struct fpregs; - uint32_t hi[3]; - uint32_t lo[3]; - uint32_t dsp_control; -#endif -}; - -// One of these is produced for each mapping in the process (i.e. line in -// /proc/$x/maps). -struct MappingInfo { - uintptr_t start_addr; - size_t size; - size_t offset; // offset into the backed file. - bool exec; // true if the mapping has the execute bit set. - char name[NAME_MAX]; -}; - class LinuxDumper { public: explicit LinuxDumper(pid_t pid); diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 41b4864b..c65fa9c9 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -64,6 +64,9 @@ #include +#include "client/linux/dump_writer_common/seccomp_unwinder.h" +#include "client/linux/dump_writer_common/thread_info.h" +#include "client/linux/dump_writer_common/ucontext_reader.h" #include "client/linux/handler/exception_handler.h" #include "client/linux/minidump_writer/cpu_set.h" #include "client/linux/minidump_writer/line_reader.h" @@ -89,393 +92,14 @@ using google_breakpad::MappingList; using google_breakpad::MinidumpFileWriter; using google_breakpad::PageAllocator; using google_breakpad::ProcCpuInfoReader; +using google_breakpad::RawContextCPU; +using google_breakpad::SeccompUnwinder; using google_breakpad::ThreadInfo; using google_breakpad::TypedMDRVA; +using google_breakpad::UContextReader; using google_breakpad::UntypedMDRVA; using google_breakpad::wasteful_vector; -// Minidump defines register structures which are different from the raw -// structures which we get from the kernel. These are platform specific -// functions to juggle the ucontext and user structures into minidump format. -#if defined(__i386__) -typedef MDRawContextX86 RawContextCPU; - -// Write a uint16_t to memory -// out: memory location to write to -// v: value to write. -void U16(void* out, uint16_t v) { - my_memcpy(out, &v, sizeof(v)); -} - -// Write a uint32_t to memory -// out: memory location to write to -// v: value to write. -void U32(void* out, uint32_t v) { - my_memcpy(out, &v, sizeof(v)); -} - -// Juggle an x86 user_(fp|fpx|)regs_struct into minidump format -// out: the minidump structure -// info: the collection of register structures. -void CPUFillFromThreadInfo(MDRawContextX86 *out, - const google_breakpad::ThreadInfo &info) { - out->context_flags = MD_CONTEXT_X86_ALL; - - out->dr0 = info.dregs[0]; - out->dr1 = info.dregs[1]; - out->dr2 = info.dregs[2]; - out->dr3 = info.dregs[3]; - // 4 and 5 deliberatly omitted because they aren't included in the minidump - // format. - out->dr6 = info.dregs[6]; - out->dr7 = info.dregs[7]; - - out->gs = info.regs.xgs; - out->fs = info.regs.xfs; - out->es = info.regs.xes; - out->ds = info.regs.xds; - - out->edi = info.regs.edi; - out->esi = info.regs.esi; - out->ebx = info.regs.ebx; - out->edx = info.regs.edx; - out->ecx = info.regs.ecx; - out->eax = info.regs.eax; - - out->ebp = info.regs.ebp; - out->eip = info.regs.eip; - out->cs = info.regs.xcs; - out->eflags = info.regs.eflags; - out->esp = info.regs.esp; - out->ss = info.regs.xss; - - out->float_save.control_word = info.fpregs.cwd; - out->float_save.status_word = info.fpregs.swd; - out->float_save.tag_word = info.fpregs.twd; - out->float_save.error_offset = info.fpregs.fip; - out->float_save.error_selector = info.fpregs.fcs; - out->float_save.data_offset = info.fpregs.foo; - out->float_save.data_selector = info.fpregs.fos; - - // 8 registers * 10 bytes per register. - my_memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8); - - // This matches the Intel fpsave format. - U16(out->extended_registers + 0, info.fpregs.cwd); - U16(out->extended_registers + 2, info.fpregs.swd); - U16(out->extended_registers + 4, info.fpregs.twd); - U16(out->extended_registers + 6, info.fpxregs.fop); - U32(out->extended_registers + 8, info.fpxregs.fip); - U16(out->extended_registers + 12, info.fpxregs.fcs); - U32(out->extended_registers + 16, info.fpregs.foo); - U16(out->extended_registers + 20, info.fpregs.fos); - U32(out->extended_registers + 24, info.fpxregs.mxcsr); - - my_memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128); - my_memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128); -} - -// Juggle an x86 ucontext into minidump format -// out: the minidump structure -// info: the collection of register structures. -void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc, - const struct _libc_fpstate* fp) { - const greg_t* regs = uc->uc_mcontext.gregs; - - out->context_flags = MD_CONTEXT_X86_FULL | - MD_CONTEXT_X86_FLOATING_POINT; - - out->gs = regs[REG_GS]; - out->fs = regs[REG_FS]; - out->es = regs[REG_ES]; - out->ds = regs[REG_DS]; - - out->edi = regs[REG_EDI]; - out->esi = regs[REG_ESI]; - out->ebx = regs[REG_EBX]; - out->edx = regs[REG_EDX]; - out->ecx = regs[REG_ECX]; - out->eax = regs[REG_EAX]; - - out->ebp = regs[REG_EBP]; - out->eip = regs[REG_EIP]; - out->cs = regs[REG_CS]; - out->eflags = regs[REG_EFL]; - out->esp = regs[REG_UESP]; - out->ss = regs[REG_SS]; - - out->float_save.control_word = fp->cw; - out->float_save.status_word = fp->sw; - out->float_save.tag_word = fp->tag; - out->float_save.error_offset = fp->ipoff; - out->float_save.error_selector = fp->cssel; - out->float_save.data_offset = fp->dataoff; - out->float_save.data_selector = fp->datasel; - - // 8 registers * 10 bytes per register. - my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); -} - -#elif defined(__x86_64) -typedef MDRawContextAMD64 RawContextCPU; - -void CPUFillFromThreadInfo(MDRawContextAMD64 *out, - const google_breakpad::ThreadInfo &info) { - out->context_flags = MD_CONTEXT_AMD64_FULL | - MD_CONTEXT_AMD64_SEGMENTS; - - out->cs = info.regs.cs; - - out->ds = info.regs.ds; - out->es = info.regs.es; - out->fs = info.regs.fs; - out->gs = info.regs.gs; - - out->ss = info.regs.ss; - out->eflags = info.regs.eflags; - - out->dr0 = info.dregs[0]; - out->dr1 = info.dregs[1]; - out->dr2 = info.dregs[2]; - out->dr3 = info.dregs[3]; - // 4 and 5 deliberatly omitted because they aren't included in the minidump - // format. - out->dr6 = info.dregs[6]; - out->dr7 = info.dregs[7]; - - out->rax = info.regs.rax; - out->rcx = info.regs.rcx; - out->rdx = info.regs.rdx; - out->rbx = info.regs.rbx; - - out->rsp = info.regs.rsp; - - out->rbp = info.regs.rbp; - out->rsi = info.regs.rsi; - out->rdi = info.regs.rdi; - out->r8 = info.regs.r8; - out->r9 = info.regs.r9; - out->r10 = info.regs.r10; - out->r11 = info.regs.r11; - out->r12 = info.regs.r12; - out->r13 = info.regs.r13; - out->r14 = info.regs.r14; - out->r15 = info.regs.r15; - - out->rip = info.regs.rip; - - out->flt_save.control_word = info.fpregs.cwd; - out->flt_save.status_word = info.fpregs.swd; - out->flt_save.tag_word = info.fpregs.ftw; - out->flt_save.error_opcode = info.fpregs.fop; - out->flt_save.error_offset = info.fpregs.rip; - out->flt_save.error_selector = 0; // We don't have this. - out->flt_save.data_offset = info.fpregs.rdp; - out->flt_save.data_selector = 0; // We don't have this. - out->flt_save.mx_csr = info.fpregs.mxcsr; - out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask; - my_memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16); - my_memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16); -} - -void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc, - const struct _libc_fpstate* fpregs) { - const greg_t* regs = uc->uc_mcontext.gregs; - - out->context_flags = MD_CONTEXT_AMD64_FULL; - - out->cs = regs[REG_CSGSFS] & 0xffff; - - out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; - out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; - - out->eflags = regs[REG_EFL]; - - out->rax = regs[REG_RAX]; - out->rcx = regs[REG_RCX]; - out->rdx = regs[REG_RDX]; - out->rbx = regs[REG_RBX]; - - out->rsp = regs[REG_RSP]; - out->rbp = regs[REG_RBP]; - out->rsi = regs[REG_RSI]; - out->rdi = regs[REG_RDI]; - out->r8 = regs[REG_R8]; - out->r9 = regs[REG_R9]; - out->r10 = regs[REG_R10]; - out->r11 = regs[REG_R11]; - out->r12 = regs[REG_R12]; - out->r13 = regs[REG_R13]; - out->r14 = regs[REG_R14]; - out->r15 = regs[REG_R15]; - - out->rip = regs[REG_RIP]; - - out->flt_save.control_word = fpregs->cwd; - out->flt_save.status_word = fpregs->swd; - out->flt_save.tag_word = fpregs->ftw; - out->flt_save.error_opcode = fpregs->fop; - out->flt_save.error_offset = fpregs->rip; - out->flt_save.data_offset = fpregs->rdp; - out->flt_save.error_selector = 0; // We don't have this. - out->flt_save.data_selector = 0; // We don't have this. - out->flt_save.mx_csr = fpregs->mxcsr; - out->flt_save.mx_csr_mask = fpregs->mxcr_mask; - my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); - my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); -} - -#elif defined(__ARMEL__) -typedef MDRawContextARM RawContextCPU; - -void CPUFillFromThreadInfo(MDRawContextARM* out, - const google_breakpad::ThreadInfo& info) { - out->context_flags = MD_CONTEXT_ARM_FULL; - - for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) - out->iregs[i] = info.regs.uregs[i]; - // No CPSR register in ThreadInfo(it's not accessible via ptrace) - out->cpsr = 0; -#if !defined(__ANDROID__) - out->float_save.fpscr = info.fpregs.fpsr | - (static_cast(info.fpregs.fpcr) << 32); - // TODO: sort this out, actually collect floating point registers - my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); - my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); -#endif -} - -void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc) { - out->context_flags = MD_CONTEXT_ARM_FULL; - - out->iregs[0] = uc->uc_mcontext.arm_r0; - out->iregs[1] = uc->uc_mcontext.arm_r1; - out->iregs[2] = uc->uc_mcontext.arm_r2; - out->iregs[3] = uc->uc_mcontext.arm_r3; - out->iregs[4] = uc->uc_mcontext.arm_r4; - out->iregs[5] = uc->uc_mcontext.arm_r5; - out->iregs[6] = uc->uc_mcontext.arm_r6; - out->iregs[7] = uc->uc_mcontext.arm_r7; - out->iregs[8] = uc->uc_mcontext.arm_r8; - out->iregs[9] = uc->uc_mcontext.arm_r9; - out->iregs[10] = uc->uc_mcontext.arm_r10; - - out->iregs[11] = uc->uc_mcontext.arm_fp; - out->iregs[12] = uc->uc_mcontext.arm_ip; - out->iregs[13] = uc->uc_mcontext.arm_sp; - out->iregs[14] = uc->uc_mcontext.arm_lr; - out->iregs[15] = uc->uc_mcontext.arm_pc; - - out->cpsr = uc->uc_mcontext.arm_cpsr; - - // TODO: fix this after fixing ExceptionHandler - out->float_save.fpscr = 0; - my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); - my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); -} - -#elif defined(__aarch64__) -typedef MDRawContextARM64 RawContextCPU; - -void CPUFillFromThreadInfo(MDRawContextARM64* out, - const google_breakpad::ThreadInfo& info) { - out->context_flags = MD_CONTEXT_ARM64_FULL; - - out->cpsr = static_cast(info.regs.pstate); - for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) - out->iregs[i] = info.regs.regs[i]; - out->iregs[MD_CONTEXT_ARM64_REG_SP] = info.regs.sp; - out->iregs[MD_CONTEXT_ARM64_REG_PC] = info.regs.pc; - - out->float_save.fpsr = info.fpregs.fpsr; - out->float_save.fpcr = info.fpregs.fpcr; - my_memcpy(&out->float_save.regs, &info.fpregs.vregs, - MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); -} - -void CPUFillFromUContext(MDRawContextARM64* out, const ucontext* uc, - const struct fpsimd_context* fpregs) { - out->context_flags = MD_CONTEXT_ARM64_FULL; - - out->cpsr = static_cast(uc->uc_mcontext.pstate); - for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) - out->iregs[i] = uc->uc_mcontext.regs[i]; - out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; - out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; - - out->float_save.fpsr = fpregs->fpsr; - out->float_save.fpcr = fpregs->fpcr; - my_memcpy(&out->float_save.regs, &fpregs->vregs, - MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); -} - -#elif defined(__mips__) -typedef MDRawContextMIPS RawContextCPU; - -static void CPUFillFromThreadInfo(MDRawContextMIPS* out, - const google_breakpad::ThreadInfo& info) { - out->context_flags = MD_CONTEXT_MIPS_FULL; - - for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) - out->iregs[i] = info.regs.regs[i]; - - out->mdhi = info.regs.hi; - out->mdlo = info.regs.lo; - - for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) { - out->hi[i] = info.hi[i]; - out->lo[i] = info.lo[i]; - } - out->dsp_control = info.dsp_control; - - out->epc = info.regs.epc; - out->badvaddr = info.regs.badvaddr; - out->status = info.regs.status; - out->cause = info.regs.cause; - - for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) - out->float_save.regs[i] = info.fpregs.regs[i]; - - out->float_save.fpcsr = info.fpregs.fpcsr; - out->float_save.fir = info.fpregs.fir; -} - -static void CPUFillFromUContext(MDRawContextMIPS* out, const ucontext* uc) { - out->context_flags = MD_CONTEXT_MIPS_FULL; - - for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) - out->iregs[i] = uc->uc_mcontext.gregs[i]; - - out->mdhi = uc->uc_mcontext.mdhi; - out->mdlo = uc->uc_mcontext.mdlo; - - out->hi[0] = uc->uc_mcontext.hi1; - out->hi[1] = uc->uc_mcontext.hi2; - out->hi[2] = uc->uc_mcontext.hi3; - out->lo[0] = uc->uc_mcontext.lo1; - out->lo[1] = uc->uc_mcontext.lo2; - out->lo[2] = uc->uc_mcontext.lo3; - out->dsp_control = uc->uc_mcontext.dsp; - - out->epc = uc->uc_mcontext.pc; - out->badvaddr = 0; // Not reported in signal context. - out->status = 0; // Not reported in signal context. - out->cause = 0; // Not reported in signal context. - - for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) -#if defined (__ANDROID__) - out->float_save.regs[i] = uc->uc_mcontext.fpregs[i]; -#else - out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; -#endif - - out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; - out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. -} - -#else -#error "This code has not been ported to your platform yet." -#endif class MinidumpWriter { public: @@ -629,123 +253,6 @@ class MinidumpWriter { return true; } - // Check if the top of the stack is part of a system call that has been - // redirected by the seccomp sandbox. If so, try to pop the stack frames - // all the way back to the point where the interception happened. - void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread, - uint8_t* stack_copy) { -#if defined(__x86_64) - uint64_t bp = cpu->rbp; - uint64_t top = thread.stack.start_of_memory_range; - for (int i = 4; i--; ) { - if (bp < top || - bp + sizeof(bp) > thread.stack.start_of_memory_range + - thread.stack.memory.data_size || - bp & 1) { - break; - } - uint64_t old_top = top; - top = bp; - uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; - my_memcpy(&bp, bp_addr, sizeof(bp)); - if (bp == 0xDEADBEEFDEADBEEFull) { - struct { - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rdi; - uint64_t rsi; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t deadbeef; - uint64_t rbp; - uint64_t fakeret; - uint64_t ret; - /* char redzone[128]; */ - } seccomp_stackframe; - if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || - top - offsetof(typeof(seccomp_stackframe), deadbeef) + - sizeof(seccomp_stackframe) > - thread.stack.start_of_memory_range+thread.stack.memory.data_size) { - break; - } - my_memcpy(&seccomp_stackframe, - bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), - sizeof(seccomp_stackframe)); - cpu->rbx = seccomp_stackframe.rbx; - cpu->rcx = seccomp_stackframe.rcx; - cpu->rdx = seccomp_stackframe.rdx; - cpu->rsi = seccomp_stackframe.rsi; - cpu->rdi = seccomp_stackframe.rdi; - cpu->rbp = seccomp_stackframe.rbp; - cpu->rsp = top + 4*sizeof(uint64_t) + 128; - cpu->r8 = seccomp_stackframe.r8; - cpu->r9 = seccomp_stackframe.r9; - cpu->r10 = seccomp_stackframe.r10; - cpu->r11 = seccomp_stackframe.r11; - cpu->r12 = seccomp_stackframe.r12; - cpu->r13 = seccomp_stackframe.r13; - cpu->r14 = seccomp_stackframe.r14; - cpu->r15 = seccomp_stackframe.r15; - cpu->rip = seccomp_stackframe.fakeret; - return; - } - } -#elif defined(__i386__) - uint32_t bp = cpu->ebp; - uint32_t top = thread.stack.start_of_memory_range; - for (int i = 4; i--; ) { - if (bp < top || - bp + sizeof(bp) > thread.stack.start_of_memory_range + - thread.stack.memory.data_size || - bp & 1) { - break; - } - uint32_t old_top = top; - top = bp; - uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range; - my_memcpy(&bp, bp_addr, sizeof(bp)); - if (bp == 0xDEADBEEFu) { - struct { - uint32_t edi; - uint32_t esi; - uint32_t edx; - uint32_t ecx; - uint32_t ebx; - uint32_t deadbeef; - uint32_t ebp; - uint32_t fakeret; - uint32_t ret; - } seccomp_stackframe; - if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top || - top - offsetof(typeof(seccomp_stackframe), deadbeef) + - sizeof(seccomp_stackframe) > - thread.stack.start_of_memory_range+thread.stack.memory.data_size) { - break; - } - my_memcpy(&seccomp_stackframe, - bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef), - sizeof(seccomp_stackframe)); - cpu->ebx = seccomp_stackframe.ebx; - cpu->ecx = seccomp_stackframe.ecx; - cpu->edx = seccomp_stackframe.edx; - cpu->esi = seccomp_stackframe.esi; - cpu->edi = seccomp_stackframe.edi; - cpu->ebp = seccomp_stackframe.ebp; - cpu->esp = top + 4*sizeof(void*); - cpu->eip = seccomp_stackframe.fakeret; - return; - } - } -#endif - } - bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, int max_stack_len, uint8_t** stack_copy) { *stack_copy = NULL; @@ -816,12 +323,13 @@ class MinidumpWriter { ucontext_ && !dumper_->IsPostMortem()) { uint8_t* stack_copy; - if (!FillThreadStack(&thread, GetStackPointer(), -1, &stack_copy)) + const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); + if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy)) return false; // Copy 256 bytes around crashing instruction pointer to minidump. const size_t kIPMemorySize = 256; - uint64_t ip = GetInstructionPointer(); + uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); // Bound it to the upper and lower bounds of the memory map // it's contained within. If it's not in mapped memory, // don't bother trying to write it. @@ -867,12 +375,12 @@ class MinidumpWriter { return false; my_memset(cpu.get(), 0, sizeof(RawContextCPU)); #if !defined(__ARM_EABI__) && !defined(__mips__) - CPUFillFromUContext(cpu.get(), ucontext_, float_state_); + UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); #else - CPUFillFromUContext(cpu.get(), ucontext_); + UContextReader::FillCPUContext(cpu.get(), ucontext_); #endif if (stack_copy) - PopSeccompStackFrame(cpu.get(), thread, stack_copy); + SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); thread.thread_context = cpu.location(); crashing_thread_context_ = cpu.location(); } else { @@ -892,9 +400,9 @@ class MinidumpWriter { if (!cpu.Allocate()) return false; my_memset(cpu.get(), 0, sizeof(RawContextCPU)); - CPUFillFromThreadInfo(cpu.get(), info); + info.FillCPUContext(cpu.get()); if (stack_copy) - PopSeccompStackFrame(cpu.get(), thread, stack_copy); + SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy); thread.thread_context = cpu.location(); if (dumper_->threads()[i] == GetCrashThread()) { crashing_thread_context_ = cpu.location(); @@ -902,7 +410,7 @@ class MinidumpWriter { // This is the crashing thread of a live process, but // no context was provided, so set the crash address // while the instruction pointer is already here. - dumper_->set_crash_address(GetInstructionPointer(info)); + dumper_->set_crash_address(info.GetInstructionPointer()); } } } @@ -1297,70 +805,6 @@ class MinidumpWriter { return dumper_->crash_thread(); } -#if defined(__i386__) - uintptr_t GetStackPointer() { - return ucontext_->uc_mcontext.gregs[REG_ESP]; - } - - uintptr_t GetInstructionPointer() { - return ucontext_->uc_mcontext.gregs[REG_EIP]; - } - - uintptr_t GetInstructionPointer(const ThreadInfo& info) { - return info.regs.eip; - } -#elif defined(__x86_64) - uintptr_t GetStackPointer() { - return ucontext_->uc_mcontext.gregs[REG_RSP]; - } - - uintptr_t GetInstructionPointer() { - return ucontext_->uc_mcontext.gregs[REG_RIP]; - } - - uintptr_t GetInstructionPointer(const ThreadInfo& info) { - return info.regs.rip; - } -#elif defined(__ARM_EABI__) - uintptr_t GetStackPointer() { - return ucontext_->uc_mcontext.arm_sp; - } - - uintptr_t GetInstructionPointer() { - return ucontext_->uc_mcontext.arm_pc; - } - - uintptr_t GetInstructionPointer(const ThreadInfo& info) { - return info.regs.uregs[15]; - } -#elif defined(__aarch64__) - uintptr_t GetStackPointer() { - return ucontext_->uc_mcontext.sp; - } - - uintptr_t GetInstructionPointer() { - return ucontext_->uc_mcontext.pc; - } - - uintptr_t GetInstructionPointer(const ThreadInfo& info) { - return info.regs.pc; - } -#elif defined(__mips__) - uintptr_t GetStackPointer() { - return ucontext_->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; - } - - uintptr_t GetInstructionPointer() { - return ucontext_->uc_mcontext.pc; - } - - uintptr_t GetInstructionPointer(const ThreadInfo& info) { - return info.regs.epc; - } -#else -#error "This code has not been ported to your platform yet." -#endif - void NullifyDirectoryEntry(MDRawDirectory* dirent) { dirent->stream_type = 0; dirent->location.data_size = 0;