11f6b2477SPavel Labath //===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===//
21f6b2477SPavel Labath //
31f6b2477SPavel Labath //                     The LLVM Compiler Infrastructure
41f6b2477SPavel Labath //
51f6b2477SPavel Labath // This file is distributed under the University of Illinois Open Source
61f6b2477SPavel Labath // License. See LICENSE.TXT for details.
71f6b2477SPavel Labath //
81f6b2477SPavel Labath //===----------------------------------------------------------------------===//
91f6b2477SPavel Labath 
101f6b2477SPavel Labath #include "Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h"
111f6b2477SPavel Labath #include "lldb/Core/ModuleSpec.h"
121f6b2477SPavel Labath #include "lldb/Core/PluginManager.h"
131f6b2477SPavel Labath #include "lldb/Utility/DataBuffer.h"
141f6b2477SPavel Labath #include "llvm/ADT/StringExtras.h"
151f6b2477SPavel Labath 
161f6b2477SPavel Labath using namespace lldb;
171f6b2477SPavel Labath using namespace lldb_private;
181f6b2477SPavel Labath using namespace lldb_private::breakpad;
191f6b2477SPavel Labath 
201f6b2477SPavel Labath namespace {
211f6b2477SPavel Labath struct Header {
221f6b2477SPavel Labath   ArchSpec arch;
231f6b2477SPavel Labath   UUID uuid;
241f6b2477SPavel Labath   static llvm::Optional<Header> parse(llvm::StringRef text);
251f6b2477SPavel Labath };
261f6b2477SPavel Labath } // namespace
271f6b2477SPavel Labath 
281f6b2477SPavel Labath static llvm::Triple::OSType toOS(llvm::StringRef str) {
291f6b2477SPavel Labath   using llvm::Triple;
301f6b2477SPavel Labath   return llvm::StringSwitch<Triple::OSType>(str)
311f6b2477SPavel Labath       .Case("Linux", Triple::Linux)
321f6b2477SPavel Labath       .Case("mac", Triple::MacOSX)
331f6b2477SPavel Labath       .Case("windows", Triple::Win32)
341f6b2477SPavel Labath       .Default(Triple::UnknownOS);
351f6b2477SPavel Labath }
361f6b2477SPavel Labath 
371f6b2477SPavel Labath static llvm::Triple::ArchType toArch(llvm::StringRef str) {
381f6b2477SPavel Labath   using llvm::Triple;
391f6b2477SPavel Labath   return llvm::StringSwitch<Triple::ArchType>(str)
401f6b2477SPavel Labath       .Case("arm", Triple::arm)
411f6b2477SPavel Labath       .Case("arm64", Triple::aarch64)
421f6b2477SPavel Labath       .Case("mips", Triple::mips)
431f6b2477SPavel Labath       .Case("ppc", Triple::ppc)
441f6b2477SPavel Labath       .Case("ppc64", Triple::ppc64)
451f6b2477SPavel Labath       .Case("s390", Triple::systemz)
461f6b2477SPavel Labath       .Case("sparc", Triple::sparc)
471f6b2477SPavel Labath       .Case("sparcv9", Triple::sparcv9)
481f6b2477SPavel Labath       .Case("x86", Triple::x86)
491f6b2477SPavel Labath       .Case("x86_64", Triple::x86_64)
501f6b2477SPavel Labath       .Default(Triple::UnknownArch);
511f6b2477SPavel Labath }
521f6b2477SPavel Labath 
531f6b2477SPavel Labath static llvm::StringRef consume_front(llvm::StringRef &str, size_t n) {
541f6b2477SPavel Labath   llvm::StringRef result = str.take_front(n);
551f6b2477SPavel Labath   str = str.drop_front(n);
561f6b2477SPavel Labath   return result;
571f6b2477SPavel Labath }
581f6b2477SPavel Labath 
591f6b2477SPavel Labath static UUID parseModuleId(llvm::Triple::OSType os, llvm::StringRef str) {
601f6b2477SPavel Labath   struct uuid_data {
611f6b2477SPavel Labath     llvm::support::ulittle32_t uuid1;
621f6b2477SPavel Labath     llvm::support::ulittle16_t uuid2[2];
631f6b2477SPavel Labath     uint8_t uuid3[8];
641f6b2477SPavel Labath     llvm::support::ulittle32_t age;
651f6b2477SPavel Labath   } data;
661f6b2477SPavel Labath   static_assert(sizeof(data) == 20, "");
671f6b2477SPavel Labath   // The textual module id encoding should be between 33 and 40 bytes long,
681f6b2477SPavel Labath   // depending on the size of the age field, which is of variable length.
691f6b2477SPavel Labath   // The first three chunks of the id are encoded in big endian, so we need to
701f6b2477SPavel Labath   // byte-swap those.
711f6b2477SPavel Labath   if (str.size() < 33 || str.size() > 40)
721f6b2477SPavel Labath     return UUID();
731f6b2477SPavel Labath   uint32_t t;
741f6b2477SPavel Labath   if (to_integer(consume_front(str, 8), t, 16))
751f6b2477SPavel Labath     data.uuid1 = t;
761f6b2477SPavel Labath   else
771f6b2477SPavel Labath     return UUID();
781f6b2477SPavel Labath   for (int i = 0; i < 2; ++i) {
791f6b2477SPavel Labath     if (to_integer(consume_front(str, 4), t, 16))
801f6b2477SPavel Labath       data.uuid2[i] = t;
811f6b2477SPavel Labath     else
821f6b2477SPavel Labath       return UUID();
831f6b2477SPavel Labath   }
841f6b2477SPavel Labath   for (int i = 0; i < 8; ++i) {
851f6b2477SPavel Labath     if (!to_integer(consume_front(str, 2), data.uuid3[i], 16))
861f6b2477SPavel Labath       return UUID();
871f6b2477SPavel Labath   }
881f6b2477SPavel Labath   if (to_integer(str, t, 16))
891f6b2477SPavel Labath     data.age = t;
901f6b2477SPavel Labath   else
911f6b2477SPavel Labath     return UUID();
921f6b2477SPavel Labath 
931f6b2477SPavel Labath   // On non-windows, the age field should always be zero, so we don't include to
941f6b2477SPavel Labath   // match the native uuid format of these platforms.
951f6b2477SPavel Labath   return UUID::fromData(&data, os == llvm::Triple::Win32 ? 20 : 16);
961f6b2477SPavel Labath }
971f6b2477SPavel Labath 
981f6b2477SPavel Labath llvm::Optional<Header> Header::parse(llvm::StringRef text) {
991f6b2477SPavel Labath   // A valid module should start with something like:
1001f6b2477SPavel Labath   // MODULE Linux x86_64 E5894855C35DCCCCCCCCCCCCCCCCCCCC0 a.out
1011f6b2477SPavel Labath   // optionally followed by
1021f6b2477SPavel Labath   // INFO CODE_ID 554889E55DC3CCCCCCCCCCCCCCCCCCCC [a.exe]
1031f6b2477SPavel Labath   llvm::StringRef token, line;
1041f6b2477SPavel Labath   std::tie(line, text) = text.split('\n');
1051f6b2477SPavel Labath   std::tie(token, line) = getToken(line);
1061f6b2477SPavel Labath   if (token != "MODULE")
1071f6b2477SPavel Labath     return llvm::None;
1081f6b2477SPavel Labath 
1091f6b2477SPavel Labath   std::tie(token, line) = getToken(line);
1101f6b2477SPavel Labath   llvm::Triple triple;
1111f6b2477SPavel Labath   triple.setOS(toOS(token));
1121f6b2477SPavel Labath   if (triple.getOS() == llvm::Triple::UnknownOS)
1131f6b2477SPavel Labath     return llvm::None;
1141f6b2477SPavel Labath 
1151f6b2477SPavel Labath   std::tie(token, line) = getToken(line);
1161f6b2477SPavel Labath   triple.setArch(toArch(token));
1171f6b2477SPavel Labath   if (triple.getArch() == llvm::Triple::UnknownArch)
1181f6b2477SPavel Labath     return llvm::None;
1191f6b2477SPavel Labath 
1201f6b2477SPavel Labath   llvm::StringRef module_id;
1211f6b2477SPavel Labath   std::tie(module_id, line) = getToken(line);
1221f6b2477SPavel Labath 
1231f6b2477SPavel Labath   std::tie(line, text) = text.split('\n');
1241f6b2477SPavel Labath   std::tie(token, line) = getToken(line);
1251f6b2477SPavel Labath   if (token == "INFO") {
1261f6b2477SPavel Labath     std::tie(token, line) = getToken(line);
1271f6b2477SPavel Labath     if (token != "CODE_ID")
1281f6b2477SPavel Labath       return llvm::None;
1291f6b2477SPavel Labath 
1301f6b2477SPavel Labath     std::tie(token, line) = getToken(line);
1311f6b2477SPavel Labath     // If we don't have any text following the code id (e.g. on linux), we
1321f6b2477SPavel Labath     // should use the module id as UUID. Otherwise, we revert back to the module
1331f6b2477SPavel Labath     // id.
1341f6b2477SPavel Labath     if (line.trim().empty()) {
1351f6b2477SPavel Labath       UUID uuid;
1361f6b2477SPavel Labath       if (uuid.SetFromStringRef(token, token.size() / 2) != token.size())
1371f6b2477SPavel Labath         return llvm::None;
1381f6b2477SPavel Labath 
1391f6b2477SPavel Labath       return Header{ArchSpec(triple), uuid};
1401f6b2477SPavel Labath     }
1411f6b2477SPavel Labath   }
1421f6b2477SPavel Labath 
1431f6b2477SPavel Labath   // We reach here if we don't have a INFO CODE_ID section, or we chose not to
1441f6b2477SPavel Labath   // use it. In either case, we need to properly decode the module id, whose
1451f6b2477SPavel Labath   // fields are encoded in big-endian.
1461f6b2477SPavel Labath   UUID uuid = parseModuleId(triple.getOS(), module_id);
1471f6b2477SPavel Labath   if (!uuid)
1481f6b2477SPavel Labath     return llvm::None;
1491f6b2477SPavel Labath 
1501f6b2477SPavel Labath   return Header{ArchSpec(triple), uuid};
1511f6b2477SPavel Labath }
1521f6b2477SPavel Labath 
1531f6b2477SPavel Labath void ObjectFileBreakpad::Initialize() {
1541f6b2477SPavel Labath   PluginManager::RegisterPlugin(GetPluginNameStatic(),
1551f6b2477SPavel Labath                                 GetPluginDescriptionStatic(), CreateInstance,
156*871f2b65SPavel Labath                                 CreateMemoryInstance, GetModuleSpecifications);
1571f6b2477SPavel Labath }
1581f6b2477SPavel Labath 
1591f6b2477SPavel Labath void ObjectFileBreakpad::Terminate() {
1601f6b2477SPavel Labath   PluginManager::UnregisterPlugin(CreateInstance);
1611f6b2477SPavel Labath }
1621f6b2477SPavel Labath 
1631f6b2477SPavel Labath ConstString ObjectFileBreakpad::GetPluginNameStatic() {
1641f6b2477SPavel Labath   static ConstString g_name("breakpad");
1651f6b2477SPavel Labath   return g_name;
1661f6b2477SPavel Labath }
1671f6b2477SPavel Labath 
1681f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateInstance(
1691f6b2477SPavel Labath     const ModuleSP &module_sp, DataBufferSP &data_sp, offset_t data_offset,
1701f6b2477SPavel Labath     const FileSpec *file, offset_t file_offset, offset_t length) {
1711f6b2477SPavel Labath   if (!data_sp) {
1721f6b2477SPavel Labath     data_sp = MapFileData(*file, length, file_offset);
1731f6b2477SPavel Labath     if (!data_sp)
1741f6b2477SPavel Labath       return nullptr;
1751f6b2477SPavel Labath     data_offset = 0;
1761f6b2477SPavel Labath   }
1771f6b2477SPavel Labath   auto text = toStringRef(data_sp->GetData());
1781f6b2477SPavel Labath   llvm::Optional<Header> header = Header::parse(text);
1791f6b2477SPavel Labath   if (!header)
1801f6b2477SPavel Labath     return nullptr;
1811f6b2477SPavel Labath 
1821f6b2477SPavel Labath   // Update the data to contain the entire file if it doesn't already
1831f6b2477SPavel Labath   if (data_sp->GetByteSize() < length) {
1841f6b2477SPavel Labath     data_sp = MapFileData(*file, length, file_offset);
1851f6b2477SPavel Labath     if (!data_sp)
1861f6b2477SPavel Labath       return nullptr;
1871f6b2477SPavel Labath     data_offset = 0;
1881f6b2477SPavel Labath   }
1891f6b2477SPavel Labath 
1901f6b2477SPavel Labath   return new ObjectFileBreakpad(module_sp, data_sp, data_offset, file,
1911f6b2477SPavel Labath                                 file_offset, length, std::move(header->arch),
1921f6b2477SPavel Labath                                 std::move(header->uuid));
1931f6b2477SPavel Labath }
1941f6b2477SPavel Labath 
1951f6b2477SPavel Labath ObjectFile *ObjectFileBreakpad::CreateMemoryInstance(
1961f6b2477SPavel Labath     const ModuleSP &module_sp, DataBufferSP &data_sp,
1971f6b2477SPavel Labath     const ProcessSP &process_sp, addr_t header_addr) {
1981f6b2477SPavel Labath   return nullptr;
1991f6b2477SPavel Labath }
2001f6b2477SPavel Labath 
2011f6b2477SPavel Labath size_t ObjectFileBreakpad::GetModuleSpecifications(
2021f6b2477SPavel Labath     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
2031f6b2477SPavel Labath     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
2041f6b2477SPavel Labath   auto text = toStringRef(data_sp->GetData());
2051f6b2477SPavel Labath   llvm::Optional<Header> header = Header::parse(text);
2061f6b2477SPavel Labath   if (!header)
2071f6b2477SPavel Labath     return 0;
2081f6b2477SPavel Labath   ModuleSpec spec(file, std::move(header->arch));
2091f6b2477SPavel Labath   spec.GetUUID() = std::move(header->uuid);
2101f6b2477SPavel Labath   specs.Append(spec);
2111f6b2477SPavel Labath   return 1;
2121f6b2477SPavel Labath }
2131f6b2477SPavel Labath 
2141f6b2477SPavel Labath ObjectFileBreakpad::ObjectFileBreakpad(const ModuleSP &module_sp,
2151f6b2477SPavel Labath                                        DataBufferSP &data_sp,
2161f6b2477SPavel Labath                                        offset_t data_offset,
2171f6b2477SPavel Labath                                        const FileSpec *file, offset_t offset,
2181f6b2477SPavel Labath                                        offset_t length, ArchSpec arch,
2191f6b2477SPavel Labath                                        UUID uuid)
2201f6b2477SPavel Labath     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
2211f6b2477SPavel Labath       m_arch(std::move(arch)), m_uuid(std::move(uuid)) {}
2221f6b2477SPavel Labath 
2231f6b2477SPavel Labath bool ObjectFileBreakpad::ParseHeader() {
2241f6b2477SPavel Labath   // We already parsed the header during initialization.
2251f6b2477SPavel Labath   return true;
2261f6b2477SPavel Labath }
2271f6b2477SPavel Labath 
2281f6b2477SPavel Labath Symtab *ObjectFileBreakpad::GetSymtab() {
2291f6b2477SPavel Labath   // TODO
2301f6b2477SPavel Labath   return nullptr;
2311f6b2477SPavel Labath }
2321f6b2477SPavel Labath 
2331f6b2477SPavel Labath bool ObjectFileBreakpad::GetArchitecture(ArchSpec &arch) {
2341f6b2477SPavel Labath   arch = m_arch;
2351f6b2477SPavel Labath   return true;
2361f6b2477SPavel Labath }
2371f6b2477SPavel Labath 
2381f6b2477SPavel Labath bool ObjectFileBreakpad::GetUUID(UUID *uuid) {
2391f6b2477SPavel Labath   *uuid = m_uuid;
2401f6b2477SPavel Labath   return true;
2411f6b2477SPavel Labath }
2421f6b2477SPavel Labath 
2431f6b2477SPavel Labath void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
2441f6b2477SPavel Labath   // TODO
2451f6b2477SPavel Labath }
246