diff options
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 426 |
1 files changed, 306 insertions, 120 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 890db5c..f348b94b 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -419,19 +419,35 @@ ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, ObjectFile *ObjectFileELF::CreateMemoryInstance( const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { - if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT)) { - const uint8_t *magic = data_sp->GetBytes(); - if (ELFHeader::MagicBytesMatch(magic)) { - unsigned address_size = ELFHeader::AddressSizeInBytes(magic); - if (address_size == 4 || address_size == 8) { - std::unique_ptr<ObjectFileELF> objfile_up( - new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); - ArchSpec spec = objfile_up->GetArchitecture(); - if (spec && objfile_up->SetModulesArchitecture(spec)) - return objfile_up.release(); - } - } - } + if (!data_sp || data_sp->GetByteSize() < (llvm::ELF::EI_NIDENT)) + return nullptr; + const uint8_t *magic = data_sp->GetBytes(); + if (!ELFHeader::MagicBytesMatch(magic)) + return nullptr; + // Read the ELF header first so we can figure out how many bytes we need + // to read to get as least the ELF header + program headers. + DataExtractor data; + data.SetData(data_sp); + elf::ELFHeader hdr; + lldb::offset_t offset = 0; + if (!hdr.Parse(data, &offset)) + return nullptr; + + // Make sure the address size is set correctly in the ELF header. + if (!hdr.Is32Bit() && !hdr.Is64Bit()) + return nullptr; + // Figure out where the program headers end and read enough bytes to get the + // program headers in their entirety. + lldb::offset_t end_phdrs = hdr.e_phoff + (hdr.e_phentsize * hdr.e_phnum); + if (end_phdrs > data_sp->GetByteSize()) + data_sp = ReadMemory(process_sp, header_addr, end_phdrs); + + std::unique_ptr<ObjectFileELF> objfile_up( + new ObjectFileELF(module_sp, data_sp, process_sp, header_addr)); + ArchSpec spec = objfile_up->GetArchitecture(); + if (spec && objfile_up->SetModulesArchitecture(spec)) + return objfile_up.release(); + return nullptr; } @@ -873,42 +889,37 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) { if (!section_list) return Address(); - // Find the SHT_DYNAMIC (.dynamic) section. - SectionSP dynsym_section_sp( - section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true)); - if (!dynsym_section_sp) - return Address(); - assert(dynsym_section_sp->GetObjectFile() == this); + for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) { + const ELFDynamic &symbol = m_dynamic_symbols[i].symbol; - user_id_t dynsym_id = dynsym_section_sp->GetID(); - const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id); - if (!dynsym_hdr) - return Address(); + if (symbol.d_tag != DT_DEBUG && symbol.d_tag != DT_MIPS_RLD_MAP && + symbol.d_tag != DT_MIPS_RLD_MAP_REL) + continue; - for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) { - ELFDynamic &symbol = m_dynamic_symbols[i]; + // Compute the offset as the number of previous entries plus the size of + // d_tag. + const addr_t offset = (i * 2 + 1) * GetAddressByteSize(); + const addr_t d_file_addr = m_dynamic_base_addr + offset; + Address d_addr; + if (!d_addr.ResolveAddressUsingFileSections(d_file_addr, GetSectionList())) + return Address(); + if (symbol.d_tag == DT_DEBUG) + return d_addr; - if (symbol.d_tag == DT_DEBUG) { - // 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); - } // MIPS executables uses DT_MIPS_RLD_MAP_REL to support PIE. DT_MIPS_RLD_MAP // exists in non-PIE. - else if ((symbol.d_tag == DT_MIPS_RLD_MAP || - symbol.d_tag == DT_MIPS_RLD_MAP_REL) && - target) { - addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize(); - addr_t dyn_base = dynsym_section_sp->GetLoadBaseAddress(target); - if (dyn_base == LLDB_INVALID_ADDRESS) + if ((symbol.d_tag == DT_MIPS_RLD_MAP || + symbol.d_tag == DT_MIPS_RLD_MAP_REL) && + target) { + const addr_t d_load_addr = d_addr.GetLoadAddress(target); + if (d_load_addr == LLDB_INVALID_ADDRESS) return Address(); Status error; if (symbol.d_tag == DT_MIPS_RLD_MAP) { // DT_MIPS_RLD_MAP tag stores an absolute address of the debug pointer. Address addr; - if (target->ReadPointerFromMemory(dyn_base + offset, error, addr, true)) + if (target->ReadPointerFromMemory(d_load_addr, error, addr, true)) return addr; } if (symbol.d_tag == DT_MIPS_RLD_MAP_REL) { @@ -916,18 +927,17 @@ Address ObjectFileELF::GetImageInfoAddress(Target *target) { // relative to the address of the tag. uint64_t rel_offset; rel_offset = target->ReadUnsignedIntegerFromMemory( - dyn_base + offset, GetAddressByteSize(), UINT64_MAX, error, true); + d_load_addr, GetAddressByteSize(), UINT64_MAX, error, true); if (error.Success() && rel_offset != UINT64_MAX) { Address addr; addr_t debug_ptr_address = - dyn_base + (offset - GetAddressByteSize()) + rel_offset; + d_load_addr - GetAddressByteSize() + rel_offset; addr.SetOffset(debug_ptr_address); return addr; } } } } - return Address(); } @@ -970,62 +980,23 @@ Address ObjectFileELF::GetBaseAddress() { return LLDB_INVALID_ADDRESS; } -// ParseDependentModules size_t ObjectFileELF::ParseDependentModules() { if (m_filespec_up) return m_filespec_up->GetSize(); m_filespec_up = std::make_unique<FileSpecList>(); - if (!ParseSectionHeaders()) - return 0; - - SectionList *section_list = GetSectionList(); - if (!section_list) - return 0; - - // Find the SHT_DYNAMIC section. - Section *dynsym = - section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true) - .get(); - if (!dynsym) - return 0; - assert(dynsym->GetObjectFile() == this); - - const ELFSectionHeaderInfo *header = GetSectionHeaderByIndex(dynsym->GetID()); - if (!header) - return 0; - // sh_link: section header index of string table used by entries in the - // section. - Section *dynstr = section_list->FindSectionByID(header->sh_link).get(); - if (!dynstr) - return 0; - - DataExtractor dynsym_data; - DataExtractor dynstr_data; - if (ReadSectionData(dynsym, dynsym_data) && - ReadSectionData(dynstr, dynstr_data)) { - ELFDynamic symbol; - const lldb::offset_t section_size = dynsym_data.GetByteSize(); - lldb::offset_t offset = 0; - - // The only type of entries we are concerned with are tagged DT_NEEDED, - // yielding the name of a required library. - while (offset < section_size) { - if (!symbol.Parse(dynsym_data, &offset)) - break; - - if (symbol.d_tag != DT_NEEDED) + if (ParseDynamicSymbols()) { + for (const auto &entry : m_dynamic_symbols) { + if (entry.symbol.d_tag != DT_NEEDED) continue; - - uint32_t str_index = static_cast<uint32_t>(symbol.d_val); - const char *lib_name = dynstr_data.PeekCStr(str_index); - FileSpec file_spec(lib_name); - FileSystem::Instance().Resolve(file_spec); - m_filespec_up->Append(file_spec); + if (!entry.name.empty()) { + FileSpec file_spec(entry.name); + FileSystem::Instance().Resolve(file_spec); + m_filespec_up->Append(file_spec); + } } } - return m_filespec_up->GetSize(); } @@ -2472,48 +2443,47 @@ size_t ObjectFileELF::ParseDynamicSymbols() { if (m_dynamic_symbols.size()) return m_dynamic_symbols.size(); - SectionList *section_list = GetSectionList(); - if (!section_list) + std::optional<DataExtractor> dynamic_data = GetDynamicData(); + if (!dynamic_data) return 0; - // Find the SHT_DYNAMIC section. - Section *dynsym = - section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true) - .get(); - if (!dynsym) - return 0; - assert(dynsym->GetObjectFile() == this); - - ELFDynamic symbol; - DataExtractor dynsym_data; - if (ReadSectionData(dynsym, dynsym_data)) { - const lldb::offset_t section_size = dynsym_data.GetByteSize(); - lldb::offset_t cursor = 0; - - while (cursor < section_size) { - if (!symbol.Parse(dynsym_data, &cursor)) + ELFDynamicWithName e; + lldb::offset_t cursor = 0; + while (e.symbol.Parse(*dynamic_data, &cursor)) { + m_dynamic_symbols.push_back(e); + if (e.symbol.d_tag == DT_NULL) + break; + } + if (std::optional<DataExtractor> dynstr_data = GetDynstrData()) { + for (ELFDynamicWithName &entry : m_dynamic_symbols) { + switch (entry.symbol.d_tag) { + case DT_NEEDED: + case DT_SONAME: + case DT_RPATH: + case DT_RUNPATH: + case DT_AUXILIARY: + case DT_FILTER: { + lldb::offset_t cursor = entry.symbol.d_val; + const char *name = dynstr_data->GetCStr(&cursor); + if (name) + entry.name = std::string(name); break; - - m_dynamic_symbols.push_back(symbol); + } + default: + break; + } } } - return m_dynamic_symbols.size(); } const ELFDynamic *ObjectFileELF::FindDynamicSymbol(unsigned tag) { if (!ParseDynamicSymbols()) return nullptr; - - DynamicSymbolCollIter I = m_dynamic_symbols.begin(); - DynamicSymbolCollIter E = m_dynamic_symbols.end(); - for (; I != E; ++I) { - ELFDynamic *symbol = &*I; - - if (symbol->d_tag == tag) - return symbol; + for (const auto &entry : m_dynamic_symbols) { + if (entry.symbol.d_tag == tag) + return &entry.symbol; } - return nullptr; } @@ -3230,7 +3200,10 @@ void ObjectFileELF::Dump(Stream *s) { ArchSpec header_arch = GetArchitecture(); *s << ", file = '" << m_file - << "', arch = " << header_arch.GetArchitectureName() << "\n"; + << "', arch = " << header_arch.GetArchitectureName(); + if (m_memory_addr != LLDB_INVALID_ADDRESS) + s->Printf(", addr = %#16.16" PRIx64, m_memory_addr); + s->EOL(); DumpELFHeader(s, m_header); s->EOL(); @@ -3248,6 +3221,12 @@ void ObjectFileELF::Dump(Stream *s) { s->EOL(); DumpDependentModules(s); s->EOL(); + DumpELFDynamic(s); + s->EOL(); + Address image_info_addr = GetImageInfoAddress(nullptr); + if (image_info_addr.IsValid()) + s->Printf("image_info_address = %#16.16" PRIx64 "\n", + image_info_addr.GetFileAddress()); } // DumpELFHeader @@ -3492,6 +3471,111 @@ void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) { } } +std::string static getDynamicTagAsString(uint16_t Arch, uint64_t Type) { +#define DYNAMIC_STRINGIFY_ENUM(tag, value) \ + case value: \ + return #tag; + +#define DYNAMIC_TAG(n, v) + switch (Arch) { + case llvm::ELF::EM_AARCH64: + switch (Type) { +#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG + } + break; + + case llvm::ELF::EM_HEXAGON: + switch (Type) { +#define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef HEXAGON_DYNAMIC_TAG + } + break; + + case llvm::ELF::EM_MIPS: + switch (Type) { +#define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef MIPS_DYNAMIC_TAG + } + break; + + case llvm::ELF::EM_PPC: + switch (Type) { +#define PPC_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef PPC_DYNAMIC_TAG + } + break; + + case llvm::ELF::EM_PPC64: + switch (Type) { +#define PPC64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef PPC64_DYNAMIC_TAG + } + break; + + case llvm::ELF::EM_RISCV: + switch (Type) { +#define RISCV_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef RISCV_DYNAMIC_TAG + } + break; + } +#undef DYNAMIC_TAG + switch (Type) { +// Now handle all dynamic tags except the architecture specific ones +#define AARCH64_DYNAMIC_TAG(name, value) +#define MIPS_DYNAMIC_TAG(name, value) +#define HEXAGON_DYNAMIC_TAG(name, value) +#define PPC_DYNAMIC_TAG(name, value) +#define PPC64_DYNAMIC_TAG(name, value) +#define RISCV_DYNAMIC_TAG(name, value) +// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. +#define DYNAMIC_TAG_MARKER(name, value) +#define DYNAMIC_TAG(name, value) \ + case value: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG +#undef MIPS_DYNAMIC_TAG +#undef HEXAGON_DYNAMIC_TAG +#undef PPC_DYNAMIC_TAG +#undef PPC64_DYNAMIC_TAG +#undef RISCV_DYNAMIC_TAG +#undef DYNAMIC_TAG_MARKER +#undef DYNAMIC_STRINGIFY_ENUM + default: + return "<unknown:>0x" + llvm::utohexstr(Type, true); + } +} + +void ObjectFileELF::DumpELFDynamic(lldb_private::Stream *s) { + ParseDynamicSymbols(); + if (m_dynamic_symbols.empty()) + return; + + s->PutCString(".dynamic:\n"); + s->PutCString("IDX d_tag d_val/d_ptr\n"); + s->PutCString("==== ---------------- ------------------\n"); + uint32_t idx = 0; + for (const auto &entry : m_dynamic_symbols) { + s->Printf("[%2u] ", idx++); + s->Printf( + "%-16s 0x%16.16" PRIx64, + getDynamicTagAsString(m_header.e_machine, entry.symbol.d_tag).c_str(), + entry.symbol.d_ptr); + if (!entry.name.empty()) + s->Printf(" \"%s\"", entry.name.c_str()); + s->EOL(); + } +} + ArchSpec ObjectFileELF::GetArchitecture() { if (!ParseHeader()) return ArchSpec(); @@ -3664,7 +3748,24 @@ llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() { } DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) { - return DataExtractor(m_data, H.p_offset, H.p_filesz); + // Try and read the program header from our cached m_data which can come from + // the file on disk being mmap'ed or from the initial part of the ELF file we + // read from memory and cached. + DataExtractor data = DataExtractor(m_data, H.p_offset, H.p_filesz); + if (data.GetByteSize() == H.p_filesz) + return data; + if (IsInMemory()) { + // We have a ELF file in process memory, read the program header data from + // the process. + if (ProcessSP process_sp = m_process_wp.lock()) { + const lldb::offset_t base_file_addr = GetBaseAddress().GetFileAddress(); + const addr_t load_bias = m_memory_addr - base_file_addr; + const addr_t data_addr = H.p_vaddr + load_bias; + if (DataBufferSP data_sp = ReadMemory(process_sp, data_addr, H.p_memsz)) + return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize()); + } + } + return DataExtractor(); } bool ObjectFileELF::AnySegmentHasPhysicalAddress() { @@ -3704,3 +3805,88 @@ ObjectFileELF::MapFileDataWritable(const FileSpec &file, uint64_t Size, return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size, Offset); } + +std::optional<DataExtractor> ObjectFileELF::GetDynstrData() { + if (SectionList *section_list = GetSectionList()) { + // Find the SHT_DYNAMIC section. + if (Section *dynamic = + section_list + ->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true) + .get()) { + assert(dynamic->GetObjectFile() == this); + if (const ELFSectionHeaderInfo *header = + GetSectionHeaderByIndex(dynamic->GetID())) { + // sh_link: section header index of string table used by entries in + // the section. + if (Section *dynstr = + section_list->FindSectionByID(header->sh_link).get()) { + DataExtractor data; + if (ReadSectionData(dynstr, data)) + return data; + } + } + } + } + + // Every ELF file which represents an executable or shared library has + // mandatory .dynamic entries. Two of these values are DT_STRTAB and DT_STRSZ + // and represent the dynamic symbol tables's string table. These are needed + // by the dynamic loader and we can read them from a process' address space. + // + // When loading and ELF file from memory, only the program headers end up + // being mapped into memory, and we can find these values in the PT_DYNAMIC + // segment. + const ELFDynamic *strtab = FindDynamicSymbol(DT_STRTAB); + const ELFDynamic *strsz = FindDynamicSymbol(DT_STRSZ); + if (strtab == nullptr || strsz == nullptr) + return std::nullopt; + + if (ProcessSP process_sp = m_process_wp.lock()) { + if (DataBufferSP data_sp = + ReadMemory(process_sp, strtab->d_ptr, strsz->d_val)) + return DataExtractor(data_sp, GetByteOrder(), GetAddressByteSize()); + } else { + // We have an ELF file with no section headers or we didn't find the + // .dynamic section. Try and find the .dynstr section. + Address addr; + if (addr.ResolveAddressUsingFileSections(strtab->d_ptr, GetSectionList())) { + DataExtractor data; + addr.GetSection()->GetSectionData(data); + return DataExtractor(data, + strtab->d_ptr - addr.GetSection()->GetFileAddress(), + strsz->d_val); + } + } + return std::nullopt; +} + +std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() { + DataExtractor data; + // The PT_DYNAMIC program header describes where the .dynamic section is and + // doesn't require parsing section headers. The PT_DYNAMIC is required by + // executables and shared libraries so it will always be available. + for (const ELFProgramHeader &H : ProgramHeaders()) { + if (H.p_type == llvm::ELF::PT_DYNAMIC) { + data = GetSegmentData(H); + if (data.GetByteSize() > 0) { + m_dynamic_base_addr = H.p_vaddr; + return data; + } + } + } + // Fall back to using section headers. + if (SectionList *section_list = GetSectionList()) { + // Find the SHT_DYNAMIC section. + if (Section *dynamic = + section_list + ->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true) + .get()) { + assert(dynamic->GetObjectFile() == this); + if (ReadSectionData(dynamic, data)) { + m_dynamic_base_addr = dynamic->GetFileAddress(); + return data; + } + } + } + return std::nullopt; +} |