// Copyright 2014 The Crashpad Authors // // 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 "minidump/minidump_module_crashpad_info_writer.h" #include #include "base/check_op.h" #include "base/logging.h" #include "minidump/minidump_annotation_writer.h" #include "minidump/minidump_simple_string_dictionary_writer.h" #include "snapshot/module_snapshot.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h" namespace crashpad { MinidumpModuleCrashpadInfoWriter::MinidumpModuleCrashpadInfoWriter() : MinidumpWritable(), module_(), list_annotations_(), simple_annotations_(), annotation_objects_() { module_.version = MinidumpModuleCrashpadInfo::kVersion; } MinidumpModuleCrashpadInfoWriter::~MinidumpModuleCrashpadInfoWriter() { } void MinidumpModuleCrashpadInfoWriter::InitializeFromSnapshot( const ModuleSnapshot* module_snapshot) { DCHECK_EQ(state(), kStateMutable); DCHECK(!list_annotations_); DCHECK(!simple_annotations_); auto list_annotations = std::make_unique(); list_annotations->InitializeFromVector(module_snapshot->AnnotationsVector()); if (list_annotations->IsUseful()) { SetListAnnotations(std::move(list_annotations)); } auto simple_annotations = std::make_unique(); simple_annotations->InitializeFromMap( module_snapshot->AnnotationsSimpleMap()); if (simple_annotations->IsUseful()) { SetSimpleAnnotations(std::move(simple_annotations)); } auto annotation_objects = std::make_unique(); annotation_objects->InitializeFromList(module_snapshot->AnnotationObjects()); if (annotation_objects->IsUseful()) { SetAnnotationObjects(std::move(annotation_objects)); } } void MinidumpModuleCrashpadInfoWriter::SetListAnnotations( std::unique_ptr list_annotations) { DCHECK_EQ(state(), kStateMutable); list_annotations_ = std::move(list_annotations); } void MinidumpModuleCrashpadInfoWriter::SetSimpleAnnotations( std::unique_ptr simple_annotations) { DCHECK_EQ(state(), kStateMutable); simple_annotations_ = std::move(simple_annotations); } void MinidumpModuleCrashpadInfoWriter::SetAnnotationObjects( std::unique_ptr annotation_objects) { DCHECK_EQ(state(), kStateMutable); annotation_objects_ = std::move(annotation_objects); } bool MinidumpModuleCrashpadInfoWriter::IsUseful() const { return list_annotations_ || simple_annotations_ || annotation_objects_; } bool MinidumpModuleCrashpadInfoWriter::Freeze() { DCHECK_EQ(state(), kStateMutable); if (!MinidumpWritable::Freeze()) { return false; } if (list_annotations_) { list_annotations_->RegisterLocationDescriptor(&module_.list_annotations); } if (simple_annotations_) { simple_annotations_->RegisterLocationDescriptor( &module_.simple_annotations); } if (annotation_objects_) { annotation_objects_->RegisterLocationDescriptor( &module_.annotation_objects); } return true; } size_t MinidumpModuleCrashpadInfoWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); return sizeof(module_); } std::vector MinidumpModuleCrashpadInfoWriter::Children() { DCHECK_GE(state(), kStateFrozen); std::vector children; if (list_annotations_) { children.push_back(list_annotations_.get()); } if (simple_annotations_) { children.push_back(simple_annotations_.get()); } if (annotation_objects_) { children.push_back(annotation_objects_.get()); } return children; } bool MinidumpModuleCrashpadInfoWriter::WriteObject( FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); return file_writer->Write(&module_, sizeof(module_)); } MinidumpModuleCrashpadInfoListWriter::MinidumpModuleCrashpadInfoListWriter() : MinidumpWritable(), module_crashpad_infos_(), module_crashpad_info_links_(), module_crashpad_info_list_base_() { } MinidumpModuleCrashpadInfoListWriter::~MinidumpModuleCrashpadInfoListWriter() { } void MinidumpModuleCrashpadInfoListWriter::InitializeFromSnapshot( const std::vector& module_snapshots) { DCHECK_EQ(state(), kStateMutable); DCHECK(module_crashpad_infos_.empty()); DCHECK(module_crashpad_info_links_.empty()); size_t count = module_snapshots.size(); for (size_t index = 0; index < count; ++index) { const ModuleSnapshot* module_snapshot = module_snapshots[index]; auto module = std::make_unique(); module->InitializeFromSnapshot(module_snapshot); if (module->IsUseful()) { AddModule(std::move(module), index); } } } void MinidumpModuleCrashpadInfoListWriter::AddModule( std::unique_ptr module_crashpad_info, size_t minidump_module_list_index) { DCHECK_EQ(state(), kStateMutable); DCHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); MinidumpModuleCrashpadInfoLink module_crashpad_info_link = {}; if (!AssignIfInRange(&module_crashpad_info_link.minidump_module_list_index, minidump_module_list_index)) { LOG(ERROR) << "minidump_module_list_index " << minidump_module_list_index << " out of range"; return; } module_crashpad_info_links_.push_back(module_crashpad_info_link); module_crashpad_infos_.push_back(std::move(module_crashpad_info)); } bool MinidumpModuleCrashpadInfoListWriter::IsUseful() const { DCHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); return !module_crashpad_infos_.empty(); } bool MinidumpModuleCrashpadInfoListWriter::Freeze() { DCHECK_EQ(state(), kStateMutable); CHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); if (!MinidumpWritable::Freeze()) { return false; } size_t module_count = module_crashpad_infos_.size(); if (!AssignIfInRange(&module_crashpad_info_list_base_.count, module_count)) { LOG(ERROR) << "module_count " << module_count << " out of range"; return false; } for (size_t index = 0; index < module_count; ++index) { module_crashpad_infos_[index]->RegisterLocationDescriptor( &module_crashpad_info_links_[index].location); } return true; } size_t MinidumpModuleCrashpadInfoListWriter::SizeOfObject() { DCHECK_GE(state(), kStateFrozen); DCHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); return sizeof(module_crashpad_info_list_base_) + module_crashpad_info_links_.size() * sizeof(module_crashpad_info_links_[0]); } std::vector MinidumpModuleCrashpadInfoListWriter::Children() { DCHECK_GE(state(), kStateFrozen); DCHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); std::vector children; for (const auto& module : module_crashpad_infos_) { children.push_back(module.get()); } return children; } bool MinidumpModuleCrashpadInfoListWriter::WriteObject( FileWriterInterface* file_writer) { DCHECK_EQ(state(), kStateWritable); DCHECK_EQ(module_crashpad_infos_.size(), module_crashpad_info_links_.size()); WritableIoVec iov; iov.iov_base = &module_crashpad_info_list_base_; iov.iov_len = sizeof(module_crashpad_info_list_base_); std::vector iovecs(1, iov); if (!module_crashpad_info_links_.empty()) { iov.iov_base = &module_crashpad_info_links_[0]; iov.iov_len = module_crashpad_info_links_.size() * sizeof(module_crashpad_info_links_[0]); iovecs.push_back(iov); } return file_writer->WriteIoVec(&iovecs); } } // namespace crashpad