
Summary: On the heels of D62934, this patch uses the same approach to introduce llvm RTTI support to the ObjectFile hierarchy. It also replaces the existing uses of GetPluginName doing run-time type checks with llvm::dyn_cast and friends. This formally introduces new dependencies from some other plugins to ObjectFile plugins. However, I believe this is fine because: - these dependencies were already kind of there, and the only reason we could get away with not modeling them explicitly was because the code was relying on magically knowing what will GetPluginName() return for a particular kind of object files. - the dependencies themselves are logical (it makes sense for SymbolVendorELF to depend on ObjectFileELF), or at least don't actively get in the way (the JitLoaderGDB->MachO thing). - they don't introduce any new dependency loops as ObjectFile plugins don't depend on any other plugins Reviewers: xiaobai, JDevlieghere, espindola Subscribers: emaste, mgorny, arichardson, MaskRay, lldb-commits Differential Revision: https://reviews.llvm.org/D65450 llvm-svn: 367413
171 lines
5.6 KiB
C++
171 lines
5.6 KiB
C++
//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
|
|
#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Core/Section.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::breakpad;
|
|
|
|
namespace {
|
|
struct Header {
|
|
ArchSpec arch;
|
|
UUID uuid;
|
|
static llvm::Optional<Header> parse(llvm::StringRef text);
|
|
};
|
|
} // namespace
|
|
|
|
llvm::Optional<Header> Header::parse(llvm::StringRef text) {
|
|
llvm::StringRef line;
|
|
std::tie(line, text) = text.split('\n');
|
|
auto Module = ModuleRecord::parse(line);
|
|
if (!Module)
|
|
return llvm::None;
|
|
|
|
llvm::Triple triple;
|
|
triple.setArch(Module->Arch);
|
|
triple.setOS(Module->OS);
|
|
|
|
std::tie(line, text) = text.split('\n');
|
|
|
|
auto Info = InfoRecord::parse(line);
|
|
UUID uuid = Info && Info->ID ? Info->ID : Module->ID;
|
|
return Header{ArchSpec(triple), std::move(uuid)};
|
|
}
|
|
|
|
char ObjectFileBreakpad::ID;
|
|
|
|
void ObjectFileBreakpad::Initialize() {
|
|
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
|
GetPluginDescriptionStatic(), CreateInstance,
|
|
CreateMemoryInstance, GetModuleSpecifications);
|
|
}
|
|
|
|
void ObjectFileBreakpad::Terminate() {
|
|
PluginManager::UnregisterPlugin(CreateInstance);
|
|
}
|
|
|
|
ConstString ObjectFileBreakpad::GetPluginNameStatic() {
|
|
static ConstString g_name("breakpad");
|
|
return g_name;
|
|
}
|
|
|
|
ObjectFile *ObjectFileBreakpad::CreateInstance(
|
|
const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset,
|
|
const FileSpec *file, offset_t file_offset, offset_t length) {
|
|
if (!data_sp) {
|
|
data_sp = MapFileData(*file, length, file_offset);
|
|
if (!data_sp)
|
|
return nullptr;
|
|
data_offset = 0;
|
|
}
|
|
auto text = toStringRef(data_sp->GetData());
|
|
llvm::Optional<Header> header = Header::parse(text);
|
|
if (!header)
|
|
return nullptr;
|
|
|
|
// Update the data to contain the entire file if it doesn't already
|
|
if (data_sp->GetByteSize() < length) {
|
|
data_sp = MapFileData(*file, length, file_offset);
|
|
if (!data_sp)
|
|
return nullptr;
|
|
data_offset = 0;
|
|
}
|
|
|
|
return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,
|
|
file_offset, length, std::move(header->arch),
|
|
std::move(header->uuid));
|
|
}
|
|
|
|
ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(
|
|
const ModuleSP &module_sp, DataBufferSP &data_sp,
|
|
const ProcessSP &process_sp, addr_t header_addr) {
|
|
return nullptr;
|
|
}
|
|
|
|
size_t ObjectFileBreakpad::GetModuleSpecifications(
|
|
const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
|
|
offset_t file_offset, offset_t length, ModuleSpecList &specs) {
|
|
auto text = toStringRef(data_sp->GetData());
|
|
llvm::Optional<Header> header = Header::parse(text);
|
|
if (!header)
|
|
return 0;
|
|
ModuleSpec spec(file, std::move(header->arch));
|
|
spec.GetUUID() = std::move(header->uuid);
|
|
specs.Append(spec);
|
|
return 1;
|
|
}
|
|
|
|
ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp,
|
|
DataBufferSP &data_sp,
|
|
offset_t data_offset,
|
|
const FileSpec *file, offset_t offset,
|
|
offset_t length, ArchSpec arch,
|
|
UUID uuid)
|
|
: ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
|
|
m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}
|
|
|
|
bool ObjectFileBreakpad::ParseHeader() {
|
|
// We already parsed the header during initialization.
|
|
return true;
|
|
}
|
|
|
|
Symtab *ObjectFileBreakpad::GetSymtab() {
|
|
// TODO
|
|
return nullptr;
|
|
}
|
|
|
|
void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
|
|
if (m_sections_up)
|
|
return;
|
|
m_sections_up = llvm::make_unique<SectionList>();
|
|
|
|
llvm::Optional<Record::Kind> current_section;
|
|
offset_t section_start;
|
|
llvm::StringRef text = toStringRef(m_data.GetData());
|
|
uint32_t next_section_id = 1;
|
|
auto maybe_add_section = [&](const uint8_t *end_ptr) {
|
|
if (!current_section)
|
|
return; // We have been called before parsing the first line.
|
|
|
|
offset_t end_offset = end_ptr - m_data.GetDataStart();
|
|
auto section_sp = std::make_shared<Section>(
|
|
GetModule(), this, next_section_id++,
|
|
ConstString(toString(*current_section)), eSectionTypeOther,
|
|
/*file_vm_addr*/ 0, /*vm_size*/ 0, section_start,
|
|
end_offset - section_start, /*log2align*/ 0, /*flags*/ 0);
|
|
m_sections_up->AddSection(section_sp);
|
|
unified_section_list.AddSection(section_sp);
|
|
};
|
|
while (!text.empty()) {
|
|
llvm::StringRef line;
|
|
std::tie(line, text) = text.split('\n');
|
|
|
|
llvm::Optional<Record::Kind> next_section = Record::classify(line);
|
|
if (next_section == Record::Line) {
|
|
// Line records logically belong to the preceding Func record, so we put
|
|
// them in the same section.
|
|
next_section = Record::Func;
|
|
}
|
|
if (next_section == current_section)
|
|
continue;
|
|
|
|
// Changing sections, finish off the previous one, if there was any.
|
|
maybe_add_section(line.bytes_begin());
|
|
// And start a new one.
|
|
current_section = next_section;
|
|
section_start = line.bytes_begin() - m_data.GetDataStart();
|
|
}
|
|
// Finally, add the last section.
|
|
maybe_add_section(m_data.GetDataEnd());
|
|
}
|