mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-15 10:07:56 +08:00
193 lines
6.3 KiB
C++
193 lines
6.3 KiB
C++
|
// Copyright 2021 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 "util/ios/ios_intermediate_dump_reader.h"
|
||
|
|
||
|
#include <memory>
|
||
|
#include <stack>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "base/logging.h"
|
||
|
#include "util/file/filesystem.h"
|
||
|
#include "util/ios/ios_intermediate_dump_data.h"
|
||
|
#include "util/ios/ios_intermediate_dump_format.h"
|
||
|
#include "util/ios/ios_intermediate_dump_list.h"
|
||
|
#include "util/ios/ios_intermediate_dump_object.h"
|
||
|
#include "util/ios/ios_intermediate_dump_writer.h"
|
||
|
|
||
|
namespace crashpad {
|
||
|
namespace internal {
|
||
|
|
||
|
bool IOSIntermediateDumpReader::Initialize(const base::FilePath& path) {
|
||
|
ScopedFileHandle handle(LoggingOpenFileForRead(path));
|
||
|
auto reader = std::make_unique<WeakFileHandleFileReader>(handle.get());
|
||
|
|
||
|
// In the event a crash is introduced by this intermediate dump, don't ever
|
||
|
// read a file twice. To ensure this doesn't happen, immediately unlink.
|
||
|
LoggingRemoveFile(path);
|
||
|
|
||
|
// Don't initialize invalid or empty files.
|
||
|
FileOffset size = LoggingFileSizeByHandle(handle.get());
|
||
|
if (!handle.is_valid() || size == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!Parse(reader.get(), size)) {
|
||
|
LOG(ERROR) << "Intermediate dump parsing failed";
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool IOSIntermediateDumpReader::Parse(FileReaderInterface* reader,
|
||
|
FileOffset file_size) {
|
||
|
std::stack<IOSIntermediateDumpObject*> stack;
|
||
|
stack.push(&minidump_);
|
||
|
using Command = IOSIntermediateDumpWriter::CommandType;
|
||
|
using Type = IOSIntermediateDumpObject::Type;
|
||
|
|
||
|
Command command;
|
||
|
if (!reader->ReadExactly(&command, sizeof(Command)) ||
|
||
|
command != Command::kRootMapStart) {
|
||
|
LOG(ERROR) << "Unexpected start to root map.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
while (reader->ReadExactly(&command, sizeof(Command))) {
|
||
|
IOSIntermediateDumpObject* parent = stack.top();
|
||
|
switch (command) {
|
||
|
case Command::kMapStart: {
|
||
|
std::unique_ptr<IOSIntermediateDumpMap> new_map(
|
||
|
new IOSIntermediateDumpMap());
|
||
|
if (parent->GetType() == Type::kMap) {
|
||
|
const auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
||
|
stack.push(new_map.get());
|
||
|
IntermediateDumpKey key;
|
||
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
||
|
return false;
|
||
|
if (key == IntermediateDumpKey::kInvalid)
|
||
|
return false;
|
||
|
parent_map->map_[key] = std::move(new_map);
|
||
|
} else if (parent->GetType() == Type::kList) {
|
||
|
const auto parent_list =
|
||
|
static_cast<IOSIntermediateDumpList*>(parent);
|
||
|
stack.push(new_map.get());
|
||
|
parent_list->push_back(std::move(new_map));
|
||
|
} else {
|
||
|
LOG(ERROR) << "Unexpected parent (not a map or list).";
|
||
|
return false;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case Command::kArrayStart: {
|
||
|
auto new_list = std::make_unique<IOSIntermediateDumpList>();
|
||
|
if (parent->GetType() != Type::kMap) {
|
||
|
LOG(ERROR) << "Attempting to push an array not in a map.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
IntermediateDumpKey key;
|
||
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
||
|
return false;
|
||
|
if (key == IntermediateDumpKey::kInvalid)
|
||
|
return false;
|
||
|
|
||
|
auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
||
|
stack.push(new_list.get());
|
||
|
parent_map->map_[key] = std::move(new_list);
|
||
|
break;
|
||
|
}
|
||
|
case Command::kMapEnd:
|
||
|
if (stack.size() < 2) {
|
||
|
LOG(ERROR) << "Attempting to pop off main map.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (parent->GetType() != Type::kMap) {
|
||
|
LOG(ERROR) << "Unexpected map end not in a map.";
|
||
|
return false;
|
||
|
}
|
||
|
stack.pop();
|
||
|
break;
|
||
|
case Command::kArrayEnd:
|
||
|
if (stack.size() < 2) {
|
||
|
LOG(ERROR) << "Attempting to pop off main map.";
|
||
|
return false;
|
||
|
}
|
||
|
if (parent->GetType() != Type::kList) {
|
||
|
LOG(ERROR) << "Unexpected list end not in a list.";
|
||
|
return false;
|
||
|
}
|
||
|
stack.pop();
|
||
|
break;
|
||
|
case Command::kProperty: {
|
||
|
if (parent->GetType() != Type::kMap) {
|
||
|
LOG(ERROR) << "Attempting to add a property not in a map.";
|
||
|
return false;
|
||
|
}
|
||
|
IntermediateDumpKey key;
|
||
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
||
|
return false;
|
||
|
if (key == IntermediateDumpKey::kInvalid)
|
||
|
return false;
|
||
|
|
||
|
off_t value_length;
|
||
|
if (!reader->ReadExactly(&value_length, sizeof(value_length))) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
constexpr int kMaximumPropertyLength = 64 * 1024 * 1024; // 64MB.
|
||
|
if (value_length > kMaximumPropertyLength) {
|
||
|
LOG(ERROR) << "Attempting to read a property that's too big: "
|
||
|
<< value_length;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> data(value_length);
|
||
|
if (!reader->ReadExactly(data.data(), value_length)) {
|
||
|
return false;
|
||
|
}
|
||
|
auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
||
|
if (parent_map->map_.find(key) != parent_map->map_.end()) {
|
||
|
LOG(ERROR) << "Inserting duplicate key";
|
||
|
}
|
||
|
parent_map->map_[key] =
|
||
|
std::make_unique<IOSIntermediateDumpData>(std::move(data));
|
||
|
break;
|
||
|
}
|
||
|
case Command::kRootMapEnd: {
|
||
|
if (stack.size() != 1) {
|
||
|
LOG(ERROR) << "Unexpected end of root map.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (reader->Seek(0, SEEK_CUR) != file_size) {
|
||
|
LOG(ERROR) << "Root map ended before end of file.";
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
default:
|
||
|
LOG(ERROR) << "Failed to parse serialized intermediate minidump.";
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOG(ERROR) << "Unexpected end of root map.";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
} // namespace internal
|
||
|
} // namespace crashpad
|