diff options
Diffstat (limited to 'gnu/llvm')
-rw-r--r-- | gnu/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 1292 |
1 files changed, 684 insertions, 608 deletions
diff --git a/gnu/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/gnu/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 3b33cf1601f..d351581c854 100644 --- a/gnu/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/gnu/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -13,24 +13,28 @@ #include <cassert> #include <unordered_map> -#include "lldb/Core/ArchSpec.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/RangeMap.h" #include "lldb/Core/Section.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/DataBufferLLVM.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" #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/Object/Decompressor.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -112,7 +116,7 @@ const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; //===----------------------------------------------------------------------===// /// @class ELFRelocation -/// @brief Generic wrapper for ELFRel and ELFRela. +/// Generic wrapper for ELFRel and ELFRela. /// /// This helper class allows us to parse both ELFRel and ELFRela relocation /// entries in a generic manner. @@ -234,16 +238,17 @@ unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { } // end anonymous namespace +static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; } + bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { // Read all fields. if (data.GetU32(offset, &n_namesz, 3) == NULL) return false; - // The name field is required to be nul-terminated, and n_namesz - // includes the terminating nul in observed implementations (contrary - // to the ELF-64 spec). A special case is needed for cores generated - // by some older Linux versions, which write a note named "CORE" - // without a nul terminator and n_namesz = 4. + // The name field is required to be nul-terminated, and n_namesz includes the + // terminating nul in observed implementations (contrary to the ELF-64 spec). + // A special case is needed for cores generated by some older Linux versions, + // which write a note named "CORE" without a nul terminator and n_namesz = 4. if (n_namesz == 4) { char buf[4]; if (data.ExtractBytes(*offset, 4, data.GetByteOrder(), buf) != 4) @@ -294,7 +299,8 @@ static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) { uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown; uint32_t fileclass = header.e_ident[EI_CLASS]; - // If there aren't any elf flags available (e.g core elf file) then return default + // If there aren't any elf flags available (e.g core elf file) then return + // default // 32 or 64 bit arch (without any architecture revision) based on object file's class. if (header.e_type == ET_CORE) { switch (fileclass) { @@ -404,8 +410,7 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, lldb::offset_t file_offset, lldb::offset_t length) { if (!data_sp) { - data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; @@ -422,8 +427,7 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { - data_sp = - DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset); + data_sp = MapFileData(*file, length, file_offset); if (!data_sp) return nullptr; data_offset = 0; @@ -434,9 +438,8 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, if (address_size == 4 || address_size == 8) { std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF( module_sp, data_sp, data_offset, file, file_offset, length)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } @@ -451,11 +454,10 @@ ObjectFile *ObjectFileELF::CreateMemoryInstance( if (ELFHeader::MagicBytesMatch(magic)) { unsigned address_size = ELFHeader::AddressSizeInBytes(magic); if (address_size == 4 || address_size == 8) { - std::auto_ptr<ObjectFileELF> objfile_ap( + std::unique_ptr<ObjectFileELF> objfile_ap( new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); - ArchSpec spec; - if (objfile_ap->GetArchitecture(spec) && - objfile_ap->SetModulesArchitecture(spec)) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } } @@ -539,19 +541,18 @@ static uint32_t calc_gnu_debuglink_crc32(const void *buf, size_t size) { uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32( const ProgramHeaderColl &program_headers, DataExtractor &object_data) { - typedef ProgramHeaderCollConstIter Iter; uint32_t core_notes_crc = 0; - for (Iter I = program_headers.begin(); I != program_headers.end(); ++I) { - if (I->p_type == llvm::ELF::PT_NOTE) { - const elf_off ph_offset = I->p_offset; - const size_t ph_size = I->p_filesz; + for (const ELFProgramHeader &H : program_headers) { + if (H.p_type == llvm::ELF::PT_NOTE) { + const elf_off ph_offset = H.p_offset; + const size_t ph_size = H.p_filesz; DataExtractor segment_data; if (segment_data.SetData(object_data, ph_offset, ph_size) != ph_size) { - // The ELF program header contained incorrect data, - // probably corefile is incomplete or corrupted. + // The ELF program header contained incorrect data, probably corefile + // is incomplete or corrupted. break; } @@ -596,8 +597,8 @@ static const char *OSABIAsCString(unsigned char osabi_byte) { // // WARNING : This function is being deprecated -// It's functionality has moved to ArchSpec::SetArchitecture -// This function is only being kept to validate the move. +// It's functionality has moved to ArchSpec::SetArchitecture This function is +// only being kept to validate the move. // // TODO : Remove this function static bool GetOsFromOSABI(unsigned char osabi_byte, @@ -675,31 +676,16 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } - // In case there is header extension in the section #0, the header - // we parsed above could have sentinel values for e_phnum, e_shnum, - // and e_shstrndx. In this case we need to reparse the header - // with a bigger data source to get the actual values. - size_t section_header_end = header.e_shoff + header.e_shentsize; - if (header.HasHeaderExtension() && - section_header_end > data_sp->GetByteSize()) { - data_sp = DataBufferLLVM::CreateSliceFromPath( - file.GetPath(), section_header_end, file_offset); - if (data_sp) { - data.SetData(data_sp); - lldb::offset_t header_offset = data_offset; - header.Parse(data, &header_offset); - } - } - - // Try to get the UUID from the section list. Usually that's at the - // end, so map the file in if we don't have it already. - section_header_end = - header.e_shoff + header.e_shnum * header.e_shentsize; - if (section_header_end > data_sp->GetByteSize()) { - data_sp = DataBufferLLVM::CreateSliceFromPath( - file.GetPath(), section_header_end, file_offset); - if (data_sp) - data.SetData(data_sp); + data_sp = MapFileData(file, -1, file_offset); + if (data_sp) + data.SetData(data_sp); + // In case there is header extension in the section #0, the header we + // parsed above could have sentinel values for e_phnum, e_shnum, and + // e_shstrndx. In this case we need to reparse the header with a + // bigger data source to get the actual values. + if (header.HasHeaderExtension()) { + lldb::offset_t header_offset = data_offset; + header.Parse(data, &header_offset); } uint32_t gnu_debuglink_crc = 0; @@ -729,61 +715,35 @@ size_t ObjectFileELF::GetModuleSpecifications( func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (file.GetByteSize() - file_offset) / 1024); + (FileSystem::Instance().GetByteSize(file) - file_offset) / + 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole // contents crc32 would be too much of luxury. Thus we will need // to fallback to something simpler. if (header.e_type == llvm::ELF::ET_CORE) { - size_t program_headers_end = - header.e_phoff + header.e_phnum * header.e_phentsize; - if (program_headers_end > data_sp->GetByteSize()) { - data_sp = DataBufferLLVM::CreateSliceFromPath( - file.GetPath(), program_headers_end, file_offset); - if (data_sp) - data.SetData(data_sp); - } ProgramHeaderColl program_headers; GetProgramHeaderInfo(program_headers, data, header); - size_t segment_data_end = 0; - for (ProgramHeaderCollConstIter I = program_headers.begin(); - I != program_headers.end(); ++I) { - segment_data_end = std::max<unsigned long long>( - I->p_offset + I->p_filesz, segment_data_end); - } - - if (segment_data_end > data_sp->GetByteSize()) { - data_sp = DataBufferLLVM::CreateSliceFromPath( - file.GetPath(), segment_data_end, file_offset); - if (data_sp) - data.SetData(data_sp); - } - core_notes_crc = CalculateELFNotesSegmentsCRC32(program_headers, data); } else { - // Need to map entire file into memory to calculate the crc. - data_sp = DataBufferLLVM::CreateSliceFromPath(file.GetPath(), -1, - file_offset); - if (data_sp) { - data.SetData(data_sp); - gnu_debuglink_crc = calc_gnu_debuglink_crc32( - data.GetDataStart(), data.GetByteSize()); - } + gnu_debuglink_crc = calc_gnu_debuglink_crc32( + data.GetDataStart(), data.GetByteSize()); } } + using u32le = llvm::support::ulittle32_t; if (gnu_debuglink_crc) { // Use 4 bytes of crc from the .gnu_debuglink section. - uint32_t uuidt[4] = {gnu_debuglink_crc, 0, 0, 0}; - uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data(gnu_debuglink_crc); + uuid = UUID::fromData(&data, sizeof(data)); } else if (core_notes_crc) { // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make - // it look different form - // .gnu_debuglink crc followed by 4 bytes of note segments crc. - uint32_t uuidt[4] = {g_core_uuid_magic, core_notes_crc, 0, 0}; - uuid.SetBytes(uuidt, sizeof(uuidt)); + // it look different form .gnu_debuglink crc followed by 4 bytes + // of note segments crc. + u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)}; + uuid = UUID::fromData(data, sizeof(data)); } } @@ -846,42 +806,30 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, SectionList *section_list = GetSectionList(); if (section_list) { if (!value_is_offset) { - bool found_offset = false; - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header == nullptr) - continue; - - if (header->p_type != PT_LOAD || header->p_offset != 0) - continue; - - value = value - header->p_vaddr; - found_offset = true; - break; - } - if (!found_offset) + addr_t base = GetBaseAddress().GetFileAddress(); + if (base == LLDB_INVALID_ADDRESS) return false; + value -= base; } const size_t num_sections = section_list->GetSize(); size_t sect_idx = 0; for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find all - // of the sections that have SHF_ALLOC in their flag bits. + // Iterate through the object file sections to find all of the sections + // that have SHF_ALLOC in their flag bits. SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (section_sp && section_sp->Test(SHF_ALLOC)) { + if (section_sp->Test(SHF_ALLOC) || + section_sp->GetType() == eSectionTypeContainer) { lldb::addr_t load_addr = section_sp->GetFileAddress(); // We don't want to update the load address of a section with type // eSectionTypeAbsoluteAddress as they already have the absolute load - // address - // already specified + // address already specified if (section_sp->GetType() != eSectionTypeAbsoluteAddress) load_addr += value; // On 32-bit systems the load address have to fit into 4 bytes. The - // rest of - // the bytes are the overflow from the addition. + // rest of the bytes are the overflow from the addition. if (GetAddressByteSize() == 4) load_addr &= 0xFFFFFFFF; @@ -911,24 +859,23 @@ uint32_t ObjectFileELF::GetAddressByteSize() const { AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { Symtab *symtab = GetSymtab(); if (!symtab) - return eAddressClassUnknown; + return AddressClass::eUnknown; - // The address class is determined based on the symtab. Ask it from the object - // file what - // contains the symtab information. + // The address class is determined based on the symtab. Ask it from the + // object file what contains the symtab information. ObjectFile *symtab_objfile = symtab->GetObjectFile(); if (symtab_objfile != nullptr && symtab_objfile != this) return symtab_objfile->GetAddressClass(file_addr); auto res = ObjectFile::GetAddressClass(file_addr); - if (res != eAddressClassCode) + if (res != AddressClass::eCode) return res; auto ub = m_address_class_map.upper_bound(file_addr); if (ub == m_address_class_map.begin()) { - // No entry in the address class map before the address. Return - // default address class for an address in a code section. - return eAddressClassCode; + // No entry in the address class map before the address. Return default + // address class for an address in a code section. + return AddressClass::eCode; } // Move iterator to the address class entry preceding address @@ -938,11 +885,11 @@ AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const { - return std::distance(m_section_headers.begin(), I) + 1u; + return std::distance(m_section_headers.begin(), I); } bool ObjectFileELF::ParseHeader() { @@ -956,6 +903,7 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile) return false; + using u32le = llvm::support::ulittle32_t; if (m_uuid.IsValid()) { // We have the full build id uuid. *uuid = m_uuid; @@ -969,11 +917,11 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { core_notes_crc = CalculateELFNotesSegmentsCRC32(m_program_headers, m_data); if (core_notes_crc) { - // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it - // look different form .gnu_debuglink crc - followed by 4 bytes of note + // Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it look + // different form .gnu_debuglink crc - followed by 4 bytes of note // segments crc. - uint32_t uuidt[4] = {g_core_uuid_magic, core_notes_crc, 0, 0}; - m_uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)}; + m_uuid = UUID::fromData(data, sizeof(data)); } } else { if (!m_gnu_debuglink_crc) @@ -981,8 +929,8 @@ bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { calc_gnu_debuglink_crc32(m_data.GetDataStart(), m_data.GetByteSize()); if (m_gnu_debuglink_crc) { // Use 4 bytes of crc from the .gnu_debuglink section. - uint32_t uuidt[4] = {m_gnu_debuglink_crc, 0, 0, 0}; - m_uuid.SetBytes(uuidt, sizeof(uuidt)); + u32le data(m_gnu_debuglink_crc); + m_uuid = UUID::fromData(&data, sizeof(data)); } } @@ -998,7 +946,7 @@ lldb_private::FileSpecList ObjectFileELF::GetDebugSymbolFilePaths() { FileSpecList file_spec_list; if (!m_gnu_debuglink_file.empty()) { - FileSpec file_spec(m_gnu_debuglink_file, false); + FileSpec file_spec(m_gnu_debuglink_file); file_spec_list.Append(file_spec); } return file_spec_list; @@ -1040,8 +988,8 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) { ELFDynamic &symbol = m_dynamic_symbols[i]; if (symbol.d_tag == DT_DEBUG) { - // Compute the offset as the number of previous entries plus the - // size of d_tag. + // Compute the offset as the number of previous entries plus the size of + // d_tag. addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize(); return Address(dynsym_section_sp, offset); } @@ -1100,6 +1048,18 @@ lldb_private::Address ObjectFileELF::GetEntryPointAddress() { return m_entry_point_address; } +Address ObjectFileELF::GetBaseAddress() { + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &H = EnumPHdr.value(); + if (H.p_type != PT_LOAD) + continue; + + return Address( + GetSectionList()->FindSectionByID(SegmentID(EnumPHdr.index())), 0); + } + return LLDB_INVALID_ADDRESS; +} + //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- @@ -1129,7 +1089,7 @@ size_t ObjectFileELF::ParseDependentModules() { return 0; // sh_link: section header index of string table used by entries in the // section. - Section *dynstr = section_list->FindSectionByID(header->sh_link + 1).get(); + Section *dynstr = section_list->FindSectionByID(header->sh_link).get(); if (!dynstr) return 0; @@ -1152,7 +1112,9 @@ size_t ObjectFileELF::ParseDependentModules() { uint32_t str_index = static_cast<uint32_t>(symbol.d_val); const char *lib_name = dynstr_data.PeekCStr(str_index); - m_filespec_ap->Append(FileSpec(lib_name, true)); + FileSpec file_spec(lib_name); + FileSystem::Instance().Resolve(file_spec); + m_filespec_ap->Append(file_spec); } } @@ -1186,7 +1148,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_phnum; ++idx) { - if (program_headers[idx].Parse(data, &offset) == false) + if (!program_headers[idx].Parse(data, &offset)) break; } @@ -1199,8 +1161,8 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, //---------------------------------------------------------------------- // ParseProgramHeaders //---------------------------------------------------------------------- -size_t ObjectFileELF::ParseProgramHeaders() { - return GetProgramHeaderInfo(m_program_headers, m_data, m_header); +bool ObjectFileELF::ParseProgramHeaders() { + return GetProgramHeaderInfo(m_program_headers, m_data, m_header) != 0; } lldb_private::Status @@ -1320,18 +1282,16 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, // Only bother processing this if we don't already have the uuid set. if (!uuid.IsValid()) { // 16 bytes is UUID|MD5, 20 bytes is SHA1. Other linkers may produce a - // build-id of a different - // length. Accept it as long as it's at least 4 bytes as it will be - // better than our own crc32. - if (note.n_descsz >= 4 && note.n_descsz <= 20) { - uint8_t uuidbuf[20]; - if (data.GetU8(&offset, &uuidbuf, note.n_descsz) == nullptr) { + // build-id of a different length. Accept it as long as it's at least + // 4 bytes as it will be better than our own crc32. + if (note.n_descsz >= 4) { + if (const uint8_t *buf = data.PeekData(offset, note.n_descsz)) { + // Save the build id as the UUID for the module. + uuid = UUID::fromData(buf, note.n_descsz); + } else { error.SetErrorString("failed to read GNU_BUILD_ID note payload"); return error; } - - // Save the build id as the UUID for the module. - uuid.SetBytes(uuidbuf, note.n_descsz); } } break; @@ -1374,8 +1334,8 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::CSR); // TODO At some point the description string could be processed. - // It could provide a steer towards the kalimba variant which - // this ELF targets. + // It could provide a steer towards the kalimba variant which this ELF + // targets. if (note.n_descsz) { const char *cstr = data.GetCStr(&offset, llvm::alignTo(note.n_descsz, 4)); @@ -1390,36 +1350,28 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, // register info arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } else if (note.n_name == LLDB_NT_OWNER_CORE) { - // Parse the NT_FILE to look for stuff in paths to shared libraries - // As the contents look like this in a 64 bit ELF core file: - // count = 0x000000000000000a (10) - // page_size = 0x0000000000001000 (4096) - // Index start end file_ofs path - // ===== ------------------ ------------------ ------------------ - // ------------------------------------- - // [ 0] 0x0000000000400000 0x0000000000401000 0x0000000000000000 - // /tmp/a.out - // [ 1] 0x0000000000600000 0x0000000000601000 0x0000000000000000 - // /tmp/a.out - // [ 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 - // /tmp/a.out + // Parse the NT_FILE to look for stuff in paths to shared libraries As + // the contents look like this in a 64 bit ELF core file: count = + // 0x000000000000000a (10) page_size = 0x0000000000001000 (4096) Index + // start end file_ofs path ===== + // ------------------ ------------------ ------------------ + // ------------------------------------- [ 0] 0x0000000000400000 + // 0x0000000000401000 0x0000000000000000 /tmp/a.out [ 1] + // 0x0000000000600000 0x0000000000601000 0x0000000000000000 /tmp/a.out [ + // 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 /tmp/a.out // [ 3] 0x00007fa79c9ed000 0x00007fa79cba8000 0x0000000000000000 - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 4] 0x00007fa79cba8000 0x00007fa79cda7000 0x00000000000001bb - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 0x00000000000001ba - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 6] 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be - // /lib/x86_64-linux-gnu/libc-2.19.so - // [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 0x0000000000000000 - // /lib/x86_64-linux-gnu/ld-2.19.so - // [ 8] 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 - // /lib/x86_64-linux-gnu/ld-2.19.so - // [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 0x0000000000000023 - // /lib/x86_64-linux-gnu/ld-2.19.so - // In the 32 bit ELFs the count, page_size, start, end, file_ofs are - // uint32_t - // For reference: see readelf source code (in binutils). + // /lib/x86_64-linux-gnu/libc-2.19.so [ 4] 0x00007fa79cba8000 + // 0x00007fa79cda7000 0x00000000000001bb /lib/x86_64-linux- + // gnu/libc-2.19.so [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 + // 0x00000000000001ba /lib/x86_64-linux-gnu/libc-2.19.so [ 6] + // 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be /lib/x86_64 + // -linux-gnu/libc-2.19.so [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 + // 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so [ 8] + // 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64 + // -linux-gnu/ld-2.19.so [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 + // 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so In the 32 bit ELFs + // the count, page_size, start, end, file_ofs are uint32_t For reference: + // see readelf source code (in binutils). if (note.n_type == NT_FILE) { uint64_t count = data.GetAddress(&offset); const char *cstr; @@ -1443,15 +1395,14 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, } if (arch_spec.IsMIPS() && arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) - // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing - // for some cases (e.g. compile with -nostdlib) - // Hence set OS to Linux - arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + // In case of MIPSR6, the LLDB_NT_OWNER_GNU note is missing for some + // cases (e.g. compile with -nostdlib) Hence set OS to Linux + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); } } - // Calculate the offset of the next note just in case "offset" has been used - // to poke at the contents of the note data + // Calculate the offset of the next note just in case "offset" has been + // used to poke at the contents of the note data offset = note_offset + note.GetByteSize(); } @@ -1550,14 +1501,13 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, const uint32_t sub_type = subTypeFromElfHeader(header); arch_spec.SetArchitecture(eArchTypeELF, header.e_machine, sub_type, header.e_ident[EI_OSABI]); - - // Validate if it is ok to remove GetOsFromOSABI. - // Note, that now the OS is determined based on EI_OSABI flag and - // the info extracted from ELF notes (see RefineModuleDetailsFromNote). - // However in some cases that still might be not enough: for example - // a shared library might not have any notes at all - // and have EI_OSABI flag set to System V, - // as result the OS will be set to UnknownOS. + + // Validate if it is ok to remove GetOsFromOSABI. Note, that now the OS is + // determined based on EI_OSABI flag and the info extracted from ELF notes + // (see RefineModuleDetailsFromNote). However in some cases that still + // might be not enough: for example a shared library might not have any + // notes at all and have EI_OSABI flag set to System V, as result the OS + // will be set to UnknownOS. GetOsFromOSABI(header.e_ident[EI_OSABI], ostype); spec_ostype = arch_spec.GetTriple().getOS(); assert(spec_ostype == ostype); @@ -1610,7 +1560,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, uint32_t idx; lldb::offset_t offset; for (idx = 0, offset = 0; idx < header.e_shnum; ++idx) { - if (section_headers[idx].Parse(sh_data, &offset) == false) + if (!section_headers[idx].Parse(sh_data, &offset)) break; } if (idx < section_headers.size()) @@ -1758,27 +1708,6 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, return 0; } -size_t ObjectFileELF::GetProgramHeaderCount() { return ParseProgramHeaders(); } - -const elf::ELFProgramHeader * -ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseProgramHeaders()) - return NULL; - - if (--id < m_program_headers.size()) - return &m_program_headers[id]; - - return NULL; -} - -DataExtractor ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id) { - const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id); - if (segment_header == NULL) - return DataExtractor(); - return DataExtractor(m_data, segment_header->p_offset, - segment_header->p_filesz); -} - llvm::StringRef ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { size_t pos = symbol_name.find('@'); @@ -1796,10 +1725,10 @@ size_t ObjectFileELF::ParseSectionHeaders() { const ObjectFileELF::ELFSectionHeaderInfo * ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) { - if (!id || !ParseSectionHeaders()) + if (!ParseSectionHeaders()) return NULL; - if (--id < m_section_headers.size()) + if (id < m_section_headers.size()) return &m_section_headers[id]; return NULL; @@ -1814,243 +1743,285 @@ lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { return 0; } -void ObjectFileELF::CreateSections(SectionList &unified_section_list) { - if (!m_sections_ap.get() && ParseSectionHeaders()) { - m_sections_ap.reset(new SectionList()); - - for (SectionHeaderCollIter I = m_section_headers.begin(); - I != m_section_headers.end(); ++I) { - const ELFSectionHeaderInfo &header = *I; - - ConstString &name = I->section_name; - const uint64_t file_size = - header.sh_type == SHT_NOBITS ? 0 : header.sh_size; - const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0; - - static ConstString g_sect_name_text(".text"); - static ConstString g_sect_name_data(".data"); - static ConstString g_sect_name_bss(".bss"); - static ConstString g_sect_name_tdata(".tdata"); - static ConstString g_sect_name_tbss(".tbss"); - static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); - static ConstString g_sect_name_dwarf_debug_addr(".debug_addr"); - static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges"); - static ConstString g_sect_name_dwarf_debug_frame(".debug_frame"); - static ConstString g_sect_name_dwarf_debug_info(".debug_info"); - static ConstString g_sect_name_dwarf_debug_line(".debug_line"); - static ConstString g_sect_name_dwarf_debug_loc(".debug_loc"); - static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo"); - static ConstString g_sect_name_dwarf_debug_macro(".debug_macro"); - static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames"); - static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes"); - static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges"); - static ConstString g_sect_name_dwarf_debug_str(".debug_str"); - static ConstString g_sect_name_dwarf_debug_str_offsets( - ".debug_str_offsets"); - static ConstString g_sect_name_dwarf_debug_abbrev_dwo( - ".debug_abbrev.dwo"); - static ConstString g_sect_name_dwarf_debug_info_dwo(".debug_info.dwo"); - static ConstString g_sect_name_dwarf_debug_line_dwo(".debug_line.dwo"); - static ConstString g_sect_name_dwarf_debug_macro_dwo(".debug_macro.dwo"); - static ConstString g_sect_name_dwarf_debug_loc_dwo(".debug_loc.dwo"); - static ConstString g_sect_name_dwarf_debug_str_dwo(".debug_str.dwo"); - static ConstString g_sect_name_dwarf_debug_str_offsets_dwo( - ".debug_str_offsets.dwo"); - static ConstString g_sect_name_eh_frame(".eh_frame"); - static ConstString g_sect_name_arm_exidx(".ARM.exidx"); - static ConstString g_sect_name_arm_extab(".ARM.extab"); - static ConstString g_sect_name_go_symtab(".gosymtab"); - - SectionType sect_type = eSectionTypeOther; - - bool is_thread_specific = false; - - if (name == g_sect_name_text) - sect_type = eSectionTypeCode; - else if (name == g_sect_name_data) - sect_type = eSectionTypeData; - else if (name == g_sect_name_bss) - sect_type = eSectionTypeZeroFill; - else if (name == g_sect_name_tdata) { - sect_type = eSectionTypeData; - is_thread_specific = true; - } else if (name == g_sect_name_tbss) { - sect_type = eSectionTypeZeroFill; - is_thread_specific = true; - } - // .debug_abbrev – Abbreviations used in the .debug_info section - // .debug_aranges – Lookup table for mapping addresses to compilation - // units - // .debug_frame – Call frame information - // .debug_info – The core DWARF information section - // .debug_line – Line number information - // .debug_loc – Location lists used in DW_AT_location attributes - // .debug_macinfo – Macro information - // .debug_pubnames – Lookup table for mapping object and function names to - // compilation units - // .debug_pubtypes – Lookup table for mapping type names to compilation - // units - // .debug_ranges – Address ranges used in DW_AT_ranges attributes - // .debug_str – String table used in .debug_info - // MISSING? .gnu_debugdata - "mini debuginfo / MiniDebugInfo" section, - // http://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html - // MISSING? .debug-index - - // http://src.chromium.org/viewvc/chrome/trunk/src/build/gdb-add-index?pathrev=144644 - // MISSING? .debug_types - Type descriptions from DWARF 4? See - // http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo - else if (name == g_sect_name_dwarf_debug_abbrev) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_addr) - sect_type = eSectionTypeDWARFDebugAddr; - else if (name == g_sect_name_dwarf_debug_aranges) - sect_type = eSectionTypeDWARFDebugAranges; - else if (name == g_sect_name_dwarf_debug_frame) - sect_type = eSectionTypeDWARFDebugFrame; - else if (name == g_sect_name_dwarf_debug_info) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_loc) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_macinfo) - sect_type = eSectionTypeDWARFDebugMacInfo; - else if (name == g_sect_name_dwarf_debug_macro) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_pubnames) - sect_type = eSectionTypeDWARFDebugPubNames; - else if (name == g_sect_name_dwarf_debug_pubtypes) - sect_type = eSectionTypeDWARFDebugPubTypes; - else if (name == g_sect_name_dwarf_debug_ranges) - sect_type = eSectionTypeDWARFDebugRanges; - else if (name == g_sect_name_dwarf_debug_str) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_str_offsets) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_dwarf_debug_abbrev_dwo) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (name == g_sect_name_dwarf_debug_info_dwo) - sect_type = eSectionTypeDWARFDebugInfo; - else if (name == g_sect_name_dwarf_debug_line_dwo) - sect_type = eSectionTypeDWARFDebugLine; - else if (name == g_sect_name_dwarf_debug_macro_dwo) - sect_type = eSectionTypeDWARFDebugMacro; - else if (name == g_sect_name_dwarf_debug_loc_dwo) - sect_type = eSectionTypeDWARFDebugLoc; - else if (name == g_sect_name_dwarf_debug_str_dwo) - sect_type = eSectionTypeDWARFDebugStr; - else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) - sect_type = eSectionTypeDWARFDebugStrOffsets; - else if (name == g_sect_name_eh_frame) - sect_type = eSectionTypeEHFrame; - else if (name == g_sect_name_arm_exidx) - sect_type = eSectionTypeARMexidx; - else if (name == g_sect_name_arm_extab) - sect_type = eSectionTypeARMextab; - else if (name == g_sect_name_go_symtab) - sect_type = eSectionTypeGoSymtab; - - const uint32_t permissions = - ((header.sh_flags & SHF_ALLOC) ? ePermissionsReadable : 0u) | - ((header.sh_flags & SHF_WRITE) ? ePermissionsWritable : 0u) | - ((header.sh_flags & SHF_EXECINSTR) ? ePermissionsExecutable : 0u); - switch (header.sh_type) { - case SHT_SYMTAB: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFSymbolTable; - break; - case SHT_DYNSYM: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicSymbols; - break; - case SHT_RELA: - case SHT_REL: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFRelocationEntries; - break; - case SHT_DYNAMIC: - assert(sect_type == eSectionTypeOther); - sect_type = eSectionTypeELFDynamicLinkInfo; - break; - } +static SectionType GetSectionTypeFromName(llvm::StringRef Name) { + return llvm::StringSwitch<SectionType>(Name) + .Case(".ARM.exidx", eSectionTypeARMexidx) + .Case(".ARM.extab", eSectionTypeARMextab) + .Cases(".bss", ".tbss", eSectionTypeZeroFill) + .Cases(".data", ".tdata", eSectionTypeData) + .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) + .Case(".debug_abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) + .Case(".debug_addr", eSectionTypeDWARFDebugAddr) + .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) + .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) + .Case(".debug_frame", eSectionTypeDWARFDebugFrame) + .Case(".debug_info", eSectionTypeDWARFDebugInfo) + .Case(".debug_info.dwo", eSectionTypeDWARFDebugInfoDwo) + .Cases(".debug_line", ".debug_line.dwo", eSectionTypeDWARFDebugLine) + .Cases(".debug_line_str", ".debug_line_str.dwo", + eSectionTypeDWARFDebugLineStr) + .Cases(".debug_loc", ".debug_loc.dwo", eSectionTypeDWARFDebugLoc) + .Cases(".debug_loclists", ".debug_loclists.dwo", + eSectionTypeDWARFDebugLocLists) + .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) + .Cases(".debug_macro", ".debug_macro.dwo", eSectionTypeDWARFDebugMacro) + .Case(".debug_names", eSectionTypeDWARFDebugNames) + .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) + .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) + .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) + .Case(".debug_str", eSectionTypeDWARFDebugStr) + .Case(".debug_str.dwo", eSectionTypeDWARFDebugStrDwo) + .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case(".debug_str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case(".debug_types", eSectionTypeDWARFDebugTypes) + .Case(".eh_frame", eSectionTypeEHFrame) + .Case(".gnu_debugaltlink", eSectionTypeDWARFGNUDebugAltLink) + .Case(".gosymtab", eSectionTypeGoSymtab) + .Case(".text", eSectionTypeCode) + .Default(eSectionTypeOther); +} + +SectionType ObjectFileELF::GetSectionType(const ELFSectionHeaderInfo &H) const { + switch (H.sh_type) { + case SHT_PROGBITS: + if (H.sh_flags & SHF_EXECINSTR) + return eSectionTypeCode; + break; + case SHT_SYMTAB: + return eSectionTypeELFSymbolTable; + case SHT_DYNSYM: + return eSectionTypeELFDynamicSymbols; + case SHT_RELA: + case SHT_REL: + return eSectionTypeELFRelocationEntries; + case SHT_DYNAMIC: + return eSectionTypeELFDynamicLinkInfo; + } + SectionType Type = GetSectionTypeFromName(H.section_name.GetStringRef()); + if (Type == eSectionTypeOther) { + // the kalimba toolchain assumes that ELF section names are free-form. + // It does support linkscripts which (can) give rise to various + // arbitrarily named sections being "Code" or "Data". + Type = kalimbaSectionType(m_header, H); + } + return Type; +} - if (eSectionTypeOther == sect_type) { - // the kalimba toolchain assumes that ELF section names are free-form. - // It does - // support linkscripts which (can) give rise to various arbitrarily - // named - // sections being "Code" or "Data". - sect_type = kalimbaSectionType(m_header, header); - } +static uint32_t GetTargetByteSize(SectionType Type, const ArchSpec &arch) { + switch (Type) { + case eSectionTypeData: + case eSectionTypeZeroFill: + return arch.GetDataByteSize(); + case eSectionTypeCode: + return arch.GetCodeByteSize(); + default: + return 1; + } +} + +static Permissions GetPermissions(const ELFSectionHeader &H) { + Permissions Perm = Permissions(0); + if (H.sh_flags & SHF_ALLOC) + Perm |= ePermissionsReadable; + if (H.sh_flags & SHF_WRITE) + Perm |= ePermissionsWritable; + if (H.sh_flags & SHF_EXECINSTR) + Perm |= ePermissionsExecutable; + return Perm; +} - const uint32_t target_bytes_size = - (eSectionTypeData == sect_type || eSectionTypeZeroFill == sect_type) - ? m_arch_spec.GetDataByteSize() - : eSectionTypeCode == sect_type ? m_arch_spec.GetCodeByteSize() - : 1; - - elf::elf_xword log2align = - (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); - SectionSP section_sp(new Section( - GetModule(), // Module to which this section belongs. - this, // ObjectFile to which this section belongs and should read - // section data from. - SectionIndex(I), // Section ID. - name, // Section name. - sect_type, // Section type. - header.sh_addr, // VM address. - vm_size, // VM size in bytes of this section. - header.sh_offset, // Offset of this section in the file. - file_size, // Size of the section as found in the file. - log2align, // Alignment of the section - header.sh_flags, // Flags for this section. - target_bytes_size)); // Number of host bytes per target byte - - section_sp->SetPermissions(permissions); - if (is_thread_specific) - section_sp->SetIsThreadSpecific(is_thread_specific); - m_sections_ap->AddSection(section_sp); +static Permissions GetPermissions(const ELFProgramHeader &H) { + Permissions Perm = Permissions(0); + if (H.p_flags & PF_R) + Perm |= ePermissionsReadable; + if (H.p_flags & PF_W) + Perm |= ePermissionsWritable; + if (H.p_flags & PF_X) + Perm |= ePermissionsExecutable; + return Perm; +} + +namespace { + +using VMRange = lldb_private::Range<addr_t, addr_t>; + +struct SectionAddressInfo { + SectionSP Segment; + VMRange Range; +}; + +// (Unlinked) ELF object files usually have 0 for every section address, meaning +// we need to compute synthetic addresses in order for "file addresses" from +// different sections to not overlap. This class handles that logic. +class VMAddressProvider { + using VMMap = llvm::IntervalMap<addr_t, SectionSP, 4, + llvm::IntervalMapHalfOpenInfo<addr_t>>; + + ObjectFile::Type ObjectType; + addr_t NextVMAddress = 0; + VMMap::Allocator Alloc; + VMMap Segments = VMMap(Alloc); + VMMap Sections = VMMap(Alloc); + lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES); + + VMRange GetVMRange(const ELFSectionHeader &H) { + addr_t Address = H.sh_addr; + addr_t Size = H.sh_flags & SHF_ALLOC ? H.sh_size : 0; + if (ObjectType == ObjectFile::Type::eTypeObjectFile && Segments.empty() && (H.sh_flags & SHF_ALLOC)) { + NextVMAddress = + llvm::alignTo(NextVMAddress, std::max<addr_t>(H.sh_addralign, 1)); + Address = NextVMAddress; + NextVMAddress += Size; } + return VMRange(Address, Size); } - if (m_sections_ap.get()) { - if (GetType() == eTypeDebugInfo) { - static const SectionType g_sections[] = { - eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, - eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugFrame, - eSectionTypeDWARFDebugInfo, eSectionTypeDWARFDebugLine, - eSectionTypeDWARFDebugLoc, eSectionTypeDWARFDebugMacInfo, - eSectionTypeDWARFDebugPubNames, eSectionTypeDWARFDebugPubTypes, - eSectionTypeDWARFDebugRanges, eSectionTypeDWARFDebugStr, - eSectionTypeDWARFDebugStrOffsets, eSectionTypeELFSymbolTable, - }; - SectionList *elf_section_list = m_sections_ap.get(); - for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); - ++idx) { - SectionType section_type = g_sections[idx]; - SectionSP section_sp( - elf_section_list->FindSectionByType(section_type, true)); - if (section_sp) { - SectionSP module_section_sp( - unified_section_list.FindSectionByType(section_type, true)); - if (module_section_sp) - unified_section_list.ReplaceSection(module_section_sp->GetID(), - section_sp); - else - unified_section_list.AddSection(section_sp); - } +public: + VMAddressProvider(ObjectFile::Type Type) : ObjectType(Type) {} + + llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) { + if (H.p_memsz == 0) { + LLDB_LOG(Log, + "Ignoring zero-sized PT_LOAD segment. Corrupt object file?"); + 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?"); + return llvm::None; + } + return VMRange(H.p_vaddr, H.p_memsz); + } + + llvm::Optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) { + VMRange Range = GetVMRange(H); + SectionSP Segment; + auto It = Segments.find(Range.GetRangeBase()); + if ((H.sh_flags & SHF_ALLOC) && It.valid()) { + addr_t MaxSize; + if (It.start() <= Range.GetRangeBase()) { + MaxSize = It.stop() - Range.GetRangeBase(); + Segment = *It; + } else + MaxSize = It.start() - Range.GetRangeBase(); + if (Range.GetByteSize() > MaxSize) { + LLDB_LOG(Log, "Shortening section crossing segment boundaries. " + "Corrupt object file?"); + Range.SetByteSize(MaxSize); } - } else { - unified_section_list = *m_sections_ap; } + if (Range.GetByteSize() > 0 && + Sections.overlaps(Range.GetRangeBase(), Range.GetRangeEnd())) { + LLDB_LOG(Log, "Ignoring overlapping section. Corrupt object file?"); + return llvm::None; + } + if (Segment) + Range.Slide(-Segment->GetFileAddress()); + return SectionAddressInfo{Segment, Range}; + } + + void AddSegment(const VMRange &Range, SectionSP Seg) { + Segments.insert(Range.GetRangeBase(), Range.GetRangeEnd(), std::move(Seg)); + } + + void AddSection(SectionAddressInfo Info, SectionSP Sect) { + if (Info.Range.GetByteSize() == 0) + return; + if (Info.Segment) + Info.Range.Slide(Info.Segment->GetFileAddress()); + Sections.insert(Info.Range.GetRangeBase(), Info.Range.GetRangeEnd(), + std::move(Sect)); + } +}; +} + +void ObjectFileELF::CreateSections(SectionList &unified_section_list) { + if (m_sections_ap) + return; + + m_sections_ap = llvm::make_unique<SectionList>(); + VMAddressProvider address_provider(CalculateType()); + + size_t LoadID = 0; + for (const auto &EnumPHdr : llvm::enumerate(ProgramHeaders())) { + const ELFProgramHeader &PHdr = EnumPHdr.value(); + if (PHdr.p_type != PT_LOAD) + continue; + + auto InfoOr = address_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); + Segment->SetPermissions(GetPermissions(PHdr)); + m_sections_ap->AddSection(Segment); + + address_provider.AddSegment(*InfoOr, std::move(Segment)); + } + + ParseSectionHeaders(); + if (m_section_headers.empty()) + return; + + for (SectionHeaderCollIter I = std::next(m_section_headers.begin()); + I != m_section_headers.end(); ++I) { + const ELFSectionHeaderInfo &header = *I; + + ConstString &name = I->section_name; + const uint64_t file_size = + header.sh_type == SHT_NOBITS ? 0 : header.sh_size; + + auto InfoOr = address_provider.GetAddressInfo(header); + if (!InfoOr) + continue; + + SectionType sect_type = GetSectionType(header); + + const uint32_t target_bytes_size = + GetTargetByteSize(sect_type, m_arch_spec); + + elf::elf_xword log2align = + (header.sh_addralign == 0) ? 0 : llvm::Log2_64(header.sh_addralign); + + SectionSP section_sp(new Section( + InfoOr->Segment, GetModule(), // Module to which this section belongs. + this, // ObjectFile to which this section belongs and should + // read section data from. + SectionIndex(I), // Section ID. + name, // Section name. + sect_type, // Section type. + InfoOr->Range.GetRangeBase(), // VM address. + InfoOr->Range.GetByteSize(), // VM size in bytes of this section. + header.sh_offset, // Offset of this section in the file. + file_size, // Size of the section as found in the file. + log2align, // Alignment of the section + header.sh_flags, // Flags for this section. + target_bytes_size)); // Number of host bytes per target byte + + section_sp->SetPermissions(GetPermissions(header)); + section_sp->SetIsThreadSpecific(header.sh_flags & SHF_TLS); + (InfoOr->Segment ? InfoOr->Segment->GetChildren() : *m_sections_ap) + .AddSection(section_sp); + address_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_ap; } // Find the arm/aarch64 mapping symbol character in the given symbol name. -// Mapping symbols have the -// form of "$<char>[.<any>]*". Additionally we recognize cases when the mapping -// symbol prefixed by -// an arbitrary string because if a symbol prefix added to each symbol in the -// object file with +// Mapping symbols have the form of "$<char>[.<any>]*". Additionally we +// recognize cases when the mapping symbol prefixed by an arbitrary string +// because if a symbol prefix added to each symbol in the object file with // objcopy then the mapping symbols are also prefixed. static char FindArmAarch64MappingSymbol(const char *symbol_name) { if (!symbol_name) @@ -2092,37 +2063,32 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, static ConstString opd_section_name(".opd"); // For ppc64 // On Android the oatdata and the oatexec symbols in the oat and odex files - // covers the full - // .text section what causes issues with displaying unusable symbol name to - // the user and very - // slow unwinding speed because the instruction emulation based unwind plans - // try to emulate all - // instructions in these symbols. Don't add these symbols to the symbol list - // as they have no - // use for the debugger and they are causing a lot of trouble. - // Filtering can't be restricted to Android because this special object file - // don't contain the - // note section specifying the environment to Android but the custom extension - // and file name - // makes it highly unlikely that this will collide with anything else. + // covers the full .text section what causes issues with displaying unusable + // symbol name to the user and very slow unwinding speed because the + // instruction emulation based unwind plans try to emulate all instructions + // in these symbols. Don't add these symbols to the symbol list as they have + // no use for the debugger and they are causing a lot of trouble. Filtering + // can't be restricted to Android because this special object file don't + // contain the note section specifying the environment to Android but the + // custom extension and file name makes it highly unlikely that this will + // collide with anything else. ConstString file_extension = m_file.GetFileNameExtension(); - bool skip_oatdata_oatexec = file_extension == ConstString("oat") || - file_extension == ConstString("odex"); + bool skip_oatdata_oatexec = file_extension == ConstString(".oat") || + file_extension == ConstString(".odex"); - ArchSpec arch; - GetArchitecture(arch); + ArchSpec arch = GetArchitecture(); ModuleSP module_sp(GetModule()); SectionList *module_section_list = module_sp ? module_sp->GetSectionList() : nullptr; // Local cache to avoid doing a FindSectionByName for each symbol. The "const - // char*" key must - // came from a ConstString object so they can be compared by pointer + // char*" key must came from a ConstString object so they can be compared by + // pointer std::unordered_map<const char *, lldb::SectionSP> section_name_to_section; unsigned i; for (i = 0; i < num_symbols; ++i) { - if (symbol.Parse(symtab_data, &offset) == false) + if (!symbol.Parse(symtab_data, &offset)) break; const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); @@ -2135,17 +2101,16 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, continue; // Skipping oatdata and oatexec sections if it is requested. See details - // above the - // definition of skip_oatdata_oatexec for the reasons. + // above the definition of skip_oatdata_oatexec for the reasons. if (skip_oatdata_oatexec && (::strcmp(symbol_name, "oatdata") == 0 || ::strcmp(symbol_name, "oatexec") == 0)) continue; SectionSP symbol_section_sp; SymbolType symbol_type = eSymbolTypeInvalid; - Elf64_Half section_idx = symbol.st_shndx; + Elf64_Half shndx = symbol.st_shndx; - switch (section_idx) { + switch (shndx) { case SHN_ABS: symbol_type = eSymbolTypeAbsolute; break; @@ -2153,7 +2118,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, symbol_type = eSymbolTypeUndefined; break; default: - symbol_section_sp = section_list->GetSectionAtIndex(section_idx); + symbol_section_sp = section_list->FindSectionByID(shndx); break; } @@ -2167,8 +2132,8 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, break; case STT_OBJECT: - // The symbol is associated with a data object, such as a variable, - // an array, etc. + // The symbol is associated with a data object, such as a variable, an + // array, etc. symbol_type = eSymbolTypeData; break; @@ -2179,13 +2144,13 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, case STT_SECTION: // The symbol is associated with a section. Symbol table entries of - // this type exist primarily for relocation and normally have - // STB_LOCAL binding. + // this type exist primarily for relocation and normally have STB_LOCAL + // binding. break; case STT_FILE: - // Conventionally, the symbol's name gives the name of the source - // file associated with the object file. A file symbol has STB_LOCAL + // Conventionally, the symbol's name gives the name of the source file + // associated with the object file. A file symbol has STB_LOCAL // binding, its section index is SHN_ABS, and it precedes the other // STB_LOCAL symbols for the file, if it is present. symbol_type = eSymbolTypeSourceFile; @@ -2227,18 +2192,18 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'a': // $a[.<any>]* - marks an ARM instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'b': case 't': // $b[.<any>]* - marks a THUMB BL instruction sequence // $t[.<any>]* - marks a THUMB instruction sequence m_address_class_map[symbol.st_value] = - eAddressClassCodeAlternateISA; + AddressClass::eCodeAlternateISA; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2252,11 +2217,11 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'x': // $x[.<any>]* - marks an A64 instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2268,18 +2233,17 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, if (arch.GetMachine() == llvm::Triple::arm) { if (symbol_type == eSymbolTypeCode) { if (symbol.st_value & 1) { - // Subtracting 1 from the address effectively unsets - // the low order bit, which results in the address - // actually pointing to the beginning of the symbol. - // This delta will be used below in conjunction with - // symbol.st_value to produce the final symbol_value - // that we store in the symtab. + // Subtracting 1 from the address effectively unsets the low order + // bit, which results in the address actually pointing to the + // beginning of the symbol. This delta will be used below in + // conjunction with symbol.st_value to produce the final + // symbol_value that we store in the symtab. symbol_value_offset = -1; m_address_class_map[symbol.st_value ^ 1] = - eAddressClassCodeAlternateISA; + AddressClass::eCodeAlternateISA; } else { // This address is ARM - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; } } } @@ -2304,36 +2268,32 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, llvm_arch == llvm::Triple::mips64 || llvm_arch == llvm::Triple::mips64el) { if (IS_MICROMIPS(symbol.st_other)) - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; else if ((symbol.st_value & 1) && (symbol_type == eSymbolTypeCode)) { symbol.st_value = symbol.st_value & (~1ull); - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; } else { if (symbol_type == eSymbolTypeCode) - m_address_class_map[symbol.st_value] = eAddressClassCode; + m_address_class_map[symbol.st_value] = AddressClass::eCode; else if (symbol_type == eSymbolTypeData) - m_address_class_map[symbol.st_value] = eAddressClassData; + m_address_class_map[symbol.st_value] = AddressClass::eData; else - m_address_class_map[symbol.st_value] = eAddressClassUnknown; + m_address_class_map[symbol.st_value] = AddressClass::eUnknown; } } } // symbol_value_offset may contain 0 for ARM symbols or -1 for THUMB - // symbols. See above for - // more details. + // symbols. See above for more details. uint64_t symbol_value = symbol.st_value + symbol_value_offset; - if (symbol_section_sp == nullptr && section_idx == SHN_ABS && + if (symbol_section_sp == nullptr && shndx == SHN_ABS && symbol.st_size != 0) { // We don't have a section for a symbol with non-zero size. Create a new - // section for it - // so the address range covered by the symbol is also covered by the - // module (represented - // through the section list). It is needed so module lookup for the - // addresses covered - // by this symbol will be successfull. This case happens for absolute - // symbols. + // section for it so the address range covered by the symbol is also + // covered by the module (represented through the section list). It is + // needed so module lookup for the addresses covered by this symbol will + // be successfull. This case happens for absolute symbols. ConstString fake_section_name(std::string(".absolute.") + symbol_name); symbol_section_sp = std::make_shared<Section>(module_sp, this, SHN_ABS, fake_section_name, @@ -2376,8 +2336,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, Mangled mangled(ConstString(symbol_bare), is_mangled); // Now append the suffix back to mangled and unmangled names. Only do it if - // the - // demangling was successful (string is not empty). + // the demangling was successful (string is not empty). if (has_suffix) { llvm::StringRef suffix = symbol_ref.substr(version_pos); @@ -2393,12 +2352,10 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, } // In ELF all symbol should have a valid size but it is not true for some - // function symbols - // coming from hand written assembly. As none of the function symbol should - // have 0 size we - // try to calculate the size for these symbols in the symtab with saying - // that their original - // size is not valid. + // function symbols coming from hand written assembly. As none of the + // function symbol should have 0 size we try to calculate the size for + // these symbols in the symtab with saying that their original size is not + // valid. bool symbol_size_valid = symbol.st_size != 0 || symbol.getType() != STT_FUNC; @@ -2427,8 +2384,7 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, lldb_private::Section *symtab) { if (symtab->GetObjectFile() != this) { // If the symbol table section is owned by a different object file, have it - // do the - // parsing. + // do the parsing. ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile()); return obj_file_elf->ParseSymbolTable(symbol_table, start_id, symtab); @@ -2445,8 +2401,7 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, symtab_hdr->sh_type == SHT_DYNSYM); // sh_link: section header index of associated string table. - // Section ID's are ones based. - user_id_t strtab_id = symtab_hdr->sh_link + 1; + user_id_t strtab_id = symtab_hdr->sh_link; Section *strtab = section_list->FindSectionByID(strtab_id).get(); if (symtab && strtab) { @@ -2530,19 +2485,17 @@ unsigned ObjectFileELF::PLTRelocationType() { return 0; } -// Returns the size of the normal plt entries and the offset of the first normal -// plt entry. The -// 0th entry in the plt table is usually a resolution entry which have different -// size in some -// architectures then the rest of the plt entries. +// Returns the size of the normal plt entries and the offset of the first +// normal plt entry. The 0th entry in the plt table is usually a resolution +// entry which have different size in some architectures then the rest of the +// plt entries. static std::pair<uint64_t, uint64_t> GetPltEntrySizeAndOffset(const ELFSectionHeader *rel_hdr, const ELFSectionHeader *plt_hdr) { const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; - // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are 16 - // bytes. - // So round the entsize up by the alignment if addralign is set. + // Clang 3.3 sets entsize to 4 for 32-bit binaries, but the plt entries are + // 16 bytes. So round the entsize up by the alignment if addralign is set. elf_xword plt_entsize = plt_hdr->sh_addralign ? llvm::alignTo(plt_hdr->sh_entsize, plt_hdr->sh_addralign) @@ -2554,12 +2507,10 @@ GetPltEntrySizeAndOffset(const ELFSectionHeader *rel_hdr, // just in case. if (plt_entsize <= 4) { // The linker haven't set the plt_hdr->sh_entsize field. Try to guess the - // size of the plt - // entries based on the number of entries and the size of the plt section - // with the - // assumption that the size of the 0th entry is at least as big as the size - // of the normal - // entries and it isn't much bigger then that. + // size of the plt entries based on the number of entries and the size of + // the plt section with the assumption that the size of the 0th entry is at + // least as big as the size of the normal entries and it isn't much bigger + // then that. if (plt_hdr->sh_addralign) plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / (num_relocations + 1) * plt_hdr->sh_addralign; @@ -2602,7 +2553,7 @@ static unsigned ParsePLTRelocations( unsigned slot_type = hdr->GetRelocationJumpSlotType(); unsigned i; for (i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; if (reloc_type(rel) != slot_type) @@ -2660,10 +2611,6 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, if (!symtab_id || !plt_id) return 0; - // Section ID's are ones based; - symtab_id++; - plt_id++; - const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id); if (!plt_hdr) return 0; @@ -2689,7 +2636,7 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, return 0; // sh_link points to associated string table. - Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get(); + Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link).get(); if (!strtab) return 0; @@ -2714,7 +2661,7 @@ ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, rel_data, symtab_data, strtab_data); } -unsigned ObjectFileELF::RelocateSection( +unsigned ObjectFileELF::ApplyRelocations( Symtab *symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, DataExtractor &rel_data, DataExtractor &symtab_data, @@ -2735,7 +2682,7 @@ unsigned ObjectFileELF::RelocateSection( } for (unsigned i = 0; i < num_relocations; ++i) { - if (rel.Parse(rel_data, &offset) == false) + if (!rel.Parse(rel_data, &offset)) break; Symbol *symbol = NULL; @@ -2745,10 +2692,19 @@ unsigned ObjectFileELF::RelocateSection( case R_386_32: case R_386_PC32: default: + // FIXME: This asserts with this input: + // + // foo.cpp + // int main(int argc, char **argv) { return 0; } + // + // clang++.exe --target=i686-unknown-linux-gnu -g -c foo.cpp -o foo.o + // + // and running this on the foo.o module. assert(false && "unexpected relocation type"); } } else { switch (reloc_type(rel)) { + case R_AARCH64_ABS64: case R_X86_64_64: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { @@ -2757,26 +2713,34 @@ unsigned ObjectFileELF::RelocateSection( uint64_t *dst = reinterpret_cast<uint64_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); - *dst = value + ELFRelocation::RelocAddend64(rel); + uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel); + memcpy(dst, &val_offset, sizeof(uint64_t)); } break; } case R_X86_64_32: - case R_X86_64_32S: { + case R_X86_64_32S: + case R_AARCH64_ABS32: { symbol = symtab->FindSymbolByID(reloc_symbol(rel)); if (symbol) { addr_t value = symbol->GetAddressRef().GetFileAddress(); value += ELFRelocation::RelocAddend32(rel); - assert( - (reloc_type(rel) == R_X86_64_32 && (value <= UINT32_MAX)) || + if ((reloc_type(rel) == R_X86_64_32 && (value > UINT32_MAX)) || (reloc_type(rel) == R_X86_64_32S && - ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN)) || + (reloc_type(rel) == R_AARCH64_ABS32 && + ((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"); + break; + } uint32_t truncated_addr = (value & 0xFFFFFFFF); DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer(); uint32_t *dst = reinterpret_cast<uint32_t *>( data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel)); - *dst = truncated_addr; + memcpy(dst, &truncated_addr, sizeof(uint32_t)); } break; } @@ -2791,7 +2755,8 @@ unsigned ObjectFileELF::RelocateSection( } unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, - user_id_t rel_id) { + user_id_t rel_id, + lldb_private::Symtab *thetab) { assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); // Parse in the section list if needed. @@ -2799,9 +2764,8 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, if (!section_list) return 0; - // Section ID's are ones based. - user_id_t symtab_id = rel_hdr->sh_link + 1; - user_id_t debug_id = rel_hdr->sh_info + 1; + user_id_t symtab_id = rel_hdr->sh_link; + user_id_t debug_id = rel_hdr->sh_info; const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); if (!symtab_hdr) @@ -2827,10 +2791,11 @@ unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, DataExtractor symtab_data; DataExtractor debug_data; - if (ReadSectionData(rel, rel_data) && ReadSectionData(symtab, symtab_data) && - ReadSectionData(debug, debug_data)) { - RelocateSection(m_symtab_ap.get(), &m_header, rel_hdr, symtab_hdr, - debug_hdr, rel_data, symtab_data, debug_data, debug); + if (GetData(rel->GetFileOffset(), rel->GetFileSize(), rel_data) && + GetData(symtab->GetFileOffset(), symtab->GetFileSize(), symtab_data) && + GetData(debug->GetFileOffset(), debug->GetFileSize(), debug_data)) { + ApplyRelocations(thetab, &m_header, rel_hdr, symtab_hdr, debug_hdr, + rel_data, symtab_data, debug_data, debug); } return 0; @@ -2842,8 +2807,7 @@ Symtab *ObjectFileELF::GetSymtab() { return NULL; // We always want to use the main object file so we (hopefully) only have one - // cached copy - // of our symtab, dynamic sections, etc. + // cached copy of our symtab, dynamic sections, etc. ObjectFile *module_obj_file = module_sp->GetObjectFile(); if (module_obj_file && module_obj_file != this) return module_obj_file->GetSymtab(); @@ -2858,18 +2822,15 @@ Symtab *ObjectFileELF::GetSymtab() { // Sharable objects and dynamic executables usually have 2 distinct symbol // tables, one named ".symtab", and the other ".dynsym". The dynsym is a - // smaller - // version of the symtab that only contains global symbols. The information - // found - // in the dynsym is therefore also found in the symtab, while the reverse is - // not - // necessarily true. + // smaller version of the symtab that only contains global symbols. The + // information found in the dynsym is therefore also found in the symtab, + // 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. + // doesn't exist then use the dynsym section which should always be + // there. symtab = section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) .get(); @@ -2890,11 +2851,13 @@ Symtab *ObjectFileELF::GetSymtab() { // also be present. const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL); if (symbol) { + const ELFDynamic *pltrelsz = FindDynamicSymbol(DT_PLTRELSZ); + assert(pltrelsz != NULL); // Synthesize trampoline symbols to help navigate the PLT. addr_t addr = symbol->d_ptr; Section *reloc_section = section_list->FindSectionContainingFileAddress(addr).get(); - if (reloc_section) { + if (reloc_section && pltrelsz->d_val > 0) { user_id_t reloc_id = reloc_section->GetID(); const ELFSectionHeaderInfo *reloc_header = GetSectionHeaderByIndex(reloc_id); @@ -2916,29 +2879,55 @@ Symtab *ObjectFileELF::GetSymtab() { } // If we still don't have any symtab then create an empty instance to avoid - // do the section - // lookup next time. + // do the section lookup next time. if (m_symtab_ap == nullptr) m_symtab_ap.reset(new Symtab(this)); m_symtab_ap->CalculateSymbolSizes(); } + return m_symtab_ap.get(); +} + +void ObjectFileELF::RelocateSection(lldb_private::Section *section) +{ + static const char *debug_prefix = ".debug"; + + // Set relocated bit so we stop getting called, regardless of whether we + // actually relocate. + section->SetIsRelocated(true); + + // We only relocate in ELF relocatable files + if (CalculateType() != eTypeObjectFile) + return; + + const char *section_name = section->GetName().GetCString(); + // Can't relocate that which can't be named + if (section_name == nullptr) + return; + + // We don't relocate non-debug sections at the moment + if (strncmp(section_name, debug_prefix, strlen(debug_prefix))) + return; + + // Relocation section names to look for + std::string needle = std::string(".rel") + section_name; + std::string needlea = std::string(".rela") + section_name; + for (SectionHeaderCollIter I = m_section_headers.begin(); I != m_section_headers.end(); ++I) { if (I->sh_type == SHT_RELA || I->sh_type == SHT_REL) { - if (CalculateType() == eTypeObjectFile) { - const char *section_name = I->section_name.AsCString(""); - if (strstr(section_name, ".rela.debug") || - strstr(section_name, ".rel.debug")) { - const ELFSectionHeader &reloc_header = *I; - user_id_t reloc_id = SectionIndex(I); - RelocateDebugSections(&reloc_header, reloc_id); - } + const char *hay_name = I->section_name.GetCString(); + if (hay_name == nullptr) + continue; + if (needle == hay_name || needlea == hay_name) { + const ELFSectionHeader &reloc_header = *I; + user_id_t reloc_id = SectionIndex(I); + RelocateDebugSections(&reloc_header, reloc_id, GetSymtab()); + break; } } } - return m_symtab_ap.get(); } void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, @@ -2948,12 +2937,10 @@ void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, return; // First we save the new symbols into a separate list and add them to the - // symbol table after - // we colleced all symbols we want to add. This is neccessary because adding a - // new symbol - // invalidates the internal index of the symtab what causing the next lookup - // to be slow because - // it have to recalculate the index first. + // symbol table after we colleced all symbols we want to add. This is + // neccessary because adding a new symbol invalidates the internal index of + // the symtab what causing the next lookup to be slow because it have to + // recalculate the index first. std::vector<Symbol> new_symbols; eh_frame->ForEachFDEEntries([this, symbol_table, section_list, &new_symbols]( @@ -3018,8 +3005,7 @@ void ObjectFileELF::Dump(Stream *s) { s->Indent(); s->PutCString("ObjectFileELF"); - ArchSpec header_arch; - GetArchitecture(header_arch); + ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; @@ -3147,8 +3133,8 @@ void ObjectFileELF::DumpELFProgramHeader(Stream *s, //---------------------------------------------------------------------- // DumpELFProgramHeader_p_type // -// Dump an token value for the ELF program header member p_type which -// describes the type of the program header +// Dump an token value for the ELF program header member p_type which describes +// the type of the program header // ---------------------------------------------------------------------- void ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, elf_word p_type) { const int kStrWidth = 15; @@ -3196,11 +3182,9 @@ void ObjectFileELF::DumpELFProgramHeaders(Stream *s) { s->PutCString("==== --------------- -------- -------- -------- " "-------- -------- ------------------------- --------\n"); - uint32_t idx = 0; - for (ProgramHeaderCollConstIter I = m_program_headers.begin(); - I != m_program_headers.end(); ++I, ++idx) { - s->Printf("[%2u] ", idx); - ObjectFileELF::DumpELFProgramHeader(s, *I); + for (const auto &H : llvm::enumerate(m_program_headers)) { + s->Format("[{0,2}] ", H.index()); + ObjectFileELF::DumpELFProgramHeader(s, H.value()); s->EOL(); } } @@ -3307,9 +3291,9 @@ void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) { } } -bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { +ArchSpec ObjectFileELF::GetArchitecture() { if (!ParseHeader()) - return false; + return ArchSpec(); if (m_section_headers.empty()) { // Allow elf notes to be parsed which may affect the detected architecture. @@ -3319,25 +3303,18 @@ bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { if (CalculateType() == eTypeCoreFile && m_arch_spec.TripleOSIsUnspecifiedUnknown()) { // Core files don't have section headers yet they have PT_NOTE program - // headers - // that might shed more light on the architecture - if (ParseProgramHeaders()) { - for (size_t i = 1, count = GetProgramHeaderCount(); i <= count; ++i) { - const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); - if (header && header->p_type == PT_NOTE && header->p_offset != 0 && - header->p_filesz > 0) { - DataExtractor data; - if (data.SetData(m_data, header->p_offset, header->p_filesz) == - header->p_filesz) { - lldb_private::UUID uuid; - RefineModuleDetailsFromNote(data, m_arch_spec, uuid); - } - } + // headers that might shed more light on the architecture + for (const elf::ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_type != PT_NOTE || H.p_offset == 0 || H.p_filesz == 0) + continue; + DataExtractor data; + if (data.SetData(m_data, H.p_offset, H.p_filesz) == H.p_filesz) { + UUID uuid; + RefineModuleDetailsFromNote(data, m_arch_spec, uuid); } } } - arch = m_arch_spec; - return true; + return m_arch_spec; } ObjectFile::Type ObjectFileELF::CalculateType() { @@ -3381,22 +3358,22 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { case llvm::ELF::ET_EXEC: // 2 - Executable file // TODO: is there any way to detect that an executable is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUser; case llvm::ELF::ET_DYN: // 3 - Shared object file // TODO: is there any way to detect that an shared library is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUnknown; case ET_CORE: // 4 - Core file // TODO: is there any way to detect that an core file is a kernel - // related executable by inspecting the program headers, section - // headers, symbols, or any other flag bits??? + // related executable by inspecting the program headers, section headers, + // symbols, or any other flag bits??? return eStrataUnknown; default: @@ -3404,3 +3381,102 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { } return eStrataUnknown; } + +size_t ObjectFileELF::ReadSectionData(Section *section, + lldb::offset_t section_offset, void *dst, + size_t dst_len) { + // If some other objectfile owns this data, pass this to them. + if (section->GetObjectFile() != this) + return section->GetObjectFile()->ReadSectionData(section, section_offset, + dst, dst_len); + + if (!section->Test(SHF_COMPRESSED)) + return ObjectFile::ReadSectionData(section, section_offset, dst, dst_len); + + // For compressed sections we need to read to full data to be able to + // decompress. + DataExtractor data; + ReadSectionData(section, data); + return data.CopyData(section_offset, dst_len, dst); +} + +size_t ObjectFileELF::ReadSectionData(Section *section, + DataExtractor §ion_data) { + // If some other objectfile owns this data, pass this to them. + if (section->GetObjectFile() != this) + return section->GetObjectFile()->ReadSectionData(section, section_data); + + size_t result = ObjectFile::ReadSectionData(section, section_data); + if (result == 0 || !section->Test(SHF_COMPRESSED)) + return result; + + auto Decompressor = llvm::object::Decompressor::create( + section->GetName().GetStringRef(), + {reinterpret_cast<const char *>(section_data.GetDataStart()), + size_t(section_data.GetByteSize())}, + GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8); + if (!Decompressor) { + GetModule()->ReportWarning( + "Unable to initialize decompressor for section '%s': %s", + section->GetName().GetCString(), + llvm::toString(Decompressor.takeError()).c_str()); + section_data.Clear(); + return 0; + } + + auto buffer_sp = + std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0); + if (auto error = Decompressor->decompress( + {reinterpret_cast<char *>(buffer_sp->GetBytes()), + size_t(buffer_sp->GetByteSize())})) { + GetModule()->ReportWarning( + "Decompression of section '%s' failed: %s", + section->GetName().GetCString(), + llvm::toString(std::move(error)).c_str()); + section_data.Clear(); + return 0; + } + + section_data.SetData(buffer_sp); + return buffer_sp->GetByteSize(); +} + +llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() { + ParseProgramHeaders(); + return m_program_headers; +} + +DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) { + return DataExtractor(m_data, H.p_offset, H.p_filesz); +} + +bool ObjectFileELF::AnySegmentHasPhysicalAddress() { + for (const ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_paddr != 0) + return true; + } + return false; +} + +std::vector<ObjectFile::LoadableData> +ObjectFileELF::GetLoadableData(Target &target) { + // Create a list of loadable data from loadable segments, using physical + // addresses if they aren't all null + std::vector<LoadableData> loadables; + bool should_use_paddr = AnySegmentHasPhysicalAddress(); + for (const ELFProgramHeader &H : ProgramHeaders()) { + LoadableData loadable; + if (H.p_type != llvm::ELF::PT_LOAD) + continue; + loadable.Dest = should_use_paddr ? H.p_paddr : H.p_vaddr; + if (loadable.Dest == LLDB_INVALID_ADDRESS) + continue; + if (H.p_filesz == 0) + continue; + auto segment_data = GetSegmentData(H); + loadable.Contents = llvm::ArrayRef<uint8_t>(segment_data.GetDataStart(), + segment_data.GetByteSize()); + loadables.push_back(loadable); + } + return loadables; +} |