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