diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:53:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:53:01 +0000 |
commit | ead246455adf1a215ec2715dad6533073a6beb4e (patch) | |
tree | f3f97a47d77053bf96fe74cdbd6fae74380e8a92 /source/Plugins/ObjectFile | |
parent | fdb00c4408990a0a63ef7f496d809ce59f263bc5 (diff) |
Notes
Diffstat (limited to 'source/Plugins/ObjectFile')
8 files changed, 379 insertions, 218 deletions
diff --git a/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index d489eaf11115a..de17d986a8608 100644 --- a/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -16,7 +16,19 @@ using namespace lldb_private; using namespace lldb_private::breakpad; namespace { -enum class Token { Unknown, Module, Info, CodeID, File, Func, Public, Stack, CFI, Init }; +enum class Token { + Unknown, + Module, + Info, + CodeID, + File, + Func, + Public, + Stack, + CFI, + Init, + Win, +}; } template<typename T> @@ -33,6 +45,7 @@ template <> Token stringTo<Token>(llvm::StringRef Str) { .Case("STACK", Token::Stack) .Case("CFI", Token::CFI) .Case("INIT", Token::Init) + .Case("WIN", Token::Win) .Default(Token::Unknown); } @@ -127,6 +140,8 @@ llvm::Optional<Record::Kind> Record::classify(llvm::StringRef Line) { switch (Tok) { case Token::CFI: return Record::StackCFI; + case Token::Win: + return Record::StackWin; default: return llvm::None; } @@ -134,13 +149,13 @@ llvm::Optional<Record::Kind> Record::classify(llvm::StringRef Line) { case Token::Unknown: // Optimistically assume that any unrecognised token means this is a line // record, those don't have a special keyword and start directly with a - // hex number. CODE_ID should never be at the start of a line, but if it - // is, it can be treated the same way as a garbled line record. + // hex number. return Record::Line; case Token::CodeID: case Token::CFI: case Token::Init: + case Token::Win: // These should never appear at the start of a valid record. return llvm::None; } @@ -390,6 +405,81 @@ llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS, return OS << " " << R.UnwindRules; } +llvm::Optional<StackWinRecord> StackWinRecord::parse(llvm::StringRef Line) { + // STACK WIN type rva code_size prologue_size epilogue_size parameter_size + // saved_register_size local_size max_stack_size has_program_string + // program_string_OR_allocates_base_pointer + + if (consume<Token>(Line) != Token::Stack) + return llvm::None; + if (consume<Token>(Line) != Token::Win) + return llvm::None; + + llvm::StringRef Str; + uint8_t Type; + std::tie(Str, Line) = getToken(Line); + // Right now we only support the "FrameData" frame type. + if (!to_integer(Str, Type) || FrameType(Type) != FrameType::FrameData) + return llvm::None; + + lldb::addr_t RVA; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, RVA, 16)) + return llvm::None; + + lldb::addr_t CodeSize; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, CodeSize, 16)) + return llvm::None; + + // Skip fields which we aren't using right now. + std::tie(Str, Line) = getToken(Line); // prologue_size + std::tie(Str, Line) = getToken(Line); // epilogue_size + + lldb::addr_t ParameterSize; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, ParameterSize, 16)) + return llvm::None; + + lldb::addr_t SavedRegisterSize; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, SavedRegisterSize, 16)) + return llvm::None; + + lldb::addr_t LocalSize; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, LocalSize, 16)) + return llvm::None; + + std::tie(Str, Line) = getToken(Line); // max_stack_size + + uint8_t HasProgramString; + std::tie(Str, Line) = getToken(Line); + if (!to_integer(Str, HasProgramString)) + return llvm::None; + // FrameData records should always have a program string. + if (!HasProgramString) + return llvm::None; + + return StackWinRecord(RVA, CodeSize, ParameterSize, SavedRegisterSize, + LocalSize, Line.trim()); +} + +bool breakpad::operator==(const StackWinRecord &L, const StackWinRecord &R) { + return L.RVA == R.RVA && L.CodeSize == R.CodeSize && + L.ParameterSize == R.ParameterSize && + L.SavedRegisterSize == R.SavedRegisterSize && + L.LocalSize == R.LocalSize && L.ProgramString == R.ProgramString; +} + +llvm::raw_ostream &breakpad::operator<<(llvm::raw_ostream &OS, + const StackWinRecord &R) { + return OS << llvm::formatv( + "STACK WIN 4 {0:x-} {1:x-} ? ? {2} {3} {4} ? 1 {5}", R.RVA, + R.CodeSize, R.ParameterSize, R.SavedRegisterSize, R.LocalSize, + R.ProgramString); +} + llvm::StringRef breakpad::toString(Record::Kind K) { switch (K) { case Record::Module: @@ -406,6 +496,8 @@ llvm::StringRef breakpad::toString(Record::Kind K) { return "PUBLIC"; case Record::StackCFI: return "STACK CFI"; + case Record::StackWin: + return "STACK WIN"; } llvm_unreachable("Unknown record kind!"); } diff --git a/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h b/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h index 5d5cdb319c10e..27bef975125dd 100644 --- a/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h +++ b/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h @@ -20,7 +20,7 @@ namespace breakpad { class Record { public: - enum Kind { Module, Info, File, Func, Line, Public, StackCFI }; + enum Kind { Module, Info, File, Func, Line, Public, StackCFI, StackWin }; /// Attempt to guess the kind of the record present in the argument without /// doing a full parse. The returned kind will always be correct for valid @@ -157,6 +157,29 @@ public: bool operator==(const StackCFIRecord &L, const StackCFIRecord &R); llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackCFIRecord &R); +class StackWinRecord : public Record { +public: + static llvm::Optional<StackWinRecord> parse(llvm::StringRef Line); + + StackWinRecord(lldb::addr_t RVA, lldb::addr_t CodeSize, + lldb::addr_t ParameterSize, lldb::addr_t SavedRegisterSize, + lldb::addr_t LocalSize, llvm::StringRef ProgramString) + : Record(StackWin), RVA(RVA), CodeSize(CodeSize), + ParameterSize(ParameterSize), SavedRegisterSize(SavedRegisterSize), + LocalSize(LocalSize), ProgramString(ProgramString) {} + + enum class FrameType : uint8_t { FPO = 0, FrameData = 4 }; + lldb::addr_t RVA; + lldb::addr_t CodeSize; + lldb::addr_t ParameterSize; + lldb::addr_t SavedRegisterSize; + lldb::addr_t LocalSize; + llvm::StringRef ProgramString; +}; + +bool operator==(const StackWinRecord &L, const StackWinRecord &R); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackWinRecord &R); + } // namespace breakpad } // namespace lldb_private diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp index 60dd9f9cecf0f..3b9e0e2092a93 100644 --- a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -42,6 +42,8 @@ llvm::Optional<Header> Header::parse(llvm::StringRef text) { return Header{ArchSpec(triple), std::move(uuid)}; } +char ObjectFileBreakpad::ID; + void ObjectFileBreakpad::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -125,7 +127,7 @@ Symtab *ObjectFileBreakpad::GetSymtab() { void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; - m_sections_up = llvm::make_unique<SectionList>(); + m_sections_up = std::make_unique<SectionList>(); llvm::Optional<Record::Kind> current_section; offset_t section_start; diff --git a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h index e8885e0cc8982..cb4bba01fb718 100644 --- a/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h +++ b/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h @@ -48,6 +48,13 @@ public: uint32_t GetPluginVersion() override { return 1; } + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + // ObjectFile Protocol. bool ParseHeader() override; @@ -78,8 +85,6 @@ public: UUID GetUUID() override { return m_uuid; } - FileSpecList GetDebugSymbolFilePaths() override { return FileSpecList(); } - uint32_t GetDependentModules(FileSpecList &files) override { return 0; } Type CalculateType() override { return eTypeDebugInfo; } diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index d62afa34bbe81..3f8502548fc25 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -18,6 +18,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" @@ -29,12 +30,13 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" - #include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MipsABIFlags.h" @@ -80,41 +82,6 @@ const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00; const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01; const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; -// LLDB_NT_OWNER_CORE and LLDB_NT_OWNER_LINUX note contants -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_SIGINFO 0x53494749 -#define NT_FILE 0x46494c45 -#define NT_PRXFPREG 0x46e62b7f -#define NT_PPC_VMX 0x100 -#define NT_PPC_SPE 0x101 -#define NT_PPC_VSX 0x102 -#define NT_386_TLS 0x200 -#define NT_386_IOPERM 0x201 -#define NT_X86_XSTATE 0x202 -#define NT_S390_HIGH_GPRS 0x300 -#define NT_S390_TIMER 0x301 -#define NT_S390_TODCMP 0x302 -#define NT_S390_TODPREG 0x303 -#define NT_S390_CTRS 0x304 -#define NT_S390_PREFIX 0x305 -#define NT_S390_LAST_BREAK 0x306 -#define NT_S390_SYSTEM_CALL 0x307 -#define NT_S390_TDB 0x308 -#define NT_S390_VXRS_LOW 0x309 -#define NT_S390_VXRS_HIGH 0x30a -#define NT_ARM_VFP 0x400 -#define NT_ARM_TLS 0x401 -#define NT_ARM_HW_BREAK 0x402 -#define NT_ARM_HW_WATCH 0x403 -#define NT_ARM_SYSTEM_CALL 0x404 -#define NT_METAG_CBUF 0x500 -#define NT_METAG_RPIPE 0x501 -#define NT_METAG_TLS 0x502 - //===----------------------------------------------------------------------===// /// \class ELFRelocation /// Generic wrapper for ELFRel and ELFRela. @@ -264,8 +231,7 @@ bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { const char *cstr = data.GetCStr(offset, llvm::alignTo(n_namesz, 4)); if (cstr == nullptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); - if (log) - log->Printf("Failed to parse note name lacking nul terminator"); + LLDB_LOGF(log, "Failed to parse note name lacking nul terminator"); return false; } @@ -333,6 +299,8 @@ static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) { return LLDB_INVALID_CPUTYPE; } +char ObjectFileELF::ID; + // Arbitrary constant used as UUID prefix for core files. const uint32_t ObjectFileELF::g_core_uuid_magic(0xE210C); @@ -429,67 +397,9 @@ bool ObjectFileELF::MagicBytesMatch(DataBufferSP &data_sp, return false; } -/* - * crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c - * - * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - * code or tables extracted from it, as desired without restriction. - */ -static uint32_t calc_crc32(uint32_t crc, const void *buf, size_t size) { - static const uint32_t g_crc32_tab[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; - const uint8_t *p = (const uint8_t *)buf; - - crc = crc ^ ~0U; - while (size--) - crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); - return crc ^ ~0U; -} - -static uint32_t calc_gnu_debuglink_crc32(const void *buf, size_t size) { - return calc_crc32(0U, buf, size); +static uint32_t calc_crc32(uint32_t init, const DataExtractor &data) { + return llvm::crc32( + init, llvm::makeArrayRef(data.GetDataStart(), data.GetByteSize())); } uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( @@ -509,8 +419,7 @@ uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( break; } - core_notes_crc = calc_crc32(core_notes_crc, segment_data.GetDataStart(), - segment_data.GetByteSize()); + core_notes_crc = calc_crc32(core_notes_crc, segment_data); } } @@ -608,10 +517,9 @@ size_t ObjectFileELF::GetModuleSpecifications( llvm::Triple::OSType spec_ostype = spec.GetArchitecture().GetTriple().getOS(); - if (log) - log->Printf("ObjectFileELF::%s file '%s' module OSABI: %s", - __FUNCTION__, file.GetPath().c_str(), - OSABIAsCString(header.e_ident[EI_OSABI])); + LLDB_LOGF(log, "ObjectFileELF::%s file '%s' module OSABI: %s", + __FUNCTION__, file.GetPath().c_str(), + OSABIAsCString(header.e_ident[EI_OSABI])); // SetArchitecture should have set the vendor to unknown vendor = spec.GetArchitecture().GetTriple().getVendor(); @@ -623,10 +531,10 @@ size_t ObjectFileELF::GetModuleSpecifications( GetOsFromOSABI(header.e_ident[EI_OSABI], ostype); assert(spec_ostype == ostype); if (spec_ostype != llvm::Triple::OSType::UnknownOS) { - if (log) - log->Printf("ObjectFileELF::%s file '%s' set ELF module OS type " - "from ELF header OSABI.", - __FUNCTION__, file.GetPath().c_str()); + LLDB_LOGF(log, + "ObjectFileELF::%s file '%s' set ELF module OS type " + "from ELF header OSABI.", + __FUNCTION__, file.GetPath().c_str()); } data_sp = MapFileData(file, -1, file_offset); @@ -652,12 +560,12 @@ size_t ObjectFileELF::GetModuleSpecifications( llvm::Triple &spec_triple = spec.GetArchitecture().GetTriple(); - if (log) - log->Printf("ObjectFileELF::%s file '%s' module set to triple: %s " - "(architecture %s)", - __FUNCTION__, file.GetPath().c_str(), - spec_triple.getTriple().c_str(), - spec.GetArchitecture().GetArchitectureName()); + LLDB_LOGF(log, + "ObjectFileELF::%s file '%s' module set to triple: %s " + "(architecture %s)", + __FUNCTION__, file.GetPath().c_str(), + spec_triple.getTriple().c_str(), + spec.GetArchitecture().GetArchitectureName()); if (!uuid.IsValid()) { uint32_t core_notes_crc = 0; @@ -682,8 +590,7 @@ size_t ObjectFileELF::GetModuleSpecifications( core_notes_crc = CalculateELFNotesSegmentsCRC32(program_headers, data); } else { - gnu_debuglink_crc = calc_gnu_debuglink_crc32( - data.GetDataStart(), data.GetByteSize()); + gnu_debuglink_crc = calc_crc32(0, data); } } using u32le = llvm::support::ulittle32_t; @@ -721,27 +628,16 @@ ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length) - : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), - m_header(), m_uuid(), m_gnu_debuglink_file(), m_gnu_debuglink_crc(0), - m_program_headers(), m_section_headers(), m_dynamic_symbols(), - m_filespec_up(), m_entry_point_address(), m_arch_spec() { + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) { if (file) m_file = *file; - ::memset(&m_header, 0, sizeof(m_header)); } ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp, DataBufferSP &header_data_sp, const lldb::ProcessSP &process_sp, addr_t header_addr) - : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), - m_header(), m_uuid(), m_gnu_debuglink_file(), m_gnu_debuglink_crc(0), - m_program_headers(), m_section_headers(), m_dynamic_symbols(), - m_filespec_up(), m_entry_point_address(), m_arch_spec() { - ::memset(&m_header, 0, sizeof(m_header)); -} - -ObjectFileELF::~ObjectFileELF() {} + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {} bool ObjectFileELF::IsExecutable() const { return ((m_header.e_type & ET_EXEC) != 0) || (m_header.e_entry != 0); @@ -872,8 +768,7 @@ UUID ObjectFileELF::GetUUID() { } } else { if (!m_gnu_debuglink_crc) - m_gnu_debuglink_crc = calc_gnu_debuglink_crc32(m_data.GetDataStart(), - m_data.GetByteSize()); + m_gnu_debuglink_crc = calc_crc32(0, m_data); if (m_gnu_debuglink_crc) { // Use 4 bytes of crc from the .gnu_debuglink section. u32le data(m_gnu_debuglink_crc); @@ -885,14 +780,10 @@ UUID ObjectFileELF::GetUUID() { return m_uuid; } -lldb_private::FileSpecList ObjectFileELF::GetDebugSymbolFilePaths() { - FileSpecList file_spec_list; - - if (!m_gnu_debuglink_file.empty()) { - FileSpec file_spec(m_gnu_debuglink_file); - file_spec_list.Append(file_spec); - } - return file_spec_list; +llvm::Optional<FileSpec> ObjectFileELF::GetDebugLink() { + if (m_gnu_debuglink_file.empty()) + return llvm::None; + return FileSpec(m_gnu_debuglink_file); } uint32_t ObjectFileELF::GetDependentModules(FileSpecList &files) { @@ -1120,9 +1011,8 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, return error; } - if (log) - log->Printf("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, - __FUNCTION__, note.n_name.c_str(), note.n_type); + LLDB_LOGF(log, "ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, + __FUNCTION__, note.n_name.c_str(), note.n_type); // Process FreeBSD ELF notes. if ((note.n_name == LLDB_NT_OWNER_FREEBSD) && @@ -1147,11 +1037,11 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().setOSName(os_name); arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 - ".%" PRIu32, - __FUNCTION__, version_major, version_minor, - static_cast<uint32_t>(version_info % 1000)); + LLDB_LOGF(log, + "ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 + ".%" PRIu32, + __FUNCTION__, version_major, version_minor, + static_cast<uint32_t>(version_info % 1000)); } // Process GNU ELF notes. else if (note.n_name == LLDB_NT_OWNER_GNU) { @@ -1172,12 +1062,11 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); arch_spec.GetTriple().setVendor( llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf( - "ObjectFileELF::%s detected Linux, min version %" PRIu32 - ".%" PRIu32 ".%" PRIu32, - __FUNCTION__, version_info[1], version_info[2], - version_info[3]); + LLDB_LOGF(log, + "ObjectFileELF::%s detected Linux, min version %" PRIu32 + ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); // FIXME we have the minimal version number, we could be propagating // that. version_info[1] = OS Major, version_info[2] = OS Minor, // version_info[3] = Revision. @@ -1186,30 +1075,28 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); arch_spec.GetTriple().setVendor( llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf("ObjectFileELF::%s detected Hurd (unsupported), min " - "version %" PRIu32 ".%" PRIu32 ".%" PRIu32, - __FUNCTION__, version_info[1], version_info[2], - version_info[3]); + LLDB_LOGF(log, + "ObjectFileELF::%s detected Hurd (unsupported), min " + "version %" PRIu32 ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); break; case LLDB_NT_GNU_ABI_OS_SOLARIS: arch_spec.GetTriple().setOS(llvm::Triple::OSType::Solaris); arch_spec.GetTriple().setVendor( llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf( - "ObjectFileELF::%s detected Solaris, min version %" PRIu32 - ".%" PRIu32 ".%" PRIu32, - __FUNCTION__, version_info[1], version_info[2], - version_info[3]); + LLDB_LOGF(log, + "ObjectFileELF::%s detected Solaris, min version %" PRIu32 + ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); break; default: - if (log) - log->Printf( - "ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 - ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, - __FUNCTION__, version_info[0], version_info[1], - version_info[2], version_info[3]); + LLDB_LOGF(log, + "ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 + ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[0], version_info[1], + version_info[2], version_info[3]); break; } } @@ -1618,9 +1505,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, section_size) == section_size)) { Status error = RefineModuleDetailsFromNote(data, arch_spec, uuid); if (error.Fail()) { - if (log) - log->Printf("ObjectFileELF::%s ELF note processing failed: %s", - __FUNCTION__, error.AsCString()); + LLDB_LOGF(log, "ObjectFileELF::%s ELF note processing failed: %s", + __FUNCTION__, error.AsCString()); } } } @@ -1790,6 +1676,8 @@ class VMAddressProvider { VMMap Segments = VMMap(Alloc); VMMap Sections = VMMap(Alloc); lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + size_t SegmentCount = 0; + std::string SegmentName; VMRange GetVMRange(const ELFSectionHeader &H) { addr_t Address = H.sh_addr; @@ -1804,18 +1692,23 @@ class VMAddressProvider { } public: - VMAddressProvider(ObjectFile::Type Type) : ObjectType(Type) {} + VMAddressProvider(ObjectFile::Type Type, llvm::StringRef SegmentName) + : ObjectType(Type), SegmentName(SegmentName) {} + + std::string GetNextSegmentName() const { + return llvm::formatv("{0}[{1}]", SegmentName, SegmentCount).str(); + } llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) { if (H.p_memsz == 0) { - LLDB_LOG(Log, - "Ignoring zero-sized PT_LOAD segment. Corrupt object file?"); + LLDB_LOG(Log, "Ignoring zero-sized {0} segment. Corrupt object file?", + SegmentName); return llvm::None; } if (Segments.overlaps(H.p_vaddr, H.p_vaddr + H.p_memsz)) { - LLDB_LOG(Log, - "Ignoring overlapping PT_LOAD segment. Corrupt object file?"); + LLDB_LOG(Log, "Ignoring overlapping {0} segment. Corrupt object file?", + SegmentName); return llvm::None; } return VMRange(H.p_vaddr, H.p_memsz); @@ -1850,6 +1743,7 @@ public: void AddSegment(const VMRange &Range, SectionSP Seg) { Segments.insert(Range.GetRangeBase(), Range.GetRangeEnd(), std::move(Seg)); + ++SegmentCount; } void AddSection(SectionAddressInfo Info, SectionSP Sect) { @@ -1867,29 +1761,32 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; - m_sections_up = llvm::make_unique<SectionList>(); - VMAddressProvider address_provider(GetType()); + m_sections_up = std::make_unique<SectionList>(); + VMAddressProvider regular_provider(GetType(), "PT_LOAD"); + VMAddressProvider tls_provider(GetType(), "PT_TLS"); - size_t LoadID = 0; for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { const ELFProgramHeader &PHdr = EnumPHdr.value(); - if (PHdr.p_type != PT_LOAD) + if (PHdr.p_type != PT_LOAD && PHdr.p_type != PT_TLS) continue; - auto InfoOr = address_provider.GetAddressInfo(PHdr); + VMAddressProvider &provider = + PHdr.p_type == PT_TLS ? tls_provider : regular_provider; + auto InfoOr = provider.GetAddressInfo(PHdr); if (!InfoOr) continue; - ConstString Name(("PT_LOAD[" + llvm::Twine(LoadID++) + "]").str()); uint32_t Log2Align = llvm::Log2_64(std::max<elf_xword>(PHdr.p_align, 1)); SectionSP Segment = std::make_shared<Section>( - GetModule(), this, SegmentID(EnumPHdr.index()), Name, - eSectionTypeContainer, InfoOr->GetRangeBase(), InfoOr->GetByteSize(), - PHdr.p_offset, PHdr.p_filesz, Log2Align, /*flags*/ 0); + GetModule(), this, SegmentID(EnumPHdr.index()), + ConstString(provider.GetNextSegmentName()), eSectionTypeContainer, + InfoOr->GetRangeBase(), InfoOr->GetByteSize(), PHdr.p_offset, + PHdr.p_filesz, Log2Align, /*flags*/ 0); Segment->SetPermissions(GetPermissions(PHdr)); + Segment->SetIsThreadSpecific(PHdr.p_type == PT_TLS); m_sections_up->AddSection(Segment); - address_provider.AddSegment(*InfoOr, std::move(Segment)); + provider.AddSegment(*InfoOr, std::move(Segment)); } ParseSectionHeaders(); @@ -1904,7 +1801,9 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { const uint64_t file_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size; - auto InfoOr = address_provider.GetAddressInfo(header); + VMAddressProvider &provider = + header.sh_flags & SHF_TLS ? tls_provider : regular_provider; + auto InfoOr = provider.GetAddressInfo(header); if (!InfoOr) continue; @@ -1935,13 +1834,77 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) { section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS); (InfoOr->Segment ? InfoOr->Segment->GetChildren() : *m_sections_up) .AddSection(section_sp); - address_provider.AddSection(std::move(*InfoOr), std::move(section_sp)); + provider.AddSection(std::move(*InfoOr), std::move(section_sp)); } // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the // unified section list. if (GetType() != eTypeDebugInfo) unified_section_list = *m_sections_up; + + // If there's a .gnu_debugdata section, we'll try to read the .symtab that's + // embedded in there and replace the one in the original object file (if any). + // If there's none in the orignal object file, we add it to it. + if (auto gdd_obj_file = GetGnuDebugDataObjectFile()) { + if (auto gdd_objfile_section_list = gdd_obj_file->GetSectionList()) { + if (SectionSP symtab_section_sp = + gdd_objfile_section_list->FindSectionByType( + eSectionTypeELFSymbolTable, true)) { + SectionSP module_section_sp = unified_section_list.FindSectionByType( + eSectionTypeELFSymbolTable, true); + if (module_section_sp) + unified_section_list.ReplaceSection(module_section_sp->GetID(), + symtab_section_sp); + else + unified_section_list.AddSection(symtab_section_sp); + } + } + } +} + +std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() { + if (m_gnu_debug_data_object_file != nullptr) + return m_gnu_debug_data_object_file; + + SectionSP section = + GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata")); + if (!section) + return nullptr; + + if (!lldb_private::lzma::isAvailable()) { + GetModule()->ReportWarning( + "No LZMA support found for reading .gnu_debugdata section"); + return nullptr; + } + + // Uncompress the data + DataExtractor data; + section->GetSectionData(data); + llvm::SmallVector<uint8_t, 0> uncompressedData; + auto err = lldb_private::lzma::uncompress(data.GetData(), uncompressedData); + if (err) { + GetModule()->ReportWarning( + "An error occurred while decompression the section %s: %s", + section->GetName().AsCString(), llvm::toString(std::move(err)).c_str()); + return nullptr; + } + + // Construct ObjectFileELF object from decompressed buffer + DataBufferSP gdd_data_buf( + new DataBufferHeap(uncompressedData.data(), uncompressedData.size())); + auto fspec = GetFileSpec().CopyByAppendingPathComponent( + llvm::StringRef("gnu_debugdata")); + m_gnu_debug_data_object_file.reset(new ObjectFileELF( + GetModule(), gdd_data_buf, 0, &fspec, 0, gdd_data_buf->GetByteSize())); + + // This line is essential; otherwise a breakpoint can be set but not hit. + m_gnu_debug_data_object_file->SetType(ObjectFile::eTypeDebugInfo); + + ArchSpec spec = m_gnu_debug_data_object_file->GetArchitecture(); + if (spec && m_gnu_debug_data_object_file->SetModulesArchitecture(spec)) + return m_gnu_debug_data_object_file; + + return nullptr; } // Find the arm/aarch64 mapping symbol character in the given symbol name. @@ -2246,8 +2209,6 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, bool is_global = symbol.getBinding() == STB_GLOBAL; uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags; - bool is_mangled = (symbol_name[0] == '_' && symbol_name[1] == 'Z'); - llvm::StringRef symbol_ref(symbol_name); // Symbol names may contain @VERSION suffixes. Find those and strip them @@ -2255,7 +2216,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, size_t version_pos = symbol_ref.find('@'); bool has_suffix = version_pos != llvm::StringRef::npos; llvm::StringRef symbol_bare = symbol_ref.substr(0, version_pos); - Mangled mangled(ConstString(symbol_bare), is_mangled); + Mangled mangled(symbol_bare); // Now append the suffix back to mangled and unmangled names. Only do it if // the demangling was successful (string is not empty). @@ -2486,14 +2447,11 @@ static unsigned ParsePLTRelocations( break; const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); - bool is_mangled = - symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false; uint64_t plt_index = plt_offset + i * plt_entsize; Symbol jump_symbol( i + start_id, // Symbol table index symbol_name, // symbol name. - is_mangled, // is the symbol name mangled? eSymbolTypeTrampoline, // Type of this symbol false, // Is this globally visible? false, // Is this symbol debug info? @@ -2654,7 +2612,7 @@ unsigned ObjectFileELF::ApplyRelocations( ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN))) { Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); - log->Printf("Failed to apply debug info relocations"); + LLDB_LOGF(log, "Failed to apply debug info relocations"); break; } uint32_t truncated_addr = (value & 0xFFFFFFFF); @@ -2749,19 +2707,29 @@ Symtab *ObjectFileELF::GetSymtab() { // while the reverse is not necessarily true. Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); - if (!symtab) { - // The symtab section is non-allocable and can be stripped, so if it - // doesn't exist then use the dynsym section which should always be - // there. - symtab = - section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) - .get(); - } if (symtab) { m_symtab_up.reset(new Symtab(symtab->GetObjectFile())); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab); } + // The symtab section is non-allocable and can be stripped, while the + // .dynsym section which should always be always be there. To support the + // minidebuginfo case we parse .dynsym when there's a .gnu_debuginfo + // section, nomatter if .symtab was already parsed or not. This is because + // minidebuginfo normally removes the .symtab symbols which have their + // matching .dynsym counterparts. + if (!symtab || + GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) { + Section *dynsym = + section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) + .get(); + if (dynsym) { + if (!m_symtab_up) + m_symtab_up.reset(new Symtab(dynsym->GetObjectFile())); + symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym); + } + } + // DT_JMPREL // If present, this entry's d_ptr member holds the address of // relocation @@ -2803,6 +2771,50 @@ Symtab *ObjectFileELF::GetSymtab() { if (m_symtab_up == nullptr) m_symtab_up.reset(new Symtab(this)); + // In the event that there's no symbol entry for the entry point we'll + // artifically create one. We delegate to the symtab object the figuring + // out of the proper size, this will usually make it span til the next + // symbol it finds in the section. This means that if there are missing + // symbols the entry point might span beyond its function definition. + // We're fine with this as it doesn't make it worse than not having a + // symbol entry at all. + if (CalculateType() == eTypeExecutable) { + ArchSpec arch = GetArchitecture(); + auto entry_point_addr = GetEntryPointAddress(); + bool is_valid_entry_point = + entry_point_addr.IsValid() && entry_point_addr.IsSectionOffset(); + addr_t entry_point_file_addr = entry_point_addr.GetFileAddress(); + if (is_valid_entry_point && !m_symtab_up->FindSymbolContainingFileAddress( + entry_point_file_addr)) { + uint64_t symbol_id = m_symtab_up->GetNumSymbols(); + Symbol symbol(symbol_id, + GetNextSyntheticSymbolName().GetCString(), // Symbol name. + eSymbolTypeCode, // Type of this symbol. + true, // Is this globally visible? + false, // Is this symbol debug info? + false, // Is this symbol a trampoline? + true, // Is this symbol artificial? + entry_point_addr.GetSection(), // Section where this + // symbol is defined. + 0, // Offset in section or symbol value. + 0, // Size. + false, // Size is valid. + false, // Contains linker annotations? + 0); // Symbol flags. + m_symtab_up->AddSymbol(symbol); + // When the entry point is arm thumb we need to explicitly set its + // class address to reflect that. This is important because expression + // evaluation relies on correctly setting a breakpoint at this + // address. + if (arch.GetMachine() == llvm::Triple::arm && + (entry_point_file_addr & 1)) + m_address_class_map[entry_point_file_addr ^ 1] = + AddressClass::eCodeAlternateISA; + else + m_address_class_map[entry_point_file_addr] = AddressClass::eCode; + } + } + m_symtab_up->CalculateSymbolSizes(); } @@ -2881,7 +2893,6 @@ void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, Symbol eh_symbol( symbol_id, // Symbol table index. symbol_name, // Symbol name. - false, // Is the symbol name mangled? eSymbolTypeCode, // Type of this symbol. true, // Is this globally visible? false, // Is this symbol debug info? diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index b63a5d14d4f5d..3b273896cb598 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -56,8 +56,6 @@ struct ELFNote { /// the ObjectFile protocol. class ObjectFileELF : public lldb_private::ObjectFile { public: - ~ObjectFileELF() override; - // Static Functions static void Initialize(); @@ -91,6 +89,13 @@ public: uint32_t GetPluginVersion() override; + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + // ObjectFile Protocol. bool ParseHeader() override; @@ -117,7 +122,9 @@ public: lldb_private::UUID GetUUID() override; - lldb_private::FileSpecList GetDebugSymbolFilePaths() override; + /// Return the contents of the .gnu_debuglink section, if the object file + /// contains it. + llvm::Optional<lldb_private::FileSpec> GetDebugLink(); uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; @@ -190,7 +197,7 @@ private: /// ELF .gnu_debuglink file and crc data if available. std::string m_gnu_debuglink_file; - uint32_t m_gnu_debuglink_crc; + uint32_t m_gnu_debuglink_crc = 0; /// Collection of program headers. ProgramHeaderColl m_program_headers; @@ -201,6 +208,10 @@ private: /// Collection of symbols from the dynamic table. DynamicSymbolColl m_dynamic_symbols; + /// Object file parsed from .gnu_debugdata section (\sa + /// GetGnuDebugDataObjectFile()) + std::shared_ptr<ObjectFileELF> m_gnu_debug_data_object_file; + /// List of file specifications corresponding to the modules (shared /// libraries) on which this object file depends. mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_up; @@ -376,6 +387,14 @@ private: lldb_private::UUID &uuid); bool AnySegmentHasPhysicalAddress(); + + /// Takes the .gnu_debugdata and returns the decompressed object file that is + /// stored within that section. + /// + /// \returns either the decompressed object file stored within the + /// .gnu_debugdata section or \c nullptr if an error occured or if there's no + /// section with that name. + std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile(); }; #endif // liblldb_ObjectFileELF_h_ diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index eaf973da38355..c55b96d9110b3 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +char ObjectFileJIT::ID; + void ObjectFileJIT::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, diff --git a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index 99241126cd1a6..c992683cfc3ce 100644 --- a/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -46,6 +46,13 @@ public: lldb::offset_t length, lldb_private::ModuleSpecList &specs); + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + // Member Functions bool ParseHeader() override; |