Pavel Labath e84f78412b Add llvm-style RTTI to ObjectFile hierarchy
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
2019-07-31 11:57:34 +00:00

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());
}