crashpad/snapshot/fuchsia/exception_snapshot_fuchsia.cc
Scott Graham ef8a063055 Fuchsia: Propagate failure to initialize exception snapshot
If the process' threads can't be read, then the cpu context object won't
be able to be initialized.

Previously, the process snapshot always assumed that the context would
be filled out, as there was no error returned, which could result in
later checks failing.

Return an error from the exception snapshot's initialization so that
process snapshot can correctly handle failure to initialize.

Bug: fuchsia:55837
Change-Id: Ia3fecef1230a19dfa23401b0339c6a94370c6baf
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2296039
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
2020-07-13 19:53:06 +00:00

142 lines
4.6 KiB
C++

// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "snapshot/fuchsia/exception_snapshot_fuchsia.h"
#include "base/numerics/safe_conversions.h"
#include "snapshot/fuchsia/cpu_context_fuchsia.h"
#include "snapshot/fuchsia/process_reader_fuchsia.h"
namespace crashpad {
namespace internal {
ExceptionSnapshotFuchsia::ExceptionSnapshotFuchsia() = default;
ExceptionSnapshotFuchsia::~ExceptionSnapshotFuchsia() = default;
bool ExceptionSnapshotFuchsia::Initialize(
ProcessReaderFuchsia* process_reader,
zx_koid_t thread_id,
const zx_exception_report_t& exception_report) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
exception_ = exception_report.header.type;
thread_id_ = thread_id;
// TODO(scottmg): Not sure whether these values for exception_info_ are
// helpful or correct. Other values in the structures are stored below into
// Codes() in case they are useful.
#if defined(ARCH_CPU_X86_64)
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(
exception_report.context.arch.u.x86_64.err_code));
exception_info_ = exception_report.context.arch.u.x86_64.err_code;
#elif defined(ARCH_CPU_ARM64)
exception_info_ = exception_report.context.arch.u.arm_64.esr;
#endif
codes_.push_back(exception_);
codes_.push_back(exception_info_);
#if defined(ARCH_CPU_X86_64)
codes_.push_back(exception_report.context.arch.u.x86_64.vector);
codes_.push_back(exception_report.context.arch.u.x86_64.cr2);
#elif defined(ARCH_CPU_ARM64)
codes_.push_back(exception_report.context.arch.u.arm_64.far);
#endif
const auto threads = process_reader->Threads();
const auto& t =
std::find_if(threads.begin(),
threads.end(),
[thread_id](const ProcessReaderFuchsia::Thread& thread) {
return thread.id == thread_id;
});
if (t == threads.end()) {
// If no threads have been read, then context_ can't be initalized, and the
// exception snapshot can't be considered initialized_.
return false;
}
#if defined(ARCH_CPU_X86_64)
context_.architecture = kCPUArchitectureX86_64;
context_.x86_64 = &context_arch_;
// TODO(fxbug.dev/5496): Add float context once saved in |t|.
InitializeCPUContextX86_64_NoFloatingPoint(t->general_registers,
context_.x86_64);
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_arch_;
InitializeCPUContextARM64(
t->general_registers, t->vector_registers, context_.arm64);
#else
#error Port.
#endif
if (context_.InstructionPointer() != 0 &&
(exception_ == ZX_EXCP_UNDEFINED_INSTRUCTION ||
exception_ == ZX_EXCP_SW_BREAKPOINT ||
exception_ == ZX_EXCP_HW_BREAKPOINT)) {
exception_address_ = context_.InstructionPointer();
} else {
#if defined(ARCH_CPU_X86_64)
exception_address_ = exception_report.context.arch.u.x86_64.cr2;
#elif defined(ARCH_CPU_ARM64)
exception_address_ = exception_report.context.arch.u.arm_64.far;
#else
#error Port.
#endif
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
const CPUContext* ExceptionSnapshotFuchsia::Context() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &context_;
}
uint64_t ExceptionSnapshotFuchsia::ThreadID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return thread_id_;
}
uint32_t ExceptionSnapshotFuchsia::Exception() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return exception_;
}
uint32_t ExceptionSnapshotFuchsia::ExceptionInfo() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return exception_info_;
}
uint64_t ExceptionSnapshotFuchsia::ExceptionAddress() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return exception_address_;
}
const std::vector<uint64_t>& ExceptionSnapshotFuchsia::Codes() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return codes_;
}
std::vector<const MemorySnapshot*> ExceptionSnapshotFuchsia::ExtraMemory()
const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<const MemorySnapshot*>();
}
} // namespace internal
} // namespace crashpad