ObjectFileBreakpad.cpp revision 360784
1//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
10#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
11#include "lldb/Core/ModuleSpec.h"
12#include "lldb/Core/PluginManager.h"
13#include "lldb/Core/Section.h"
14
15using namespace lldb;
16using namespace lldb_private;
17using namespace lldb_private::breakpad;
18
19namespace {
20struct Header {
21  ArchSpec arch;
22  UUID uuid;
23  static llvm::Optional<Header> parse(llvm::StringRef text);
24};
25} // namespace
26
27llvm::Optional<Header> Header::parse(llvm::StringRef text) {
28  llvm::StringRef line;
29  std::tie(line, text) = text.split('\n');
30  auto Module = ModuleRecord::parse(line);
31  if (!Module)
32    return llvm::None;
33
34  llvm::Triple triple;
35  triple.setArch(Module->Arch);
36  triple.setOS(Module->OS);
37
38  std::tie(line, text) = text.split('\n');
39
40  auto Info = InfoRecord::parse(line);
41  UUID uuid = Info && Info->ID ? Info->ID : Module->ID;
42  return Header{ArchSpec(triple), std::move(uuid)};
43}
44
45char ObjectFileBreakpad::ID;
46
47void ObjectFileBreakpad::Initialize() {
48  PluginManager::RegisterPlugin(GetPluginNameStatic(),
49                                GetPluginDescriptionStatic(), CreateInstance,
50                                CreateMemoryInstance, GetModuleSpecifications);
51}
52
53void ObjectFileBreakpad::Terminate() {
54  PluginManager::UnregisterPlugin(CreateInstance);
55}
56
57ConstString ObjectFileBreakpad::GetPluginNameStatic() {
58  static ConstString g_name("breakpad");
59  return g_name;
60}
61
62ObjectFile *ObjectFileBreakpad::CreateInstance(
63    const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset,
64    const FileSpec *file, offset_t file_offset, offset_t length) {
65  if (!data_sp) {
66    data_sp = MapFileData(*file, length, file_offset);
67    if (!data_sp)
68      return nullptr;
69    data_offset = 0;
70  }
71  auto text = toStringRef(data_sp->GetData());
72  llvm::Optional<Header> header = Header::parse(text);
73  if (!header)
74    return nullptr;
75
76  // Update the data to contain the entire file if it doesn't already
77  if (data_sp->GetByteSize() < length) {
78    data_sp = MapFileData(*file, length, file_offset);
79    if (!data_sp)
80      return nullptr;
81    data_offset = 0;
82  }
83
84  return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,
85                                file_offset, length, std::move(header->arch),
86                                std::move(header->uuid));
87}
88
89ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(
90    const ModuleSP &module_sp, DataBufferSP &data_sp,
91    const ProcessSP &process_sp, addr_t header_addr) {
92  return nullptr;
93}
94
95size_t ObjectFileBreakpad::GetModuleSpecifications(
96    const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
97    offset_t file_offset, offset_t length, ModuleSpecList &specs) {
98  auto text = toStringRef(data_sp->GetData());
99  llvm::Optional<Header> header = Header::parse(text);
100  if (!header)
101    return 0;
102  ModuleSpec spec(file, std::move(header->arch));
103  spec.GetUUID() = std::move(header->uuid);
104  specs.Append(spec);
105  return 1;
106}
107
108ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp,
109                                       DataBufferSP &data_sp,
110                                       offset_t data_offset,
111                                       const FileSpec *file, offset_t offset,
112                                       offset_t length, ArchSpec arch,
113                                       UUID uuid)
114    : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
115      m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}
116
117bool ObjectFileBreakpad::ParseHeader() {
118  // We already parsed the header during initialization.
119  return true;
120}
121
122Symtab *ObjectFileBreakpad::GetSymtab() {
123  // TODO
124  return nullptr;
125}
126
127void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
128  if (m_sections_up)
129    return;
130  m_sections_up = std::make_unique<SectionList>();
131
132  llvm::Optional<Record::Kind> current_section;
133  offset_t section_start;
134  llvm::StringRef text = toStringRef(m_data.GetData());
135  uint32_t next_section_id = 1;
136  auto maybe_add_section = [&](const uint8_t *end_ptr) {
137    if (!current_section)
138      return; // We have been called before parsing the first line.
139
140    offset_t end_offset = end_ptr - m_data.GetDataStart();
141    auto section_sp = std::make_shared<Section>(
142        GetModule(), this, next_section_id++,
143        ConstString(toString(*current_section)), eSectionTypeOther,
144        /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start,
145        end_offset - section_start, /*log2align*/ 0, /*flags*/ 0);
146    m_sections_up->AddSection(section_sp);
147    unified_section_list.AddSection(section_sp);
148  };
149  while (!text.empty()) {
150    llvm::StringRef line;
151    std::tie(line, text) = text.split('\n');
152
153    llvm::Optional<Record::Kind> next_section = Record::classify(line);
154    if (next_section == Record::Line) {
155      // Line records logically belong to the preceding Func record, so we put
156      // them in the same section.
157      next_section = Record::Func;
158    }
159    if (next_section == current_section)
160      continue;
161
162    // Changing sections, finish off the previous one, if there was any.
163    maybe_add_section(line.bytes_begin());
164    // And start a new one.
165    current_section = next_section;
166    section_start = line.bytes_begin() - m_data.GetDataStart();
167  }
168  // Finally, add the last section.
169  maybe_add_section(m_data.GetDataEnd());
170}
171