xref: /src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4) !
1cfca06d7SDimitry Andric //===-- ObjectFileBreakpad.cpp --------------------------------------------===//
294994d37SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
694994d37SDimitry Andric //
794994d37SDimitry Andric //===----------------------------------------------------------------------===//
894994d37SDimitry Andric 
994994d37SDimitry Andric #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
105f29bb8aSDimitry Andric #include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
1194994d37SDimitry Andric #include "lldb/Core/ModuleSpec.h"
1294994d37SDimitry Andric #include "lldb/Core/PluginManager.h"
1394994d37SDimitry Andric #include "lldb/Core/Section.h"
14e3b55780SDimitry Andric #include <optional>
1594994d37SDimitry Andric 
1694994d37SDimitry Andric using namespace lldb;
1794994d37SDimitry Andric using namespace lldb_private;
1894994d37SDimitry Andric using namespace lldb_private::breakpad;
1994994d37SDimitry Andric 
20cfca06d7SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileBreakpad)
21cfca06d7SDimitry Andric 
2294994d37SDimitry Andric namespace {
2394994d37SDimitry Andric struct Header {
2494994d37SDimitry Andric   ArchSpec arch;
2594994d37SDimitry Andric   UUID uuid;
26e3b55780SDimitry Andric   static std::optional<Header> parse(llvm::StringRef text);
2794994d37SDimitry Andric };
2894994d37SDimitry Andric } // namespace
2994994d37SDimitry Andric 
parse(llvm::StringRef text)30e3b55780SDimitry Andric std::optional<Header> Header::parse(llvm::StringRef text) {
315f29bb8aSDimitry Andric   llvm::StringRef line;
3294994d37SDimitry Andric   std::tie(line, text) = text.split('\n');
335f29bb8aSDimitry Andric   auto Module = ModuleRecord::parse(line);
345f29bb8aSDimitry Andric   if (!Module)
35e3b55780SDimitry Andric     return std::nullopt;
3694994d37SDimitry Andric 
3794994d37SDimitry Andric   llvm::Triple triple;
385f29bb8aSDimitry Andric   triple.setArch(Module->Arch);
395f29bb8aSDimitry Andric   triple.setOS(Module->OS);
4094994d37SDimitry Andric 
4194994d37SDimitry Andric   std::tie(line, text) = text.split('\n');
4294994d37SDimitry Andric 
435f29bb8aSDimitry Andric   auto Info = InfoRecord::parse(line);
445f29bb8aSDimitry Andric   UUID uuid = Info && Info->ID ? Info->ID : Module->ID;
455f29bb8aSDimitry Andric   return Header{ArchSpec(triple), std::move(uuid)};
4694994d37SDimitry Andric }
4794994d37SDimitry Andric 
48ead24645SDimitry Andric char ObjectFileBreakpad::ID;
49ead24645SDimitry Andric 
Initialize()5094994d37SDimitry Andric void ObjectFileBreakpad::Initialize() {
5194994d37SDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(),
5294994d37SDimitry Andric                                 GetPluginDescriptionStatic(), CreateInstance,
5394994d37SDimitry Andric                                 CreateMemoryInstance, GetModuleSpecifications);
5494994d37SDimitry Andric }
5594994d37SDimitry Andric 
Terminate()5694994d37SDimitry Andric void ObjectFileBreakpad::Terminate() {
5794994d37SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
5894994d37SDimitry Andric }
5994994d37SDimitry Andric 
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)6094994d37SDimitry Andric ObjectFile *ObjectFileBreakpad::CreateInstance(
61145449b1SDimitry Andric     const ModuleSP &module_sp, DataBufferSP data_sp, offset_t data_offset,
6294994d37SDimitry Andric     const FileSpec *file, offset_t file_offset, offset_t length) {
6394994d37SDimitry Andric   if (!data_sp) {
6494994d37SDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
6594994d37SDimitry Andric     if (!data_sp)
6694994d37SDimitry Andric       return nullptr;
6794994d37SDimitry Andric     data_offset = 0;
6894994d37SDimitry Andric   }
6994994d37SDimitry Andric   auto text = toStringRef(data_sp->GetData());
70e3b55780SDimitry Andric   std::optional<Header> header = Header::parse(text);
7194994d37SDimitry Andric   if (!header)
7294994d37SDimitry Andric     return nullptr;
7394994d37SDimitry Andric 
7494994d37SDimitry Andric   // Update the data to contain the entire file if it doesn't already
7594994d37SDimitry Andric   if (data_sp->GetByteSize() < length) {
7694994d37SDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
7794994d37SDimitry Andric     if (!data_sp)
7894994d37SDimitry Andric       return nullptr;
7994994d37SDimitry Andric     data_offset = 0;
8094994d37SDimitry Andric   }
8194994d37SDimitry Andric 
8294994d37SDimitry Andric   return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,
8394994d37SDimitry Andric                                 file_offset, length, std::move(header->arch),
8494994d37SDimitry Andric                                 std::move(header->uuid));
8594994d37SDimitry Andric }
8694994d37SDimitry Andric 
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)8794994d37SDimitry Andric ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(
88145449b1SDimitry Andric     const ModuleSP &module_sp, WritableDataBufferSP data_sp,
8994994d37SDimitry Andric     const ProcessSP &process_sp, addr_t header_addr) {
9094994d37SDimitry Andric   return nullptr;
9194994d37SDimitry Andric }
9294994d37SDimitry Andric 
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)9394994d37SDimitry Andric size_t ObjectFileBreakpad::GetModuleSpecifications(
9494994d37SDimitry Andric     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
9594994d37SDimitry Andric     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
9694994d37SDimitry Andric   auto text = toStringRef(data_sp->GetData());
97e3b55780SDimitry Andric   std::optional<Header> header = Header::parse(text);
9894994d37SDimitry Andric   if (!header)
9994994d37SDimitry Andric     return 0;
10094994d37SDimitry Andric   ModuleSpec spec(file, std::move(header->arch));
10194994d37SDimitry Andric   spec.GetUUID() = std::move(header->uuid);
10294994d37SDimitry Andric   specs.Append(spec);
10394994d37SDimitry Andric   return 1;
10494994d37SDimitry Andric }
10594994d37SDimitry Andric 
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)10694994d37SDimitry Andric ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp,
10794994d37SDimitry Andric                                        DataBufferSP &data_sp,
10894994d37SDimitry Andric                                        offset_t data_offset,
10994994d37SDimitry Andric                                        const FileSpec *file, offset_t offset,
11094994d37SDimitry Andric                                        offset_t length, ArchSpec arch,
11194994d37SDimitry Andric                                        UUID uuid)
11294994d37SDimitry Andric     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
11394994d37SDimitry Andric       m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}
11494994d37SDimitry Andric 
ParseHeader()11594994d37SDimitry Andric bool ObjectFileBreakpad::ParseHeader() {
11694994d37SDimitry Andric   // We already parsed the header during initialization.
11794994d37SDimitry Andric   return true;
11894994d37SDimitry Andric }
11994994d37SDimitry Andric 
ParseSymtab(Symtab & symtab)120f65dcba8SDimitry Andric void ObjectFileBreakpad::ParseSymtab(Symtab &symtab) {
121f65dcba8SDimitry Andric   // Nothing to do for breakpad files, all information is parsed as debug info
122f65dcba8SDimitry Andric   // which means "lldb_private::Function" objects are used, or symbols are added
123f65dcba8SDimitry Andric   // by the SymbolFileBreakpad::AddSymbols(...) function in the symbol file.
12494994d37SDimitry Andric }
12594994d37SDimitry Andric 
CreateSections(SectionList & unified_section_list)12694994d37SDimitry Andric void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
1275f29bb8aSDimitry Andric   if (m_sections_up)
12894994d37SDimitry Andric     return;
129ead24645SDimitry Andric   m_sections_up = std::make_unique<SectionList>();
13094994d37SDimitry Andric 
131e3b55780SDimitry Andric   std::optional<Record::Kind> current_section;
13294994d37SDimitry Andric   offset_t section_start;
13394994d37SDimitry Andric   llvm::StringRef text = toStringRef(m_data.GetData());
13494994d37SDimitry Andric   uint32_t next_section_id = 1;
13594994d37SDimitry Andric   auto maybe_add_section = [&](const uint8_t *end_ptr) {
1365f29bb8aSDimitry Andric     if (!current_section)
13794994d37SDimitry Andric       return; // We have been called before parsing the first line.
13894994d37SDimitry Andric 
13994994d37SDimitry Andric     offset_t end_offset = end_ptr - m_data.GetDataStart();
14094994d37SDimitry Andric     auto section_sp = std::make_shared<Section>(
14194994d37SDimitry Andric         GetModule(), this, next_section_id++,
1425f29bb8aSDimitry Andric         ConstString(toString(*current_section)), eSectionTypeOther,
14394994d37SDimitry Andric         /*file_vm_addr*/ 0, /*vm_size*/ 0, section_start,
14494994d37SDimitry Andric         end_offset - section_start, /*log2align*/ 0, /*flags*/ 0);
1455f29bb8aSDimitry Andric     m_sections_up->AddSection(section_sp);
14694994d37SDimitry Andric     unified_section_list.AddSection(section_sp);
14794994d37SDimitry Andric   };
14894994d37SDimitry Andric   while (!text.empty()) {
14994994d37SDimitry Andric     llvm::StringRef line;
15094994d37SDimitry Andric     std::tie(line, text) = text.split('\n');
15194994d37SDimitry Andric 
152e3b55780SDimitry Andric     std::optional<Record::Kind> next_section = Record::classify(line);
153c0981da4SDimitry Andric     if (next_section == Record::Line || next_section == Record::Inline) {
154c0981da4SDimitry Andric       // Line/Inline records logically belong to the preceding Func record, so
155c0981da4SDimitry Andric       // we put them in the same section.
1565f29bb8aSDimitry Andric       next_section = Record::Func;
15794994d37SDimitry Andric     }
1585f29bb8aSDimitry Andric     if (next_section == current_section)
15994994d37SDimitry Andric       continue;
16094994d37SDimitry Andric 
16194994d37SDimitry Andric     // Changing sections, finish off the previous one, if there was any.
16294994d37SDimitry Andric     maybe_add_section(line.bytes_begin());
16394994d37SDimitry Andric     // And start a new one.
1645f29bb8aSDimitry Andric     current_section = next_section;
16594994d37SDimitry Andric     section_start = line.bytes_begin() - m_data.GetDataStart();
16694994d37SDimitry Andric   }
16794994d37SDimitry Andric   // Finally, add the last section.
16894994d37SDimitry Andric   maybe_add_section(m_data.GetDataEnd());
16994994d37SDimitry Andric }
170