From 88d8114fda3e4a7292654bd6ac0c34d6c88a8121 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 1 Aug 2018 10:48:27 -0700 Subject: Define and use a a new MDRawContextARM64 This struct matches the layout defined by Microsoft and replaces Breakpad's MDRawContextARM64_Old. This CL updates the processor to understand either the old or new structs, but clients continue to write the old structs. Change-Id: I8dedd9ddb2ec083b802723b9ac87beb18d98edbd Reviewed-on: https://chromium-review.googlesource.com/1155938 Reviewed-by: Mark Mentovai --- src/processor/convert_old_arm64_context.cc | 67 +++++++++++++++++++++++ src/processor/convert_old_arm64_context.h | 42 +++++++++++++++ src/processor/dump_context.cc | 25 ++++----- src/processor/microdump.cc | 22 +++++--- src/processor/minidump.cc | 83 +++++++++++++++++++++++++++-- src/processor/processor.gyp | 2 + src/processor/stackwalker.cc | 2 +- src/processor/stackwalker_arm64.cc | 2 +- src/processor/stackwalker_arm64.h | 4 +- src/processor/stackwalker_arm64_unittest.cc | 6 +-- 10 files changed, 222 insertions(+), 33 deletions(-) create mode 100644 src/processor/convert_old_arm64_context.cc create mode 100644 src/processor/convert_old_arm64_context.h (limited to 'src/processor') diff --git a/src/processor/convert_old_arm64_context.cc b/src/processor/convert_old_arm64_context.cc new file mode 100644 index 00000000..d4b749e7 --- /dev/null +++ b/src/processor/convert_old_arm64_context.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2018, 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 "processor/convert_old_arm64_context.h" + +#include + +namespace google_breakpad { + +void ConvertOldARM64Context(const MDRawContextARM64_Old& old, + MDRawContextARM64* context) { + context->context_flags = MD_CONTEXT_ARM64; + if (old.context_flags & MD_CONTEXT_ARM64_INTEGER_OLD) { + context->context_flags |= + MD_CONTEXT_ARM64_INTEGER | MD_CONTEXT_ARM64_CONTROL; + } + if (old.context_flags & MD_CONTEXT_ARM64_FLOATING_POINT_OLD) { + context->context_flags |= MD_CONTEXT_ARM64_FLOATING_POINT; + } + + context->cpsr = old.cpsr; + + static_assert(sizeof(old.iregs) == sizeof(context->iregs), + "iregs size mismatch"); + memcpy(context->iregs, old.iregs, sizeof(context->iregs)); + + static_assert(sizeof(old.float_save.regs) == sizeof(context->float_save.regs), + "float_save.regs size mismatch"); + memcpy(context->float_save.regs, + old.float_save.regs, + sizeof(context->float_save.regs)); + context->float_save.fpcr = old.float_save.fpcr; + context->float_save.fpsr = old.float_save.fpsr; + + memset(context->bcr, 0, sizeof(context->bcr)); + memset(context->bvr, 0, sizeof(context->bvr)); + memset(context->wcr, 0, sizeof(context->wcr)); + memset(context->wvr, 0, sizeof(context->wvr)); +} + +} // namespace google_breakpad diff --git a/src/processor/convert_old_arm64_context.h b/src/processor/convert_old_arm64_context.h new file mode 100644 index 00000000..8c0dfe90 --- /dev/null +++ b/src/processor/convert_old_arm64_context.h @@ -0,0 +1,42 @@ +// Copyright (c) 2018, 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 PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ +#define PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ + +#include "google_breakpad/common/minidump_cpu_arm64.h" + +namespace google_breakpad { + +void ConvertOldARM64Context(const MDRawContextARM64_Old& old, + MDRawContextARM64* context); + +} // namespace google_breakpad + +#endif // PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ diff --git a/src/processor/dump_context.cc b/src/processor/dump_context.cc index 198b9501..63ccf4ab 100644 --- a/src/processor/dump_context.cc +++ b/src/processor/dump_context.cc @@ -121,13 +121,13 @@ const MDRawContextARM* DumpContext::GetContextARM() const { return context_.arm; } -const MDRawContextARM64_Old* DumpContext::GetContextARM64() const { - if (GetContextCPU() != MD_CONTEXT_ARM64_OLD) { +const MDRawContextARM64* DumpContext::GetContextARM64() const { + if (GetContextCPU() != MD_CONTEXT_ARM64) { BPLOG(ERROR) << "DumpContext cannot get arm64 context"; return NULL; } - return context_.arm64_old; + return context_.arm64; } const MDRawContextMIPS* DumpContext::GetContextMIPS() const { @@ -157,7 +157,7 @@ bool DumpContext::GetInstructionPointer(uint64_t* ip) const { case MD_CONTEXT_ARM: *ip = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_PC]; break; - case MD_CONTEXT_ARM64_OLD: + case MD_CONTEXT_ARM64: *ip = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_PC]; break; case MD_CONTEXT_PPC: @@ -201,7 +201,7 @@ bool DumpContext::GetStackPointer(uint64_t* sp) const { case MD_CONTEXT_ARM: *sp = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_SP]; break; - case MD_CONTEXT_ARM64_OLD: + case MD_CONTEXT_ARM64: *sp = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_SP]; break; case MD_CONTEXT_PPC: @@ -256,8 +256,8 @@ void DumpContext::SetContextARM(MDRawContextARM* arm) { context_.arm = arm; } -void DumpContext::SetContextARM64(MDRawContextARM64_Old* arm64) { - context_.arm64_old = arm64; +void DumpContext::SetContextARM64(MDRawContextARM64* arm64) { + context_.arm64 = arm64; } void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) { @@ -290,10 +290,6 @@ void DumpContext::FreeContext() { delete context_.arm; break; - case MD_CONTEXT_ARM64_OLD: - delete context_.arm64_old; - break; - case MD_CONTEXT_MIPS: case MD_CONTEXT_MIPS64: delete context_.ctx_mips; @@ -581,10 +577,10 @@ void DumpContext::Print() { break; } - case MD_CONTEXT_ARM64_OLD: { - const MDRawContextARM64_Old* context_arm64 = GetContextARM64(); + case MD_CONTEXT_ARM64: { + const MDRawContextARM64* context_arm64 = GetContextARM64(); printf("MDRawContextARM64\n"); - printf(" context_flags = 0x%" PRIx64 "\n", + printf(" context_flags = 0x%x\n", context_arm64->context_flags); for (unsigned int ireg_index = 0; ireg_index < MD_CONTEXT_ARM64_GPR_COUNT; @@ -603,6 +599,7 @@ void DumpContext::Print() { printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n", freg_index, fp_value.high, fp_value.low); } + break; } diff --git a/src/processor/microdump.cc b/src/processor/microdump.cc index b100f765..13e261b4 100644 --- a/src/processor/microdump.cc +++ b/src/processor/microdump.cc @@ -44,6 +44,7 @@ #include "google_breakpad/common/minidump_cpu_arm.h" #include "google_breakpad/processor/code_module.h" #include "processor/basic_code_module.h" +#include "processor/convert_old_arm64_context.h" #include "processor/linked_ptr.h" #include "processor/logging.h" #include "processor/range_map-inl.h" @@ -125,8 +126,8 @@ void MicrodumpContext::SetContextARM(MDRawContextARM* arm) { valid_ = true; } -void MicrodumpContext::SetContextARM64(MDRawContextARM64_Old* arm64) { - DumpContext::SetContextFlags(MD_CONTEXT_ARM64_OLD); +void MicrodumpContext::SetContextARM64(MDRawContextARM64* arm64) { + DumpContext::SetContextFlags(MD_CONTEXT_ARM64); DumpContext::SetContextARM64(arm64); valid_ = true; } @@ -311,15 +312,22 @@ Microdump::Microdump(const string& contents) memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size()); context_->SetContextARM(arm); } else if (strcmp(arch.c_str(), kArm64Architecture) == 0) { - if (cpu_state_raw.size() != sizeof(MDRawContextARM64_Old)) { + if (cpu_state_raw.size() == sizeof(MDRawContextARM64)) { + MDRawContextARM64* arm = new MDRawContextARM64(); + memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextARM64(arm); + } else if (cpu_state_raw.size() == sizeof(MDRawContextARM64_Old)) { + MDRawContextARM64_Old old_arm; + memcpy(&old_arm, &cpu_state_raw[0], cpu_state_raw.size()); + MDRawContextARM64* new_arm = new MDRawContextARM64(); + ConvertOldARM64Context(old_arm, new_arm); + context_->SetContextARM64(new_arm); + } else { std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() - << " bytes instead of " << sizeof(MDRawContextARM64_Old) + << " bytes instead of " << sizeof(MDRawContextARM64) << std::endl; continue; } - MDRawContextARM64_Old* arm = new MDRawContextARM64_Old(); - memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size()); - context_->SetContextARM64(arm); } else if (strcmp(arch.c_str(), kX86Architecture) == 0) { if (cpu_state_raw.size() != sizeof(MDRawContextX86)) { std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 020b95d3..c86a813f 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -59,6 +59,7 @@ #include "google_breakpad/processor/dump_context.h" #include "processor/basic_code_module.h" #include "processor/basic_code_modules.h" +#include "processor/convert_old_arm64_context.h" #include "processor/logging.h" // All intentional fallthroughs in breakpad are in this file, so define @@ -104,6 +105,8 @@ bool IsContextSizeUnique(uint32_t context_size) { num_matching_contexts++; if (context_size == sizeof(MDRawContextARM)) num_matching_contexts++; + if (context_size == sizeof(MDRawContextARM64)) + num_matching_contexts++; if (context_size == sizeof(MDRawContextARM64_Old)) num_matching_contexts++; if (context_size == sizeof(MDRawContextMIPS)) @@ -745,10 +748,8 @@ bool MinidumpContext::Read(uint32_t expected_size) { for (unsigned int fpr_index = 0; fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT; ++fpr_index) { - // While ARM64 is bi-endian, iOS (currently the only platform - // for which ARM64 support has been brought up) uses ARM64 exclusively - // in little-endian mode. - Normalize128(&context_arm64->float_save.regs[fpr_index], false); + Normalize128(&context_arm64->float_save.regs[fpr_index], + minidump_->is_big_endian()); Swap(&context_arm64->float_save.regs[fpr_index]); } } @@ -762,7 +763,9 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } - SetContextARM64(context_arm64.release()); + scoped_ptr new_context(new MDRawContextARM64()); + ConvertOldARM64Context(*context_arm64.get(), new_context.get()); + SetContextARM64(new_context.release()); } else { uint32_t context_flags; if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { @@ -1059,6 +1062,58 @@ bool MinidumpContext::Read(uint32_t expected_size) { break; } + case MD_CONTEXT_ARM64: { + if (expected_size != sizeof(MDRawContextARM64)) { + BPLOG(ERROR) << "MinidumpContext arm64 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextARM64); + return false; + } + + scoped_ptr context_arm64(new MDRawContextARM64()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_arm64->context_flags = context_flags; + + size_t flags_size = sizeof(context_arm64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_arm64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(*context_arm64) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read arm64 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext arm does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_arm64->context_flags was already swapped. + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM64_GPR_COUNT; + ++ireg_index) { + Swap(&context_arm64->iregs[ireg_index]); + } + Swap(&context_arm64->cpsr); + Swap(&context_arm64->float_save.fpsr); + Swap(&context_arm64->float_save.fpcr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT; + ++fpr_index) { + Normalize128(&context_arm64->float_save.regs[fpr_index], + minidump_->is_big_endian()); + Swap(&context_arm64->float_save.regs[fpr_index]); + } + } + SetContextARM64(context_arm64.release()); + break; + } + case MD_CONTEXT_MIPS: case MD_CONTEXT_MIPS64: { if (expected_size != sizeof(MDRawContextMIPS)) { @@ -1199,6 +1254,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) { return_value = true; break; + case MD_CONTEXT_ARM64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64) + return_value = true; + break; + case MD_CONTEXT_ARM64_OLD: if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64_OLD) return_value = true; @@ -3487,6 +3547,7 @@ string MinidumpSystemInfo::GetCPU() { cpu = "arm"; break; + case MD_CPU_ARCHITECTURE_ARM64: case MD_CPU_ARCHITECTURE_ARM64_OLD: cpu = "arm64"; break; @@ -4994,6 +5055,7 @@ Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width) path_(path), stream_(NULL), swap_(false), + is_big_endian_(false), valid_(false), hexdump_(hexdump), hexdump_width_(hexdump_width) { @@ -5006,6 +5068,7 @@ Minidump::Minidump(istream& stream) path_(), stream_(&stream), swap_(false), + is_big_endian_(false), valid_(false), hexdump_(false), hexdump_width_(0) { @@ -5086,6 +5149,9 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { case MD_CPU_ARCHITECTURE_ARM: *context_cpu_flags = MD_CONTEXT_ARM; break; + case MD_CPU_ARCHITECTURE_ARM64: + *context_cpu_flags = MD_CONTEXT_ARM64; + break; case MD_CPU_ARCHITECTURE_ARM64_OLD: *context_cpu_flags = MD_CONTEXT_ARM64_OLD; break; @@ -5161,6 +5227,13 @@ bool Minidump::Read() { swap_ = false; } +#if defined(__BIG_ENDIAN__) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + is_big_endian_ = !swap_; +#else + is_big_endian_ = swap_; +#endif + BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") << "byte-swapping minidump"; diff --git a/src/processor/processor.gyp b/src/processor/processor.gyp index d09a8953..feec7443 100644 --- a/src/processor/processor.gyp +++ b/src/processor/processor.gyp @@ -49,6 +49,8 @@ 'cfi_frame_info.h', 'contained_range_map-inl.h', 'contained_range_map.h', + 'convert_old_arm64_context.cc', + 'convert_old_arm64_context.h', 'disassembler_x86.cc', 'disassembler_x86.h', 'dump_context.cc', diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index c7634ff0..4988ef1e 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -259,7 +259,7 @@ Stackwalker* Stackwalker::StackwalkerForCPU( break; } - case MD_CONTEXT_ARM64_OLD: + case MD_CONTEXT_ARM64: cpu_stackwalker = new StackwalkerARM64(system_info, context->GetContextARM64(), memory, modules, diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc index 042fd089..f9660112 100644 --- a/src/processor/stackwalker_arm64.cc +++ b/src/processor/stackwalker_arm64.cc @@ -48,7 +48,7 @@ namespace google_breakpad { StackwalkerARM64::StackwalkerARM64(const SystemInfo* system_info, - const MDRawContextARM64_Old* context, + const MDRawContextARM64* context, MemoryRegion* memory, const CodeModules* modules, StackFrameSymbolizer* resolver_helper) diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h index 1b01f21e..121e8246 100644 --- a/src/processor/stackwalker_arm64.h +++ b/src/processor/stackwalker_arm64.h @@ -55,7 +55,7 @@ class StackwalkerARM64 : public Stackwalker { // included in the stack. The other arguments are passed directly through // to the base Stackwalker constructor. StackwalkerARM64(const SystemInfo* system_info, - const MDRawContextARM64_Old* context, + const MDRawContextARM64* context, MemoryRegion* memory, const CodeModules* modules, StackFrameSymbolizer* frame_symbolizer); @@ -89,7 +89,7 @@ class StackwalkerARM64 : public Stackwalker { // Stores the CPU context corresponding to the youngest stack frame, to // be returned by GetContextFrame. - const MDRawContextARM64_Old* context_; + const MDRawContextARM64* context_; // Validity mask for youngest stack frame. This is always // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of diff --git a/src/processor/stackwalker_arm64_unittest.cc b/src/processor/stackwalker_arm64_unittest.cc index fff70744..f9d18cea 100644 --- a/src/processor/stackwalker_arm64_unittest.cc +++ b/src/processor/stackwalker_arm64_unittest.cc @@ -122,14 +122,14 @@ class StackwalkerARM64Fixture { } // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. - void BrandContext(MDRawContextARM64_Old *raw_context) { + void BrandContext(MDRawContextARM64 *raw_context) { uint8_t x = 173; for (size_t i = 0; i < sizeof(*raw_context); i++) reinterpret_cast(raw_context)[i] = (x += 17); } SystemInfo system_info; - MDRawContextARM64_Old raw_context; + MDRawContextARM64 raw_context; Section stack_section; MockMemoryRegion stack_region; MockCodeModule module1; @@ -688,7 +688,7 @@ struct CFIFixture: public StackwalkerARM64Fixture { } // The values we expect to find for the caller's registers. - MDRawContextARM64_Old expected; + MDRawContextARM64 expected; // The validity mask for expected. uint64_t expected_validity; -- cgit v1.2.1