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 <mark@chromium.org>
This commit is contained in:
Joshua Peraza
2018-08-01 10:48:27 -07:00
parent 627ef0cb9c
commit 88d8114fda
22 changed files with 411 additions and 83 deletions

View File

@@ -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 <string.h>
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

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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<MDRawContextARM64> 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<MDRawContextARM64> 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<uint8_t*>(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";

View File

@@ -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',

View File

@@ -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,

View File

@@ -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)

View File

@@ -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

View File

@@ -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<uint8_t *>(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;