diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Plugins/ObjectFile | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp | 607 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h | 645 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 5925 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 766 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp | 429 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h | 201 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 11186 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h | 396 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 1715 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h | 532 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp | 63 | ||||
-rw-r--r-- | lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h | 9 |
12 files changed, 10890 insertions, 11584 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index 625cce3c106..a3e82390d26 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -24,240 +24,201 @@ using namespace llvm::ELF; // // GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor // with error handling code and provide for parsing a sequence of values. -static bool -GetMaxU64(const lldb_private::DataExtractor &data, - lldb::offset_t *offset, - uint64_t *value, - uint32_t byte_size) -{ - const lldb::offset_t saved_offset = *offset; - *value = data.GetMaxU64(offset, byte_size); - return *offset != saved_offset; +static bool GetMaxU64(const lldb_private::DataExtractor &data, + lldb::offset_t *offset, uint64_t *value, + uint32_t byte_size) { + const lldb::offset_t saved_offset = *offset; + *value = data.GetMaxU64(offset, byte_size); + return *offset != saved_offset; } -static bool -GetMaxU64(const lldb_private::DataExtractor &data, - lldb::offset_t *offset, - uint64_t *value, - uint32_t byte_size, - uint32_t count) -{ - lldb::offset_t saved_offset = *offset; - - for (uint32_t i = 0; i < count; ++i, ++value) - { - if (GetMaxU64(data, offset, value, byte_size) == false) - { - *offset = saved_offset; - return false; - } +static bool GetMaxU64(const lldb_private::DataExtractor &data, + lldb::offset_t *offset, uint64_t *value, + uint32_t byte_size, uint32_t count) { + lldb::offset_t saved_offset = *offset; + + for (uint32_t i = 0; i < count; ++i, ++value) { + if (GetMaxU64(data, offset, value, byte_size) == false) { + *offset = saved_offset; + return false; } - return true; + } + return true; } -static bool -GetMaxS64(const lldb_private::DataExtractor &data, - lldb::offset_t *offset, - int64_t *value, - uint32_t byte_size) -{ - const lldb::offset_t saved_offset = *offset; - *value = data.GetMaxS64(offset, byte_size); - return *offset != saved_offset; +static bool GetMaxS64(const lldb_private::DataExtractor &data, + lldb::offset_t *offset, int64_t *value, + uint32_t byte_size) { + const lldb::offset_t saved_offset = *offset; + *value = data.GetMaxS64(offset, byte_size); + return *offset != saved_offset; } -static bool -GetMaxS64(const lldb_private::DataExtractor &data, - lldb::offset_t *offset, - int64_t *value, - uint32_t byte_size, - uint32_t count) -{ - lldb::offset_t saved_offset = *offset; - - for (uint32_t i = 0; i < count; ++i, ++value) - { - if (GetMaxS64(data, offset, value, byte_size) == false) - { - *offset = saved_offset; - return false; - } +static bool GetMaxS64(const lldb_private::DataExtractor &data, + lldb::offset_t *offset, int64_t *value, + uint32_t byte_size, uint32_t count) { + lldb::offset_t saved_offset = *offset; + + for (uint32_t i = 0; i < count; ++i, ++value) { + if (GetMaxS64(data, offset, value, byte_size) == false) { + *offset = saved_offset; + return false; } - return true; + } + return true; } //------------------------------------------------------------------------------ // ELFHeader -ELFHeader::ELFHeader() -{ - memset(this, 0, sizeof(ELFHeader)); -} +ELFHeader::ELFHeader() { memset(this, 0, sizeof(ELFHeader)); } -ByteOrder -ELFHeader::GetByteOrder() const -{ - if (e_ident[EI_DATA] == ELFDATA2MSB) - return eByteOrderBig; - if (e_ident[EI_DATA] == ELFDATA2LSB) - return eByteOrderLittle; - return eByteOrderInvalid; +ByteOrder ELFHeader::GetByteOrder() const { + if (e_ident[EI_DATA] == ELFDATA2MSB) + return eByteOrderBig; + if (e_ident[EI_DATA] == ELFDATA2LSB) + return eByteOrderLittle; + return eByteOrderInvalid; } -bool -ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - // Read e_ident. This provides byte order and address size info. - if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL) - return false; +bool ELFHeader::Parse(lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + // Read e_ident. This provides byte order and address size info. + if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL) + return false; - const unsigned byte_size = Is32Bit() ? 4 : 8; - data.SetByteOrder(GetByteOrder()); - data.SetAddressByteSize(byte_size); + const unsigned byte_size = Is32Bit() ? 4 : 8; + data.SetByteOrder(GetByteOrder()); + data.SetAddressByteSize(byte_size); - // Read e_type and e_machine. - if (data.GetU16(offset, &e_type, 2) == NULL) - return false; + // Read e_type and e_machine. + if (data.GetU16(offset, &e_type, 2) == NULL) + return false; - // Read e_version. - if (data.GetU32(offset, &e_version, 1) == NULL) - return false; + // Read e_version. + if (data.GetU32(offset, &e_version, 1) == NULL) + return false; - // Read e_entry, e_phoff and e_shoff. - if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false) - return false; + // Read e_entry, e_phoff and e_shoff. + if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false) + return false; - // Read e_flags. - if (data.GetU32(offset, &e_flags, 1) == NULL) - return false; + // Read e_flags. + if (data.GetU32(offset, &e_flags, 1) == NULL) + return false; - // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and - // e_shstrndx. - if (data.GetU16(offset, &e_ehsize, 6) == NULL) - return false; + // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and + // e_shstrndx. + if (data.GetU16(offset, &e_ehsize, 6) == NULL) + return false; - return true; + return true; } -bool -ELFHeader::MagicBytesMatch(const uint8_t *magic) -{ - return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0; +bool ELFHeader::MagicBytesMatch(const uint8_t *magic) { + return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0; } -unsigned -ELFHeader::AddressSizeInBytes(const uint8_t *magic) -{ - unsigned address_size = 0; - - switch (magic[EI_CLASS]) - { - case ELFCLASS32: - address_size = 4; - break; - - case ELFCLASS64: - address_size = 8; - break; - } - return address_size; -} +unsigned ELFHeader::AddressSizeInBytes(const uint8_t *magic) { + unsigned address_size = 0; -unsigned -ELFHeader::GetRelocationJumpSlotType() const -{ - unsigned slot = 0; - - switch (e_machine) - { - default: - assert(false && "architecture not supported"); - break; - case EM_PPC: - slot = R_PPC_JMP_SLOT; - break; - case EM_PPC64: - slot = R_PPC64_JMP_SLOT; - break; - case EM_386: - case EM_IAMCU: // FIXME: is this correct? - slot = R_386_JUMP_SLOT; - break; - case EM_X86_64: - slot = R_X86_64_JUMP_SLOT; - break; - case EM_ARM: - slot = R_ARM_JUMP_SLOT; - break; - case EM_HEXAGON: - slot = R_HEX_JMP_SLOT; - break; - case EM_AARCH64: - slot = R_AARCH64_JUMP_SLOT; - break; - case EM_MIPS: - slot = R_MIPS_JUMP_SLOT; - break; - case EM_S390: - slot = R_390_JMP_SLOT; - break; - } + switch (magic[EI_CLASS]) { + case ELFCLASS32: + address_size = 4; + break; - return slot; + case ELFCLASS64: + address_size = 8; + break; + } + return address_size; +} + +unsigned ELFHeader::GetRelocationJumpSlotType() const { + unsigned slot = 0; + + switch (e_machine) { + default: + assert(false && "architecture not supported"); + break; + case EM_PPC: + slot = R_PPC_JMP_SLOT; + break; + case EM_PPC64: + slot = R_PPC64_JMP_SLOT; + break; + case EM_386: + case EM_IAMCU: // FIXME: is this correct? + slot = R_386_JUMP_SLOT; + break; + case EM_X86_64: + slot = R_X86_64_JUMP_SLOT; + break; + case EM_ARM: + slot = R_ARM_JUMP_SLOT; + break; + case EM_HEXAGON: + slot = R_HEX_JMP_SLOT; + break; + case EM_AARCH64: + slot = R_AARCH64_JUMP_SLOT; + break; + case EM_MIPS: + slot = R_MIPS_JUMP_SLOT; + break; + case EM_S390: + slot = R_390_JMP_SLOT; + break; + } + + return slot; } //------------------------------------------------------------------------------ // ELFSectionHeader -ELFSectionHeader::ELFSectionHeader() -{ - memset(this, 0, sizeof(ELFSectionHeader)); +ELFSectionHeader::ELFSectionHeader() { + memset(this, 0, sizeof(ELFSectionHeader)); } -bool -ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, - lldb::offset_t *offset) -{ - const unsigned byte_size = data.GetAddressByteSize(); +bool ELFSectionHeader::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const unsigned byte_size = data.GetAddressByteSize(); - // Read sh_name and sh_type. - if (data.GetU32(offset, &sh_name, 2) == NULL) - return false; + // Read sh_name and sh_type. + if (data.GetU32(offset, &sh_name, 2) == NULL) + return false; - // Read sh_flags. - if (GetMaxU64(data, offset, &sh_flags, byte_size) == false) - return false; + // Read sh_flags. + if (GetMaxU64(data, offset, &sh_flags, byte_size) == false) + return false; - // Read sh_addr, sh_off and sh_size. - if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false) - return false; + // Read sh_addr, sh_off and sh_size. + if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false) + return false; - // Read sh_link and sh_info. - if (data.GetU32(offset, &sh_link, 2) == NULL) - return false; + // Read sh_link and sh_info. + if (data.GetU32(offset, &sh_link, 2) == NULL) + return false; - // Read sh_addralign and sh_entsize. - if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false) - return false; + // Read sh_addralign and sh_entsize. + if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false) + return false; - return true; + return true; } //------------------------------------------------------------------------------ // ELFSymbol -ELFSymbol::ELFSymbol() -{ - memset(this, 0, sizeof(ELFSymbol)); -} +ELFSymbol::ELFSymbol() { memset(this, 0, sizeof(ELFSymbol)); } -#define ENUM_TO_CSTR(e) case e: return #e +#define ENUM_TO_CSTR(e) \ + case e: \ + return #e -const char * -ELFSymbol::bindingToCString(unsigned char binding) -{ - switch (binding) - { +const char *ELFSymbol::bindingToCString(unsigned char binding) { + switch (binding) { ENUM_TO_CSTR(STB_LOCAL); ENUM_TO_CSTR(STB_GLOBAL); ENUM_TO_CSTR(STB_WEAK); @@ -265,15 +226,12 @@ ELFSymbol::bindingToCString(unsigned char binding) ENUM_TO_CSTR(STB_HIOS); ENUM_TO_CSTR(STB_LOPROC); ENUM_TO_CSTR(STB_HIPROC); - } - return ""; + } + return ""; } -const char * -ELFSymbol::typeToCString(unsigned char type) -{ - switch (type) - { +const char *ELFSymbol::typeToCString(unsigned char type) { + switch (type) { ENUM_TO_CSTR(STT_NOTYPE); ENUM_TO_CSTR(STT_OBJECT); ENUM_TO_CSTR(STT_FUNC); @@ -285,16 +243,13 @@ ELFSymbol::typeToCString(unsigned char type) ENUM_TO_CSTR(STT_HIOS); ENUM_TO_CSTR(STT_LOPROC); ENUM_TO_CSTR(STT_HIPROC); - } - return ""; + } + return ""; } -const char * -ELFSymbol::sectionIndexToCString (elf_half shndx, - const lldb_private::SectionList *section_list) -{ - switch (shndx) - { +const char *ELFSymbol::sectionIndexToCString( + elf_half shndx, const lldb_private::SectionList *section_list) { + switch (shndx) { ENUM_TO_CSTR(SHN_UNDEF); ENUM_TO_CSTR(SHN_LOPROC); ENUM_TO_CSTR(SHN_HIPROC); @@ -303,180 +258,148 @@ ELFSymbol::sectionIndexToCString (elf_half shndx, ENUM_TO_CSTR(SHN_ABS); ENUM_TO_CSTR(SHN_COMMON); ENUM_TO_CSTR(SHN_XINDEX); - default: - { - const lldb_private::Section *section = section_list->GetSectionAtIndex(shndx).get(); - if (section) - return section->GetName().AsCString(""); - } - break; - } - return ""; + default: { + const lldb_private::Section *section = + section_list->GetSectionAtIndex(shndx).get(); + if (section) + return section->GetName().AsCString(""); + } break; + } + return ""; } -void -ELFSymbol::Dump (lldb_private::Stream *s, - uint32_t idx, - const lldb_private::DataExtractor *strtab_data, - const lldb_private::SectionList *section_list) -{ - s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n", - idx, - st_value, - st_size, - st_name, - st_info, - bindingToCString (getBinding()), - typeToCString (getType()), - st_other, - st_shndx, - sectionIndexToCString (st_shndx, section_list), - strtab_data ? strtab_data->PeekCStr(st_name) : ""); +void ELFSymbol::Dump(lldb_private::Stream *s, uint32_t idx, + const lldb_private::DataExtractor *strtab_data, + const lldb_private::SectionList *section_list) { + s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 + " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n", + idx, st_value, st_size, st_name, st_info, + bindingToCString(getBinding()), typeToCString(getType()), st_other, + st_shndx, sectionIndexToCString(st_shndx, section_list), + strtab_data ? strtab_data->PeekCStr(st_name) : ""); } -bool -ELFSymbol::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - const unsigned byte_size = data.GetAddressByteSize(); - const bool parsing_32 = byte_size == 4; - - // Read st_name. - if (data.GetU32(offset, &st_name, 1) == NULL) - return false; - - if (parsing_32) - { - // Read st_value and st_size. - if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false) - return false; - - // Read st_info and st_other. - if (data.GetU8(offset, &st_info, 2) == NULL) - return false; - - // Read st_shndx. - if (data.GetU16(offset, &st_shndx, 1) == NULL) - return false; - } - else - { - // Read st_info and st_other. - if (data.GetU8(offset, &st_info, 2) == NULL) - return false; - - // Read st_shndx. - if (data.GetU16(offset, &st_shndx, 1) == NULL) - return false; - - // Read st_value and st_size. - if (data.GetU64(offset, &st_value, 2) == NULL) - return false; - } - return true; +bool ELFSymbol::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const unsigned byte_size = data.GetAddressByteSize(); + const bool parsing_32 = byte_size == 4; + + // Read st_name. + if (data.GetU32(offset, &st_name, 1) == NULL) + return false; + + if (parsing_32) { + // Read st_value and st_size. + if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false) + return false; + + // Read st_info and st_other. + if (data.GetU8(offset, &st_info, 2) == NULL) + return false; + + // Read st_shndx. + if (data.GetU16(offset, &st_shndx, 1) == NULL) + return false; + } else { + // Read st_info and st_other. + if (data.GetU8(offset, &st_info, 2) == NULL) + return false; + + // Read st_shndx. + if (data.GetU16(offset, &st_shndx, 1) == NULL) + return false; + + // Read st_value and st_size. + if (data.GetU64(offset, &st_value, 2) == NULL) + return false; + } + return true; } //------------------------------------------------------------------------------ // ELFProgramHeader -ELFProgramHeader::ELFProgramHeader() -{ - memset(this, 0, sizeof(ELFProgramHeader)); +ELFProgramHeader::ELFProgramHeader() { + memset(this, 0, sizeof(ELFProgramHeader)); } -bool -ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, - lldb::offset_t *offset) -{ - const uint32_t byte_size = data.GetAddressByteSize(); - const bool parsing_32 = byte_size == 4; - - // Read p_type; - if (data.GetU32(offset, &p_type, 1) == NULL) - return false; - - if (parsing_32) { - // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz. - if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false) - return false; - - // Read p_flags. - if (data.GetU32(offset, &p_flags, 1) == NULL) - return false; - - // Read p_align. - if (GetMaxU64(data, offset, &p_align, byte_size) == false) - return false; - } - else { - // Read p_flags. - if (data.GetU32(offset, &p_flags, 1) == NULL) - return false; - - // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align. - if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false) - return false; - } - - return true; +bool ELFProgramHeader::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const uint32_t byte_size = data.GetAddressByteSize(); + const bool parsing_32 = byte_size == 4; + + // Read p_type; + if (data.GetU32(offset, &p_type, 1) == NULL) + return false; + + if (parsing_32) { + // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz. + if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false) + return false; + + // Read p_flags. + if (data.GetU32(offset, &p_flags, 1) == NULL) + return false; + + // Read p_align. + if (GetMaxU64(data, offset, &p_align, byte_size) == false) + return false; + } else { + // Read p_flags. + if (data.GetU32(offset, &p_flags, 1) == NULL) + return false; + + // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align. + if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false) + return false; + } + + return true; } //------------------------------------------------------------------------------ // ELFDynamic -ELFDynamic::ELFDynamic() -{ - memset(this, 0, sizeof(ELFDynamic)); -} +ELFDynamic::ELFDynamic() { memset(this, 0, sizeof(ELFDynamic)); } -bool -ELFDynamic::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - const unsigned byte_size = data.GetAddressByteSize(); - return GetMaxS64(data, offset, &d_tag, byte_size, 2); +bool ELFDynamic::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const unsigned byte_size = data.GetAddressByteSize(); + return GetMaxS64(data, offset, &d_tag, byte_size, 2); } //------------------------------------------------------------------------------ // ELFRel -ELFRel::ELFRel() -{ - memset(this, 0, sizeof(ELFRel)); -} +ELFRel::ELFRel() { memset(this, 0, sizeof(ELFRel)); } -bool -ELFRel::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - const unsigned byte_size = data.GetAddressByteSize(); +bool ELFRel::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const unsigned byte_size = data.GetAddressByteSize(); - // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) - return false; + // Read r_offset and r_info. + if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) + return false; - return true; + return true; } //------------------------------------------------------------------------------ // ELFRela -ELFRela::ELFRela() -{ - memset(this, 0, sizeof(ELFRela)); -} +ELFRela::ELFRela() { memset(this, 0, sizeof(ELFRela)); } -bool -ELFRela::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - const unsigned byte_size = data.GetAddressByteSize(); +bool ELFRela::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + const unsigned byte_size = data.GetAddressByteSize(); - // Read r_offset and r_info. - if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) - return false; + // Read r_offset and r_info. + if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false) + return false; - // Read r_addend; - if (GetMaxS64(data, offset, &r_addend, byte_size) == false) - return false; + // Read r_addend; + if (GetMaxS64(data, offset, &r_addend, byte_size) == false) + return false; - return true; + return true; } - - diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index 4ea22b51baf..71b200f1c16 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -25,13 +25,11 @@ #include "lldb/lldb-enumerations.h" -namespace lldb_private -{ +namespace lldb_private { class DataExtractor; } // End namespace lldb_private. -namespace elf -{ +namespace elf { //------------------------------------------------------------------------------ /// @name ELF type definitions. @@ -44,10 +42,10 @@ typedef uint64_t elf_addr; typedef uint64_t elf_off; typedef uint16_t elf_half; typedef uint32_t elf_word; -typedef int32_t elf_sword; +typedef int32_t elf_sword; typedef uint64_t elf_size; typedef uint64_t elf_xword; -typedef int64_t elf_sxword; +typedef int64_t elf_sxword; //@} //------------------------------------------------------------------------------ @@ -56,376 +54,331 @@ typedef int64_t elf_sxword; /// /// This object is used to identify the general attributes on an ELF file and to /// locate additional sections within the file. -struct ELFHeader -{ - unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification. - elf_addr e_entry; ///< Virtual address program entry point. - elf_off e_phoff; ///< File offset of program header table. - elf_off e_shoff; ///< File offset of section header table. - elf_word e_flags; ///< Processor specific flags. - elf_word e_version; ///< Version of object file (always 1). - elf_half e_type; ///< Object file type. - elf_half e_machine; ///< Target architecture. - elf_half e_ehsize; ///< Byte size of the ELF header. - elf_half e_phentsize; ///< Size of a program header table entry. - elf_half e_phnum; ///< Number of program header entries. - elf_half e_shentsize; ///< Size of a section header table entry. - elf_half e_shnum; ///< Number of section header entries. - elf_half e_shstrndx; ///< String table section index. - - ELFHeader(); - - //-------------------------------------------------------------------------- - /// Returns true if this is a 32 bit ELF file header. - /// - /// @return - /// True if this is a 32 bit ELF file header. - bool Is32Bit() const { - return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32; - } - - //-------------------------------------------------------------------------- - /// Returns true if this is a 64 bit ELF file header. - /// - /// @return - /// True if this is a 64 bit ELF file header. - bool Is64Bit() const { - return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64; - } - - //-------------------------------------------------------------------------- - /// The byte order of this ELF file header. - /// - /// @return - /// The byte order of this ELF file as described by the header. - lldb::ByteOrder - GetByteOrder() const; - - //-------------------------------------------------------------------------- - /// The jump slot relocation type of this ELF. - unsigned - GetRelocationJumpSlotType() const; - - //-------------------------------------------------------------------------- - /// Parse an ELFHeader entry starting at position \p offset and - /// update the data extractor with the address size and byte order - /// attributes as defined by the header. - /// - /// @param[in,out] data - /// The DataExtractor to read from. Updated with the address size and - /// byte order attributes appropriate to this header. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFHeader was successfully read and false - /// otherwise. - bool - Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset); - - //-------------------------------------------------------------------------- - /// Examines at most EI_NIDENT bytes starting from the given pointer and - /// determines if the magic ELF identification exists. - /// - /// @return - /// True if the given sequence of bytes identifies an ELF file. - static bool - MagicBytesMatch(const uint8_t *magic); - - //-------------------------------------------------------------------------- - /// Examines at most EI_NIDENT bytes starting from the given address and - /// determines the address size of the underlying ELF file. This function - /// should only be called on an pointer for which MagicBytesMatch returns - /// true. - /// - /// @return - /// The number of bytes forming an address in the ELF file (either 4 or - /// 8), else zero if the address size could not be determined. - static unsigned - AddressSizeInBytes(const uint8_t *magic); +struct ELFHeader { + unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification. + elf_addr e_entry; ///< Virtual address program entry point. + elf_off e_phoff; ///< File offset of program header table. + elf_off e_shoff; ///< File offset of section header table. + elf_word e_flags; ///< Processor specific flags. + elf_word e_version; ///< Version of object file (always 1). + elf_half e_type; ///< Object file type. + elf_half e_machine; ///< Target architecture. + elf_half e_ehsize; ///< Byte size of the ELF header. + elf_half e_phentsize; ///< Size of a program header table entry. + elf_half e_phnum; ///< Number of program header entries. + elf_half e_shentsize; ///< Size of a section header table entry. + elf_half e_shnum; ///< Number of section header entries. + elf_half e_shstrndx; ///< String table section index. + + ELFHeader(); + + //-------------------------------------------------------------------------- + /// Returns true if this is a 32 bit ELF file header. + /// + /// @return + /// True if this is a 32 bit ELF file header. + bool Is32Bit() const { + return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32; + } + + //-------------------------------------------------------------------------- + /// Returns true if this is a 64 bit ELF file header. + /// + /// @return + /// True if this is a 64 bit ELF file header. + bool Is64Bit() const { + return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64; + } + + //-------------------------------------------------------------------------- + /// The byte order of this ELF file header. + /// + /// @return + /// The byte order of this ELF file as described by the header. + lldb::ByteOrder GetByteOrder() const; + + //-------------------------------------------------------------------------- + /// The jump slot relocation type of this ELF. + unsigned GetRelocationJumpSlotType() const; + + //-------------------------------------------------------------------------- + /// Parse an ELFHeader entry starting at position \p offset and + /// update the data extractor with the address size and byte order + /// attributes as defined by the header. + /// + /// @param[in,out] data + /// The DataExtractor to read from. Updated with the address size and + /// byte order attributes appropriate to this header. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFHeader was successfully read and false + /// otherwise. + bool Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset); + + //-------------------------------------------------------------------------- + /// Examines at most EI_NIDENT bytes starting from the given pointer and + /// determines if the magic ELF identification exists. + /// + /// @return + /// True if the given sequence of bytes identifies an ELF file. + static bool MagicBytesMatch(const uint8_t *magic); + + //-------------------------------------------------------------------------- + /// Examines at most EI_NIDENT bytes starting from the given address and + /// determines the address size of the underlying ELF file. This function + /// should only be called on an pointer for which MagicBytesMatch returns + /// true. + /// + /// @return + /// The number of bytes forming an address in the ELF file (either 4 or + /// 8), else zero if the address size could not be determined. + static unsigned AddressSizeInBytes(const uint8_t *magic); }; //------------------------------------------------------------------------------ /// @class ELFSectionHeader /// @brief Generic representation of an ELF section header. -struct ELFSectionHeader -{ - elf_word sh_name; ///< Section name string index. - elf_word sh_type; ///< Section type. - elf_xword sh_flags; ///< Section attributes. - elf_addr sh_addr; ///< Virtual address of the section in memory. - elf_off sh_offset; ///< Start of section from beginning of file. - elf_xword sh_size; ///< Number of bytes occupied in the file. - elf_word sh_link; ///< Index of associated section. - elf_word sh_info; ///< Extra section info (overloaded). - elf_xword sh_addralign; ///< Power of two alignment constraint. - elf_xword sh_entsize; ///< Byte size of each section entry. - - ELFSectionHeader(); - - //-------------------------------------------------------------------------- - /// Parse an ELFSectionHeader entry from the given DataExtracter starting at - /// position \p offset. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFSectionHeader was successfully read and false - /// otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); +struct ELFSectionHeader { + elf_word sh_name; ///< Section name string index. + elf_word sh_type; ///< Section type. + elf_xword sh_flags; ///< Section attributes. + elf_addr sh_addr; ///< Virtual address of the section in memory. + elf_off sh_offset; ///< Start of section from beginning of file. + elf_xword sh_size; ///< Number of bytes occupied in the file. + elf_word sh_link; ///< Index of associated section. + elf_word sh_info; ///< Extra section info (overloaded). + elf_xword sh_addralign; ///< Power of two alignment constraint. + elf_xword sh_entsize; ///< Byte size of each section entry. + + ELFSectionHeader(); + + //-------------------------------------------------------------------------- + /// Parse an ELFSectionHeader entry from the given DataExtracter starting at + /// position \p offset. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFSectionHeader was successfully read and false + /// otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); }; //------------------------------------------------------------------------------ /// @class ELFProgramHeader /// @brief Generic representation of an ELF program header. -struct ELFProgramHeader -{ - elf_word p_type; ///< Type of program segment. - elf_word p_flags; ///< Segment attributes. - elf_off p_offset; ///< Start of segment from beginning of file. - elf_addr p_vaddr; ///< Virtual address of segment in memory. - elf_addr p_paddr; ///< Physical address (for non-VM systems). - elf_xword p_filesz; ///< Byte size of the segment in file. - elf_xword p_memsz; ///< Byte size of the segment in memory. - elf_xword p_align; ///< Segment alignment constraint. - - ELFProgramHeader(); - - /// Parse an ELFProgramHeader entry from the given DataExtractor starting at - /// position \p offset. The address size of the DataExtractor determines if - /// a 32 or 64 bit object is to be parsed. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFProgramHeader was successfully read and false - /// otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); +struct ELFProgramHeader { + elf_word p_type; ///< Type of program segment. + elf_word p_flags; ///< Segment attributes. + elf_off p_offset; ///< Start of segment from beginning of file. + elf_addr p_vaddr; ///< Virtual address of segment in memory. + elf_addr p_paddr; ///< Physical address (for non-VM systems). + elf_xword p_filesz; ///< Byte size of the segment in file. + elf_xword p_memsz; ///< Byte size of the segment in memory. + elf_xword p_align; ///< Segment alignment constraint. + + ELFProgramHeader(); + + /// Parse an ELFProgramHeader entry from the given DataExtractor starting at + /// position \p offset. The address size of the DataExtractor determines if + /// a 32 or 64 bit object is to be parsed. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFProgramHeader was successfully read and false + /// otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); }; //------------------------------------------------------------------------------ /// @class ELFSymbol /// @brief Represents a symbol within an ELF symbol table. -struct ELFSymbol -{ - elf_addr st_value; ///< Absolute or relocatable address. - elf_xword st_size; ///< Size of the symbol or zero. - elf_word st_name; ///< Symbol name string index. - unsigned char st_info; ///< Symbol type and binding attributes. - unsigned char st_other; ///< Reserved for future use. - elf_half st_shndx; ///< Section to which this symbol applies. - - ELFSymbol(); - - /// Returns the binding attribute of the st_info member. - unsigned char getBinding() const { return st_info >> 4; } - - /// Returns the type attribute of the st_info member. - unsigned char getType() const { return st_info & 0x0F; } - - /// Sets the binding and type of the st_info member. - void setBindingAndType(unsigned char binding, unsigned char type) { - st_info = (binding << 4) + (type & 0x0F); - } - - static const char * - bindingToCString(unsigned char binding); - - static const char * - typeToCString(unsigned char type); - - static const char * - sectionIndexToCString(elf_half shndx, - const lldb_private::SectionList *section_list); - - /// Parse an ELFSymbol entry from the given DataExtractor starting at - /// position \p offset. The address size of the DataExtractor determines if - /// a 32 or 64 bit object is to be parsed. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFSymbol was successfully read and false otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); - - void - Dump (lldb_private::Stream *s, - uint32_t idx, - const lldb_private::DataExtractor *strtab_data, - const lldb_private::SectionList *section_list); +struct ELFSymbol { + elf_addr st_value; ///< Absolute or relocatable address. + elf_xword st_size; ///< Size of the symbol or zero. + elf_word st_name; ///< Symbol name string index. + unsigned char st_info; ///< Symbol type and binding attributes. + unsigned char st_other; ///< Reserved for future use. + elf_half st_shndx; ///< Section to which this symbol applies. + + ELFSymbol(); + + /// Returns the binding attribute of the st_info member. + unsigned char getBinding() const { return st_info >> 4; } + + /// Returns the type attribute of the st_info member. + unsigned char getType() const { return st_info & 0x0F; } + + /// Sets the binding and type of the st_info member. + void setBindingAndType(unsigned char binding, unsigned char type) { + st_info = (binding << 4) + (type & 0x0F); + } + + static const char *bindingToCString(unsigned char binding); + + static const char *typeToCString(unsigned char type); + + static const char * + sectionIndexToCString(elf_half shndx, + const lldb_private::SectionList *section_list); + + /// Parse an ELFSymbol entry from the given DataExtractor starting at + /// position \p offset. The address size of the DataExtractor determines if + /// a 32 or 64 bit object is to be parsed. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFSymbol was successfully read and false otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + + void Dump(lldb_private::Stream *s, uint32_t idx, + const lldb_private::DataExtractor *strtab_data, + const lldb_private::SectionList *section_list); }; //------------------------------------------------------------------------------ /// @class ELFDynamic /// @brief Represents an entry in an ELF dynamic table. -struct ELFDynamic -{ - elf_sxword d_tag; ///< Type of dynamic table entry. - union - { - elf_xword d_val; ///< Integer value of the table entry. - elf_addr d_ptr; ///< Pointer value of the table entry. - }; - - ELFDynamic(); - - /// Parse an ELFDynamic entry from the given DataExtractor starting at - /// position \p offset. The address size of the DataExtractor determines if - /// a 32 or 64 bit object is to be parsed. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFDynamic entry was successfully read and false - /// otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); +struct ELFDynamic { + elf_sxword d_tag; ///< Type of dynamic table entry. + union { + elf_xword d_val; ///< Integer value of the table entry. + elf_addr d_ptr; ///< Pointer value of the table entry. + }; + + ELFDynamic(); + + /// Parse an ELFDynamic entry from the given DataExtractor starting at + /// position \p offset. The address size of the DataExtractor determines if + /// a 32 or 64 bit object is to be parsed. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFDynamic entry was successfully read and false + /// otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); }; //------------------------------------------------------------------------------ /// @class ELFRel /// @brief Represents a relocation entry with an implicit addend. -struct ELFRel -{ - elf_addr r_offset; ///< Address of reference. - elf_xword r_info; ///< symbol index and type of relocation. - - ELFRel(); - - /// Parse an ELFRel entry from the given DataExtractor starting at position - /// \p offset. The address size of the DataExtractor determines if a 32 or - /// 64 bit object is to be parsed. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFRel entry was successfully read and false otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); - - /// Returns the type when the given entry represents a 32-bit relocation. - static unsigned - RelocType32(const ELFRel &rel) - { - return rel.r_info & 0x0ff; - } - - /// Returns the type when the given entry represents a 64-bit relocation. - static unsigned - RelocType64(const ELFRel &rel) - { - return rel.r_info & 0xffffffff; - } - - /// Returns the symbol index when the given entry represents a 32-bit - /// relocation. - static unsigned - RelocSymbol32(const ELFRel &rel) - { - return rel.r_info >> 8; - } - - /// Returns the symbol index when the given entry represents a 64-bit - /// relocation. - static unsigned - RelocSymbol64(const ELFRel &rel) - { - return rel.r_info >> 32; - } +struct ELFRel { + elf_addr r_offset; ///< Address of reference. + elf_xword r_info; ///< symbol index and type of relocation. + + ELFRel(); + + /// Parse an ELFRel entry from the given DataExtractor starting at position + /// \p offset. The address size of the DataExtractor determines if a 32 or + /// 64 bit object is to be parsed. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFRel entry was successfully read and false otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + + /// Returns the type when the given entry represents a 32-bit relocation. + static unsigned RelocType32(const ELFRel &rel) { return rel.r_info & 0x0ff; } + + /// Returns the type when the given entry represents a 64-bit relocation. + static unsigned RelocType64(const ELFRel &rel) { + return rel.r_info & 0xffffffff; + } + + /// Returns the symbol index when the given entry represents a 32-bit + /// relocation. + static unsigned RelocSymbol32(const ELFRel &rel) { return rel.r_info >> 8; } + + /// Returns the symbol index when the given entry represents a 64-bit + /// relocation. + static unsigned RelocSymbol64(const ELFRel &rel) { return rel.r_info >> 32; } }; //------------------------------------------------------------------------------ /// @class ELFRela /// @brief Represents a relocation entry with an explicit addend. -struct ELFRela -{ - elf_addr r_offset; ///< Address of reference. - elf_xword r_info; ///< Symbol index and type of relocation. - elf_sxword r_addend; ///< Constant part of expression. - - ELFRela(); - - /// Parse an ELFRela entry from the given DataExtractor starting at position - /// \p offset. The address size of the DataExtractor determines if a 32 or - /// 64 bit object is to be parsed. - /// - /// @param[in] data - /// The DataExtractor to read from. The address size of the extractor - /// determines if a 32 or 64 bit object should be read. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFRela entry was successfully read and false otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); - - /// Returns the type when the given entry represents a 32-bit relocation. - static unsigned - RelocType32(const ELFRela &rela) - { - return rela.r_info & 0x0ff; - } - - /// Returns the type when the given entry represents a 64-bit relocation. - static unsigned - RelocType64(const ELFRela &rela) - { - return rela.r_info & 0xffffffff; - } - - /// Returns the symbol index when the given entry represents a 32-bit - /// relocation. - static unsigned - RelocSymbol32(const ELFRela &rela) - { - return rela.r_info >> 8; - } - - /// Returns the symbol index when the given entry represents a 64-bit - /// relocation. - static unsigned - RelocSymbol64(const ELFRela &rela) - { - return rela.r_info >> 32; - } +struct ELFRela { + elf_addr r_offset; ///< Address of reference. + elf_xword r_info; ///< Symbol index and type of relocation. + elf_sxword r_addend; ///< Constant part of expression. + + ELFRela(); + + /// Parse an ELFRela entry from the given DataExtractor starting at position + /// \p offset. The address size of the DataExtractor determines if a 32 or + /// 64 bit object is to be parsed. + /// + /// @param[in] data + /// The DataExtractor to read from. The address size of the extractor + /// determines if a 32 or 64 bit object should be read. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFRela entry was successfully read and false otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + + /// Returns the type when the given entry represents a 32-bit relocation. + static unsigned RelocType32(const ELFRela &rela) { + return rela.r_info & 0x0ff; + } + + /// Returns the type when the given entry represents a 64-bit relocation. + static unsigned RelocType64(const ELFRela &rela) { + return rela.r_info & 0xffffffff; + } + + /// Returns the symbol index when the given entry represents a 32-bit + /// relocation. + static unsigned RelocSymbol32(const ELFRela &rela) { + return rela.r_info >> 8; + } + + /// Returns the symbol index when the given entry represents a 64-bit + /// relocation. + static unsigned RelocSymbol64(const ELFRela &rela) { + return rela.r_info >> 32; + } }; } // End namespace elf. diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 6a372e42bea..42e6dbc7f90 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -9,8 +9,8 @@ #include "ObjectFileELF.h" -#include <cassert> #include <algorithm> +#include <cassert> #include <unordered_map> #include "lldb/Core/ArchSpec.h" @@ -35,8 +35,10 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" -#define CASE_AND_STREAM(s, def, width) \ - case def: s->Printf("%-*s", width, #def); break; +#define CASE_AND_STREAM(s, def, width) \ + case def: \ + s->Printf("%-*s", width, #def); \ + break; using namespace lldb; using namespace lldb_private; @@ -47,64 +49,64 @@ namespace { // ELF note owner definitions const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD"; -const char *const LLDB_NT_OWNER_GNU = "GNU"; -const char *const LLDB_NT_OWNER_NETBSD = "NetBSD"; -const char *const LLDB_NT_OWNER_CSR = "csr"; +const char *const LLDB_NT_OWNER_GNU = "GNU"; +const char *const LLDB_NT_OWNER_NETBSD = "NetBSD"; +const char *const LLDB_NT_OWNER_CSR = "csr"; const char *const LLDB_NT_OWNER_ANDROID = "Android"; -const char *const LLDB_NT_OWNER_CORE = "CORE"; -const char *const LLDB_NT_OWNER_LINUX = "LINUX"; +const char *const LLDB_NT_OWNER_CORE = "CORE"; +const char *const LLDB_NT_OWNER_LINUX = "LINUX"; // ELF note type definitions -const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01; +const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01; const elf_word LLDB_NT_FREEBSD_ABI_SIZE = 4; -const elf_word LLDB_NT_GNU_ABI_TAG = 0x01; -const elf_word LLDB_NT_GNU_ABI_SIZE = 16; +const elf_word LLDB_NT_GNU_ABI_TAG = 0x01; +const elf_word LLDB_NT_GNU_ABI_SIZE = 16; const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03; -const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01; -const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4; +const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01; +const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4; // GNU ABI note OS constants -const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00; -const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01; +const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00; +const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01; const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; // LLDB_NT_OWNER_CORE and LLDB_NT_OWNER_LINUX note contants -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_SIGINFO 0x53494749 -#define NT_FILE 0x46494c45 -#define NT_PRXFPREG 0x46e62b7f -#define NT_PPC_VMX 0x100 -#define NT_PPC_SPE 0x101 -#define NT_PPC_VSX 0x102 -#define NT_386_TLS 0x200 -#define NT_386_IOPERM 0x201 -#define NT_X86_XSTATE 0x202 -#define NT_S390_HIGH_GPRS 0x300 -#define NT_S390_TIMER 0x301 -#define NT_S390_TODCMP 0x302 -#define NT_S390_TODPREG 0x303 -#define NT_S390_CTRS 0x304 -#define NT_S390_PREFIX 0x305 -#define NT_S390_LAST_BREAK 0x306 -#define NT_S390_SYSTEM_CALL 0x307 -#define NT_S390_TDB 0x308 -#define NT_S390_VXRS_LOW 0x309 -#define NT_S390_VXRS_HIGH 0x30a -#define NT_ARM_VFP 0x400 -#define NT_ARM_TLS 0x401 -#define NT_ARM_HW_BREAK 0x402 -#define NT_ARM_HW_WATCH 0x403 -#define NT_ARM_SYSTEM_CALL 0x404 -#define NT_METAG_CBUF 0x500 -#define NT_METAG_RPIPE 0x501 -#define NT_METAG_TLS 0x502 +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f +#define NT_PPC_VMX 0x100 +#define NT_PPC_SPE 0x101 +#define NT_PPC_VSX 0x102 +#define NT_386_TLS 0x200 +#define NT_386_IOPERM 0x201 +#define NT_X86_XSTATE 0x202 +#define NT_S390_HIGH_GPRS 0x300 +#define NT_S390_TIMER 0x301 +#define NT_S390_TODCMP 0x302 +#define NT_S390_TODPREG 0x303 +#define NT_S390_CTRS 0x304 +#define NT_S390_PREFIX 0x305 +#define NT_S390_LAST_BREAK 0x306 +#define NT_S390_SYSTEM_CALL 0x307 +#define NT_S390_TDB 0x308 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a +#define NT_ARM_VFP 0x400 +#define NT_ARM_TLS 0x401 +#define NT_ARM_HW_BREAK 0x402 +#define NT_ARM_HW_WATCH 0x403 +#define NT_ARM_SYSTEM_CALL 0x404 +#define NT_METAG_CBUF 0x500 +#define NT_METAG_RPIPE 0x501 +#define NT_METAG_TLS 0x502 //===----------------------------------------------------------------------===// /// @class ELFRelocation @@ -112,401 +114,335 @@ const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02; /// /// This helper class allows us to parse both ELFRel and ELFRela relocation /// entries in a generic manner. -class ELFRelocation -{ +class ELFRelocation { public: + /// Constructs an ELFRelocation entry with a personality as given by @p + /// type. + /// + /// @param type Either DT_REL or DT_RELA. Any other value is invalid. + ELFRelocation(unsigned type); - /// Constructs an ELFRelocation entry with a personality as given by @p - /// type. - /// - /// @param type Either DT_REL or DT_RELA. Any other value is invalid. - ELFRelocation(unsigned type); - - ~ELFRelocation(); + ~ELFRelocation(); - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); - static unsigned - RelocType32(const ELFRelocation &rel); + static unsigned RelocType32(const ELFRelocation &rel); - static unsigned - RelocType64(const ELFRelocation &rel); + static unsigned RelocType64(const ELFRelocation &rel); - static unsigned - RelocSymbol32(const ELFRelocation &rel); + static unsigned RelocSymbol32(const ELFRelocation &rel); - static unsigned - RelocSymbol64(const ELFRelocation &rel); + static unsigned RelocSymbol64(const ELFRelocation &rel); - static unsigned - RelocOffset32(const ELFRelocation &rel); + static unsigned RelocOffset32(const ELFRelocation &rel); - static unsigned - RelocOffset64(const ELFRelocation &rel); + static unsigned RelocOffset64(const ELFRelocation &rel); - static unsigned - RelocAddend32(const ELFRelocation &rel); + static unsigned RelocAddend32(const ELFRelocation &rel); - static unsigned - RelocAddend64(const ELFRelocation &rel); + static unsigned RelocAddend64(const ELFRelocation &rel); private: - typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion; + typedef llvm::PointerUnion<ELFRel *, ELFRela *> RelocUnion; - RelocUnion reloc; + RelocUnion reloc; }; -ELFRelocation::ELFRelocation(unsigned type) -{ - if (type == DT_REL || type == SHT_REL) - reloc = new ELFRel(); - else if (type == DT_RELA || type == SHT_RELA) - reloc = new ELFRela(); - else { - assert(false && "unexpected relocation type"); - reloc = static_cast<ELFRel*>(NULL); - } +ELFRelocation::ELFRelocation(unsigned type) { + if (type == DT_REL || type == SHT_REL) + reloc = new ELFRel(); + else if (type == DT_RELA || type == SHT_RELA) + reloc = new ELFRela(); + else { + assert(false && "unexpected relocation type"); + reloc = static_cast<ELFRel *>(NULL); + } } -ELFRelocation::~ELFRelocation() -{ - if (reloc.is<ELFRel*>()) - delete reloc.get<ELFRel*>(); - else - delete reloc.get<ELFRela*>(); +ELFRelocation::~ELFRelocation() { + if (reloc.is<ELFRel *>()) + delete reloc.get<ELFRel *>(); + else + delete reloc.get<ELFRela *>(); } -bool -ELFRelocation::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset) -{ - if (reloc.is<ELFRel*>()) - return reloc.get<ELFRel*>()->Parse(data, offset); - else - return reloc.get<ELFRela*>()->Parse(data, offset); +bool ELFRelocation::Parse(const lldb_private::DataExtractor &data, + lldb::offset_t *offset) { + if (reloc.is<ELFRel *>()) + return reloc.get<ELFRel *>()->Parse(data, offset); + else + return reloc.get<ELFRela *>()->Parse(data, offset); } -unsigned -ELFRelocation::RelocType32(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return ELFRel::RelocType32(*rel.reloc.get<ELFRel*>()); - else - return ELFRela::RelocType32(*rel.reloc.get<ELFRela*>()); +unsigned ELFRelocation::RelocType32(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return ELFRel::RelocType32(*rel.reloc.get<ELFRel *>()); + else + return ELFRela::RelocType32(*rel.reloc.get<ELFRela *>()); } -unsigned -ELFRelocation::RelocType64(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return ELFRel::RelocType64(*rel.reloc.get<ELFRel*>()); - else - return ELFRela::RelocType64(*rel.reloc.get<ELFRela*>()); +unsigned ELFRelocation::RelocType64(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return ELFRel::RelocType64(*rel.reloc.get<ELFRel *>()); + else + return ELFRela::RelocType64(*rel.reloc.get<ELFRela *>()); } -unsigned -ELFRelocation::RelocSymbol32(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return ELFRel::RelocSymbol32(*rel.reloc.get<ELFRel*>()); - else - return ELFRela::RelocSymbol32(*rel.reloc.get<ELFRela*>()); +unsigned ELFRelocation::RelocSymbol32(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return ELFRel::RelocSymbol32(*rel.reloc.get<ELFRel *>()); + else + return ELFRela::RelocSymbol32(*rel.reloc.get<ELFRela *>()); } -unsigned -ELFRelocation::RelocSymbol64(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return ELFRel::RelocSymbol64(*rel.reloc.get<ELFRel*>()); - else - return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>()); +unsigned ELFRelocation::RelocSymbol64(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return ELFRel::RelocSymbol64(*rel.reloc.get<ELFRel *>()); + else + return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela *>()); } -unsigned -ELFRelocation::RelocOffset32(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return rel.reloc.get<ELFRel*>()->r_offset; - else - return rel.reloc.get<ELFRela*>()->r_offset; +unsigned ELFRelocation::RelocOffset32(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return rel.reloc.get<ELFRel *>()->r_offset; + else + return rel.reloc.get<ELFRela *>()->r_offset; } -unsigned -ELFRelocation::RelocOffset64(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return rel.reloc.get<ELFRel*>()->r_offset; - else - return rel.reloc.get<ELFRela*>()->r_offset; +unsigned ELFRelocation::RelocOffset64(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return rel.reloc.get<ELFRel *>()->r_offset; + else + return rel.reloc.get<ELFRela *>()->r_offset; } -unsigned -ELFRelocation::RelocAddend32(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return 0; - else - return rel.reloc.get<ELFRela*>()->r_addend; +unsigned ELFRelocation::RelocAddend32(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return 0; + else + return rel.reloc.get<ELFRela *>()->r_addend; } -unsigned -ELFRelocation::RelocAddend64(const ELFRelocation &rel) -{ - if (rel.reloc.is<ELFRel*>()) - return 0; - else - return rel.reloc.get<ELFRela*>()->r_addend; +unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { + if (rel.reloc.is<ELFRel *>()) + return 0; + else + return rel.reloc.get<ELFRela *>()->r_addend; } } // end anonymous namespace -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. - if (n_namesz == 4) - { - char buf[4]; - if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4) - return false; - if (strncmp (buf, "CORE", 4) == 0) - { - n_name = "CORE"; - *offset += 4; - return true; - } - } - - const char *cstr = data.GetCStr(offset, llvm::alignTo (n_namesz, 4)); - if (cstr == NULL) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); - if (log) - log->Printf("Failed to parse note name lacking nul terminator"); - - return false; - } - n_name = cstr; - return true; -} - -static uint32_t -kalimbaVariantFromElfFlags(const elf::elf_word e_flags) -{ - const uint32_t dsp_rev = e_flags & 0xFF; - uint32_t kal_arch_variant = LLDB_INVALID_CPUTYPE; - switch(dsp_rev) - { - // TODO(mg11) Support more variants - case 10: - kal_arch_variant = llvm::Triple::KalimbaSubArch_v3; - break; - case 14: - kal_arch_variant = llvm::Triple::KalimbaSubArch_v4; - break; - case 17: - case 20: - kal_arch_variant = llvm::Triple::KalimbaSubArch_v5; - break; - default: - break; - } - return kal_arch_variant; -} - -static uint32_t -mipsVariantFromElfFlags(const elf::elf_word e_flags, uint32_t endian) -{ - const uint32_t mips_arch = e_flags & llvm::ELF::EF_MIPS_ARCH; - uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown; - - switch (mips_arch) - { - case llvm::ELF::EF_MIPS_ARCH_1: - case llvm::ELF::EF_MIPS_ARCH_2: - case llvm::ELF::EF_MIPS_ARCH_32: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el : ArchSpec::eMIPSSubType_mips32; - case llvm::ELF::EF_MIPS_ARCH_32R2: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r2el : ArchSpec::eMIPSSubType_mips32r2; - case llvm::ELF::EF_MIPS_ARCH_32R6: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r6el : ArchSpec::eMIPSSubType_mips32r6; - case llvm::ELF::EF_MIPS_ARCH_3: - case llvm::ELF::EF_MIPS_ARCH_4: - case llvm::ELF::EF_MIPS_ARCH_5: - case llvm::ELF::EF_MIPS_ARCH_64: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el : ArchSpec::eMIPSSubType_mips64; - case llvm::ELF::EF_MIPS_ARCH_64R2: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r2el : ArchSpec::eMIPSSubType_mips64r2; - case llvm::ELF::EF_MIPS_ARCH_64R6: - return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r6el : ArchSpec::eMIPSSubType_mips64r6; - default: - break; - } - - return arch_variant; -} +bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { + // Read all fields. + if (data.GetU32(offset, &n_namesz, 3) == NULL) + return false; -static uint32_t -subTypeFromElfHeader(const elf::ELFHeader& header) -{ - if (header.e_machine == llvm::ELF::EM_MIPS) - return mipsVariantFromElfFlags (header.e_flags, - header.e_ident[EI_DATA]); + // 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) + return false; + if (strncmp(buf, "CORE", 4) == 0) { + n_name = "CORE"; + *offset += 4; + return true; + } + } + + const char *cstr = data.GetCStr(offset, llvm::alignTo(n_namesz, 4)); + if (cstr == NULL) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); + if (log) + log->Printf("Failed to parse note name lacking nul terminator"); - return - llvm::ELF::EM_CSR_KALIMBA == header.e_machine ? - kalimbaVariantFromElfFlags(header.e_flags) : - LLDB_INVALID_CPUTYPE; + return false; + } + n_name = cstr; + return true; +} + +static uint32_t kalimbaVariantFromElfFlags(const elf::elf_word e_flags) { + const uint32_t dsp_rev = e_flags & 0xFF; + uint32_t kal_arch_variant = LLDB_INVALID_CPUTYPE; + switch (dsp_rev) { + // TODO(mg11) Support more variants + case 10: + kal_arch_variant = llvm::Triple::KalimbaSubArch_v3; + break; + case 14: + kal_arch_variant = llvm::Triple::KalimbaSubArch_v4; + break; + case 17: + case 20: + kal_arch_variant = llvm::Triple::KalimbaSubArch_v5; + break; + default: + break; + } + return kal_arch_variant; +} + +static uint32_t mipsVariantFromElfFlags(const elf::elf_word e_flags, + uint32_t endian) { + const uint32_t mips_arch = e_flags & llvm::ELF::EF_MIPS_ARCH; + uint32_t arch_variant = ArchSpec::eMIPSSubType_unknown; + + switch (mips_arch) { + case llvm::ELF::EF_MIPS_ARCH_1: + case llvm::ELF::EF_MIPS_ARCH_2: + case llvm::ELF::EF_MIPS_ARCH_32: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el + : ArchSpec::eMIPSSubType_mips32; + case llvm::ELF::EF_MIPS_ARCH_32R2: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r2el + : ArchSpec::eMIPSSubType_mips32r2; + case llvm::ELF::EF_MIPS_ARCH_32R6: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r6el + : ArchSpec::eMIPSSubType_mips32r6; + case llvm::ELF::EF_MIPS_ARCH_3: + case llvm::ELF::EF_MIPS_ARCH_4: + case llvm::ELF::EF_MIPS_ARCH_5: + case llvm::ELF::EF_MIPS_ARCH_64: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el + : ArchSpec::eMIPSSubType_mips64; + case llvm::ELF::EF_MIPS_ARCH_64R2: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r2el + : ArchSpec::eMIPSSubType_mips64r2; + case llvm::ELF::EF_MIPS_ARCH_64R6: + return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64r6el + : ArchSpec::eMIPSSubType_mips64r6; + default: + break; + } + + return arch_variant; +} + +static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) { + if (header.e_machine == llvm::ELF::EM_MIPS) + return mipsVariantFromElfFlags(header.e_flags, header.e_ident[EI_DATA]); + + return llvm::ELF::EM_CSR_KALIMBA == header.e_machine + ? kalimbaVariantFromElfFlags(header.e_flags) + : LLDB_INVALID_CPUTYPE; } //! The kalimba toolchain identifies a code section as being //! one with the SHT_PROGBITS set in the section sh_type and the top //! bit in the 32-bit address field set. static lldb::SectionType -kalimbaSectionType( - const elf::ELFHeader& header, - const elf::ELFSectionHeader& sect_hdr) -{ - if (llvm::ELF::EM_CSR_KALIMBA != header.e_machine) - { - return eSectionTypeOther; - } +kalimbaSectionType(const elf::ELFHeader &header, + const elf::ELFSectionHeader §_hdr) { + if (llvm::ELF::EM_CSR_KALIMBA != header.e_machine) { + return eSectionTypeOther; + } - if (llvm::ELF::SHT_NOBITS == sect_hdr.sh_type) - { - return eSectionTypeZeroFill; - } + if (llvm::ELF::SHT_NOBITS == sect_hdr.sh_type) { + return eSectionTypeZeroFill; + } - if (llvm::ELF::SHT_PROGBITS == sect_hdr.sh_type) - { - const lldb::addr_t KAL_CODE_BIT = 1 << 31; - return KAL_CODE_BIT & sect_hdr.sh_addr ? - eSectionTypeCode : eSectionTypeData; - } + if (llvm::ELF::SHT_PROGBITS == sect_hdr.sh_type) { + const lldb::addr_t KAL_CODE_BIT = 1 << 31; + return KAL_CODE_BIT & sect_hdr.sh_addr ? eSectionTypeCode + : eSectionTypeData; + } - return eSectionTypeOther; + return eSectionTypeOther; } // Arbitrary constant used as UUID prefix for core files. -const uint32_t -ObjectFileELF::g_core_uuid_magic(0xE210C); +const uint32_t ObjectFileELF::g_core_uuid_magic(0xE210C); //------------------------------------------------------------------ // Static methods. //------------------------------------------------------------------ -void -ObjectFileELF::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - CreateMemoryInstance, - GetModuleSpecifications); -} - -void -ObjectFileELF::Terminate() -{ - PluginManager::UnregisterPlugin(CreateInstance); -} - -lldb_private::ConstString -ObjectFileELF::GetPluginNameStatic() -{ - static ConstString g_name("elf"); - return g_name; -} - -const char * -ObjectFileELF::GetPluginDescriptionStatic() -{ - return "ELF object file reader."; -} - -ObjectFile * -ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp, - DataBufferSP &data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) -{ - if (!data_sp) - { - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - data_offset = 0; - } +void ObjectFileELF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} - if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset)) - { - const uint8_t *magic = data_sp->GetBytes() + data_offset; - if (ELFHeader::MagicBytesMatch(magic)) - { - // Update the data to contain the entire file if it doesn't already - if (data_sp->GetByteSize() < length) { - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - data_offset = 0; - magic = data_sp->GetBytes(); - } - unsigned address_size = ELFHeader::AddressSizeInBytes(magic); - 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)) - return objfile_ap.release(); - } - } - } - return NULL; +void ObjectFileELF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } +lldb_private::ConstString ObjectFileELF::GetPluginNameStatic() { + static ConstString g_name("elf"); + return g_name; +} -ObjectFile* -ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& 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::auto_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)) - return objfile_ap.release(); - } - } - } - return NULL; +const char *ObjectFileELF::GetPluginDescriptionStatic() { + return "ELF object file reader."; } -bool -ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) -{ - if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset)) - { - const uint8_t *magic = data_sp->GetBytes() + data_offset; - return ELFHeader::MagicBytesMatch(magic); - } - return false; +ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + data_offset = 0; + } + + if (data_sp && + data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset)) { + const uint8_t *magic = data_sp->GetBytes() + data_offset; + if (ELFHeader::MagicBytesMatch(magic)) { + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + data_offset = 0; + magic = data_sp->GetBytes(); + } + unsigned address_size = ELFHeader::AddressSizeInBytes(magic); + 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)) + return objfile_ap.release(); + } + } + } + return NULL; +} + +ObjectFile *ObjectFileELF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &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::auto_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)) + return objfile_ap.release(); + } + } + } + return NULL; +} + +bool ObjectFileELF::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + if (data_sp && + data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset)) { + const uint8_t *magic = data_sp->GetBytes() + data_offset; + return ELFHeader::MagicBytesMatch(magic); + } + return false; } /* @@ -515,130 +451,117 @@ ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp, * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. */ -static uint32_t -calc_crc32(uint32_t crc, const void *buf, size_t size) -{ - static const uint32_t g_crc32_tab[] = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d - }; - const uint8_t *p = (const uint8_t *)buf; - - crc = crc ^ ~0U; - while (size--) - crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); - return crc ^ ~0U; -} - -static uint32_t -calc_gnu_debuglink_crc32(const void *buf, size_t size) -{ - return calc_crc32(0U, buf, size); -} - -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; - - 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. - break; - } - - core_notes_crc = calc_crc32(core_notes_crc, - segment_data.GetDataStart(), - segment_data.GetByteSize()); - } - } - - return core_notes_crc; -} - -static const char* -OSABIAsCString (unsigned char osabi_byte) -{ -#define _MAKE_OSABI_CASE(x) case x: return #x - switch (osabi_byte) - { - _MAKE_OSABI_CASE(ELFOSABI_NONE); - _MAKE_OSABI_CASE(ELFOSABI_HPUX); - _MAKE_OSABI_CASE(ELFOSABI_NETBSD); - _MAKE_OSABI_CASE(ELFOSABI_GNU); - _MAKE_OSABI_CASE(ELFOSABI_HURD); - _MAKE_OSABI_CASE(ELFOSABI_SOLARIS); - _MAKE_OSABI_CASE(ELFOSABI_AIX); - _MAKE_OSABI_CASE(ELFOSABI_IRIX); - _MAKE_OSABI_CASE(ELFOSABI_FREEBSD); - _MAKE_OSABI_CASE(ELFOSABI_TRU64); - _MAKE_OSABI_CASE(ELFOSABI_MODESTO); - _MAKE_OSABI_CASE(ELFOSABI_OPENBSD); - _MAKE_OSABI_CASE(ELFOSABI_OPENVMS); - _MAKE_OSABI_CASE(ELFOSABI_NSK); - _MAKE_OSABI_CASE(ELFOSABI_AROS); - _MAKE_OSABI_CASE(ELFOSABI_FENIXOS); - _MAKE_OSABI_CASE(ELFOSABI_C6000_ELFABI); - _MAKE_OSABI_CASE(ELFOSABI_C6000_LINUX); - _MAKE_OSABI_CASE(ELFOSABI_ARM); - _MAKE_OSABI_CASE(ELFOSABI_STANDALONE); - default: - return "<unknown-osabi>"; - } +static uint32_t calc_crc32(uint32_t crc, const void *buf, size_t size) { + static const uint32_t g_crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + const uint8_t *p = (const uint8_t *)buf; + + crc = crc ^ ~0U; + while (size--) + crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return crc ^ ~0U; +} + +static uint32_t calc_gnu_debuglink_crc32(const void *buf, size_t size) { + return calc_crc32(0U, buf, size); +} + +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; + + 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. + break; + } + + core_notes_crc = calc_crc32(core_notes_crc, segment_data.GetDataStart(), + segment_data.GetByteSize()); + } + } + + return core_notes_crc; +} + +static const char *OSABIAsCString(unsigned char osabi_byte) { +#define _MAKE_OSABI_CASE(x) \ + case x: \ + return #x + switch (osabi_byte) { + _MAKE_OSABI_CASE(ELFOSABI_NONE); + _MAKE_OSABI_CASE(ELFOSABI_HPUX); + _MAKE_OSABI_CASE(ELFOSABI_NETBSD); + _MAKE_OSABI_CASE(ELFOSABI_GNU); + _MAKE_OSABI_CASE(ELFOSABI_HURD); + _MAKE_OSABI_CASE(ELFOSABI_SOLARIS); + _MAKE_OSABI_CASE(ELFOSABI_AIX); + _MAKE_OSABI_CASE(ELFOSABI_IRIX); + _MAKE_OSABI_CASE(ELFOSABI_FREEBSD); + _MAKE_OSABI_CASE(ELFOSABI_TRU64); + _MAKE_OSABI_CASE(ELFOSABI_MODESTO); + _MAKE_OSABI_CASE(ELFOSABI_OPENBSD); + _MAKE_OSABI_CASE(ELFOSABI_OPENVMS); + _MAKE_OSABI_CASE(ELFOSABI_NSK); + _MAKE_OSABI_CASE(ELFOSABI_AROS); + _MAKE_OSABI_CASE(ELFOSABI_FENIXOS); + _MAKE_OSABI_CASE(ELFOSABI_C6000_ELFABI); + _MAKE_OSABI_CASE(ELFOSABI_C6000_LINUX); + _MAKE_OSABI_CASE(ELFOSABI_ARM); + _MAKE_OSABI_CASE(ELFOSABI_STANDALONE); + default: + return "<unknown-osabi>"; + } #undef _MAKE_OSABI_CASE } @@ -648,2492 +571,2422 @@ OSABIAsCString (unsigned char osabi_byte) // This function is only being kept to validate the move. // // TODO : Remove this function -static bool -GetOsFromOSABI (unsigned char osabi_byte, llvm::Triple::OSType &ostype) -{ - switch (osabi_byte) - { - case ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break; - case ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break; - case ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break; - case ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break; - case ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break; - case ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break; - default: - ostype = llvm::Triple::OSType::UnknownOS; - } - return ostype != llvm::Triple::OSType::UnknownOS; -} - -size_t -ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); - - const size_t initial_count = specs.GetSize(); - - if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) - { - DataExtractor data; - data.SetData(data_sp); - elf::ELFHeader header; - if (header.Parse(data, &data_offset)) - { - if (data_sp) - { - ModuleSpec spec (file); - - const uint32_t sub_type = subTypeFromElfHeader(header); - spec.GetArchitecture().SetArchitecture(eArchTypeELF, - header.e_machine, - sub_type, - header.e_ident[EI_OSABI]); - - if (spec.GetArchitecture().IsValid()) - { - llvm::Triple::OSType ostype; - llvm::Triple::VendorType vendor; - llvm::Triple::OSType spec_ostype = spec.GetArchitecture ().GetTriple ().getOS (); - - if (log) - log->Printf ("ObjectFileELF::%s file '%s' module OSABI: %s", __FUNCTION__, file.GetPath ().c_str (), OSABIAsCString (header.e_ident[EI_OSABI])); - - // SetArchitecture should have set the vendor to unknown - vendor = spec.GetArchitecture ().GetTriple ().getVendor (); - assert(vendor == llvm::Triple::UnknownVendor); - - // - // Validate it is ok to remove GetOsFromOSABI - GetOsFromOSABI (header.e_ident[EI_OSABI], ostype); - assert(spec_ostype == ostype); - if (spec_ostype != llvm::Triple::OSType::UnknownOS) - { - if (log) - log->Printf ("ObjectFileELF::%s file '%s' set ELF module OS type from ELF header OSABI.", __FUNCTION__, file.GetPath ().c_str ()); - } - - // 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. - size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize; - if (section_header_end > data_sp->GetByteSize()) - { - data_sp = file.MemoryMapFileContentsIfLocal (file_offset, section_header_end); - data.SetData(data_sp); - } - - uint32_t gnu_debuglink_crc = 0; - std::string gnu_debuglink_file; - SectionHeaderColl section_headers; - lldb_private::UUID &uuid = spec.GetUUID(); - - using namespace std::placeholders; - const SetDataFunction set_data = std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3); - GetSectionHeaderInfo(section_headers, set_data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture ()); - - - llvm::Triple &spec_triple = spec.GetArchitecture ().GetTriple (); - - if (log) - log->Printf ("ObjectFileELF::%s file '%s' module set to triple: %s (architecture %s)", __FUNCTION__, file.GetPath ().c_str (), spec_triple.getTriple ().c_str (), spec.GetArchitecture ().GetArchitectureName ()); - - if (!uuid.IsValid()) - { - uint32_t core_notes_crc = 0; - - if (!gnu_debuglink_crc) - { - lldb_private::Timer scoped_timer (LLVM_PRETTY_FUNCTION, - "Calculating module crc32 %s with size %" PRIu64 " KiB", - file.GetLastPathComponent().AsCString(), - (file.GetByteSize()-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 = file.MemoryMapFileContentsIfLocal(file_offset, program_headers_end); - data.SetData(data_sp); - } - ProgramHeaderColl program_headers; - GetProgramHeaderInfo(program_headers, set_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 = file.MemoryMapFileContentsIfLocal(file_offset, segment_data_end); - 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 = file.MemoryMapFileContentsIfLocal (file_offset, SIZE_MAX); - data.SetData(data_sp); - gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize()); - } - } - 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)); - } - 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)); - } - } - - specs.Append(spec); +static bool GetOsFromOSABI(unsigned char osabi_byte, + llvm::Triple::OSType &ostype) { + switch (osabi_byte) { + case ELFOSABI_AIX: + ostype = llvm::Triple::OSType::AIX; + break; + case ELFOSABI_FREEBSD: + ostype = llvm::Triple::OSType::FreeBSD; + break; + case ELFOSABI_GNU: + ostype = llvm::Triple::OSType::Linux; + break; + case ELFOSABI_NETBSD: + ostype = llvm::Triple::OSType::NetBSD; + break; + case ELFOSABI_OPENBSD: + ostype = llvm::Triple::OSType::OpenBSD; + break; + case ELFOSABI_SOLARIS: + ostype = llvm::Triple::OSType::Solaris; + break; + default: + ostype = llvm::Triple::OSType::UnknownOS; + } + return ostype != llvm::Triple::OSType::UnknownOS; +} + +size_t ObjectFileELF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); + + const size_t initial_count = specs.GetSize(); + + if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + DataExtractor data; + data.SetData(data_sp); + elf::ELFHeader header; + if (header.Parse(data, &data_offset)) { + if (data_sp) { + ModuleSpec spec(file); + + const uint32_t sub_type = subTypeFromElfHeader(header); + spec.GetArchitecture().SetArchitecture( + eArchTypeELF, header.e_machine, sub_type, header.e_ident[EI_OSABI]); + + if (spec.GetArchitecture().IsValid()) { + llvm::Triple::OSType ostype; + llvm::Triple::VendorType vendor; + llvm::Triple::OSType spec_ostype = + spec.GetArchitecture().GetTriple().getOS(); + + if (log) + log->Printf("ObjectFileELF::%s file '%s' module OSABI: %s", + __FUNCTION__, file.GetPath().c_str(), + OSABIAsCString(header.e_ident[EI_OSABI])); + + // SetArchitecture should have set the vendor to unknown + vendor = spec.GetArchitecture().GetTriple().getVendor(); + assert(vendor == llvm::Triple::UnknownVendor); + + // + // Validate it is ok to remove GetOsFromOSABI + GetOsFromOSABI(header.e_ident[EI_OSABI], ostype); + assert(spec_ostype == ostype); + if (spec_ostype != llvm::Triple::OSType::UnknownOS) { + if (log) + log->Printf("ObjectFileELF::%s file '%s' set ELF module OS type " + "from ELF header OSABI.", + __FUNCTION__, file.GetPath().c_str()); + } + + // 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. + size_t section_header_end = + header.e_shoff + header.e_shnum * header.e_shentsize; + if (section_header_end > data_sp->GetByteSize()) { + data_sp = file.MemoryMapFileContentsIfLocal(file_offset, + section_header_end); + data.SetData(data_sp); + } + + uint32_t gnu_debuglink_crc = 0; + std::string gnu_debuglink_file; + SectionHeaderColl section_headers; + lldb_private::UUID &uuid = spec.GetUUID(); + + using namespace std::placeholders; + const SetDataFunction set_data = + std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3); + GetSectionHeaderInfo(section_headers, set_data, header, uuid, + gnu_debuglink_file, gnu_debuglink_crc, + spec.GetArchitecture()); + + llvm::Triple &spec_triple = spec.GetArchitecture().GetTriple(); + + if (log) + log->Printf("ObjectFileELF::%s file '%s' module set to triple: %s " + "(architecture %s)", + __FUNCTION__, file.GetPath().c_str(), + spec_triple.getTriple().c_str(), + spec.GetArchitecture().GetArchitectureName()); + + if (!uuid.IsValid()) { + uint32_t core_notes_crc = 0; + + if (!gnu_debuglink_crc) { + lldb_private::Timer scoped_timer( + LLVM_PRETTY_FUNCTION, + "Calculating module crc32 %s with size %" PRIu64 " KiB", + file.GetLastPathComponent().AsCString(), + (file.GetByteSize() - 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 = file.MemoryMapFileContentsIfLocal( + file_offset, program_headers_end); + data.SetData(data_sp); + } + ProgramHeaderColl program_headers; + GetProgramHeaderInfo(program_headers, set_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 = file.MemoryMapFileContentsIfLocal(file_offset, + segment_data_end); + 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 = + file.MemoryMapFileContentsIfLocal(file_offset, SIZE_MAX); + data.SetData(data_sp); + gnu_debuglink_crc = calc_gnu_debuglink_crc32( + data.GetDataStart(), data.GetByteSize()); + } } + 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)); + } 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)); + } + } + + specs.Append(spec); } + } } + } - return specs.GetSize() - initial_count; + return specs.GetSize() - initial_count; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -ObjectFileELF::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ObjectFileELF::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ObjectFileELF::GetPluginVersion() -{ - return m_plugin_version; -} +uint32_t ObjectFileELF::GetPluginVersion() { return m_plugin_version; } //------------------------------------------------------------------ // ObjectFile protocol //------------------------------------------------------------------ -ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - lldb::offset_t data_offset, - const FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) : - ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), - m_header(), - m_uuid(), - m_gnu_debuglink_file(), - m_gnu_debuglink_crc(0), - m_program_headers(), - m_section_headers(), - m_dynamic_symbols(), - m_filespec_ap(), - m_entry_point_address(), - m_arch_spec() -{ - if (file) - m_file = *file; - ::memset(&m_header, 0, sizeof(m_header)); -} - -ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp, - DataBufferSP& header_data_sp, - const lldb::ProcessSP &process_sp, - addr_t header_addr) : - ObjectFile(module_sp, process_sp, header_addr, header_data_sp), - m_header(), - m_uuid(), - m_gnu_debuglink_file(), - m_gnu_debuglink_crc(0), - m_program_headers(), - m_section_headers(), - m_dynamic_symbols(), - m_filespec_ap(), - m_entry_point_address(), - m_arch_spec() -{ - ::memset(&m_header, 0, sizeof(m_header)); -} - -ObjectFileELF::~ObjectFileELF() -{ -} - -bool -ObjectFileELF::IsExecutable() const -{ - return ((m_header.e_type & ET_EXEC) != 0) || (m_header.e_entry != 0); -} - -bool -ObjectFileELF::SetLoadAddress (Target &target, - lldb::addr_t value, - bool value_is_offset) -{ - ModuleSP module_sp = GetModule(); - if (module_sp) - { - size_t num_loaded_sections = 0; - SectionList *section_list = GetSectionList (); - if (section_list) - { - if (!value_is_offset) - { - bool found_offset = false; - for (size_t i = 0, 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) - return false; - } +ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, lldb::offset_t data_offset, + const FileSpec *file, lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_header(), m_uuid(), m_gnu_debuglink_file(), m_gnu_debuglink_crc(0), + m_program_headers(), m_section_headers(), m_dynamic_symbols(), + m_filespec_ap(), m_entry_point_address(), m_arch_spec() { + if (file) + m_file = *file; + ::memset(&m_header, 0, sizeof(m_header)); +} + +ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp, + DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, + addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_header(), m_uuid(), m_gnu_debuglink_file(), m_gnu_debuglink_crc(0), + m_program_headers(), m_section_headers(), m_dynamic_symbols(), + m_filespec_ap(), m_entry_point_address(), m_arch_spec() { + ::memset(&m_header, 0, sizeof(m_header)); +} + +ObjectFileELF::~ObjectFileELF() {} + +bool ObjectFileELF::IsExecutable() const { + return ((m_header.e_type & ET_EXEC) != 0) || (m_header.e_entry != 0); +} + +bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + if (!value_is_offset) { + bool found_offset = false; + for (size_t i = 0, count = GetProgramHeaderCount(); i < count; ++i) { + const elf::ELFProgramHeader *header = GetProgramHeaderByIndex(i); + if (header == nullptr) + continue; - 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. - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - if (section_sp && section_sp->Test(SHF_ALLOC)) - { - 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 - 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. - if (GetAddressByteSize() == 4) - load_addr &= 0xFFFFFFFF; - - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr)) - ++num_loaded_sections; - } - } - return num_loaded_sections > 0; + if (header->p_type != PT_LOAD || header->p_offset != 0) + continue; + + value = value - header->p_vaddr; + found_offset = true; + break; + } + if (!found_offset) + return false; + } + + 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. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && section_sp->Test(SHF_ALLOC)) { + 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 + 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. + if (GetAddressByteSize() == 4) + load_addr &= 0xFFFFFFFF; + + if (target.GetSectionLoadList().SetSectionLoadAddress(section_sp, + load_addr)) + ++num_loaded_sections; } + } + return num_loaded_sections > 0; } - return false; + } + return false; } -ByteOrder -ObjectFileELF::GetByteOrder() const -{ - if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) - return eByteOrderBig; - if (m_header.e_ident[EI_DATA] == ELFDATA2LSB) - return eByteOrderLittle; - return eByteOrderInvalid; -} - -uint32_t -ObjectFileELF::GetAddressByteSize() const -{ - return m_data.GetAddressByteSize(); -} - -AddressClass -ObjectFileELF::GetAddressClass (addr_t file_addr) -{ - Symtab* symtab = GetSymtab(); - if (!symtab) - return eAddressClassUnknown; - - // 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) - 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; - } +ByteOrder ObjectFileELF::GetByteOrder() const { + if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) + return eByteOrderBig; + if (m_header.e_ident[EI_DATA] == ELFDATA2LSB) + return eByteOrderLittle; + return eByteOrderInvalid; +} + +uint32_t ObjectFileELF::GetAddressByteSize() const { + return m_data.GetAddressByteSize(); +} + +AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) { + Symtab *symtab = GetSymtab(); + if (!symtab) + return eAddressClassUnknown; + + // 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) + 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; + } - // Move iterator to the address class entry preceding address - --ub; + // Move iterator to the address class entry preceding address + --ub; - return ub->second; + return ub->second; } -size_t -ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) -{ - return std::distance(m_section_headers.begin(), I) + 1u; +size_t ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I) { + return std::distance(m_section_headers.begin(), I) + 1u; } -size_t -ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const -{ - return std::distance(m_section_headers.begin(), I) + 1u; +size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const { + return std::distance(m_section_headers.begin(), I) + 1u; } -bool -ObjectFileELF::ParseHeader() -{ - lldb::offset_t offset = 0; - if (!m_header.Parse(m_data, &offset)) - return false; - - if (!IsInMemory()) - return true; - - // For in memory object files m_data might not contain the full object file. Try to load it - // until the end of the "Section header table" what is at the end of the ELF file. - addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize; - if (m_data.GetByteSize() < file_size) - { - ProcessSP process_sp (m_process_wp.lock()); - if (!process_sp) - return false; - - DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); - if (!data_sp) - return false; - m_data.SetData(data_sp, 0, file_size); - } +bool ObjectFileELF::ParseHeader() { + lldb::offset_t offset = 0; + if (!m_header.Parse(m_data, &offset)) + return false; + if (!IsInMemory()) return true; + + // For in memory object files m_data might not contain the full object file. + // Try to load it + // until the end of the "Section header table" what is at the end of the ELF + // file. + addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize; + if (m_data.GetByteSize() < file_size) { + ProcessSP process_sp(m_process_wp.lock()); + if (!process_sp) + return false; + + DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); + if (!data_sp) + return false; + m_data.SetData(data_sp, 0, file_size); + } + + return true; } -bool -ObjectFileELF::GetUUID(lldb_private::UUID* uuid) -{ - // Need to parse the section list to get the UUIDs, so make sure that's been done. - if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile) - return false; +bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { + // Need to parse the section list to get the UUIDs, so make sure that's been + // done. + if (!ParseSectionHeaders() && GetType() != ObjectFile::eTypeCoreFile) + return false; - if (m_uuid.IsValid()) - { - // We have the full build id uuid. - *uuid = m_uuid; - return true; - } - else if (GetType() == ObjectFile::eTypeCoreFile) - { - uint32_t core_notes_crc = 0; - - if (!ParseProgramHeaders()) - return false; - - 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 - // segments crc. - uint32_t uuidt[4] = { g_core_uuid_magic, core_notes_crc, 0, 0 }; - m_uuid.SetBytes (uuidt, sizeof(uuidt)); - } - } - else - { - if (!m_gnu_debuglink_crc) - m_gnu_debuglink_crc = 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)); - } - } + if (m_uuid.IsValid()) { + // We have the full build id uuid. + *uuid = m_uuid; + return true; + } else if (GetType() == ObjectFile::eTypeCoreFile) { + uint32_t core_notes_crc = 0; - if (m_uuid.IsValid()) - { - *uuid = m_uuid; - return true; - } + if (!ParseProgramHeaders()) + return false; + + 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 + // segments crc. + uint32_t uuidt[4] = {g_core_uuid_magic, core_notes_crc, 0, 0}; + m_uuid.SetBytes(uuidt, sizeof(uuidt)); + } + } else { + if (!m_gnu_debuglink_crc) + m_gnu_debuglink_crc = + 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)); + } + } + + if (m_uuid.IsValid()) { + *uuid = m_uuid; + return true; + } - return false; + return false; } -lldb_private::FileSpecList -ObjectFileELF::GetDebugSymbolFilePaths() -{ - FileSpecList file_spec_list; +lldb_private::FileSpecList ObjectFileELF::GetDebugSymbolFilePaths() { + FileSpecList file_spec_list; - if (!m_gnu_debuglink_file.empty()) - { - FileSpec file_spec (m_gnu_debuglink_file.c_str(), false); - file_spec_list.Append (file_spec); - } - return file_spec_list; + if (!m_gnu_debuglink_file.empty()) { + FileSpec file_spec(m_gnu_debuglink_file.c_str(), false); + file_spec_list.Append(file_spec); + } + return file_spec_list; } -uint32_t -ObjectFileELF::GetDependentModules(FileSpecList &files) -{ - size_t num_modules = ParseDependentModules(); - uint32_t num_specs = 0; +uint32_t ObjectFileELF::GetDependentModules(FileSpecList &files) { + size_t num_modules = ParseDependentModules(); + uint32_t num_specs = 0; - for (unsigned i = 0; i < num_modules; ++i) - { - if (files.AppendIfUnique(m_filespec_ap->GetFileSpecAtIndex(i))) - num_specs++; - } + for (unsigned i = 0; i < num_modules; ++i) { + if (files.AppendIfUnique(m_filespec_ap->GetFileSpecAtIndex(i))) + num_specs++; + } - return num_specs; + return num_specs; } -Address -ObjectFileELF::GetImageInfoAddress(Target *target) -{ - if (!ParseDynamicSymbols()) - return Address(); +Address ObjectFileELF::GetImageInfoAddress(Target *target) { + if (!ParseDynamicSymbols()) + return Address(); - SectionList *section_list = GetSectionList(); - if (!section_list) - return Address(); + SectionList *section_list = GetSectionList(); + 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); + // 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); - user_id_t dynsym_id = dynsym_section_sp->GetID(); - const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id); - if (!dynsym_hdr) - return Address(); + user_id_t dynsym_id = dynsym_section_sp->GetID(); + const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id); + if (!dynsym_hdr) + return Address(); - for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) - { - ELFDynamic &symbol = m_dynamic_symbols[i]; + for (size_t i = 0; i < m_dynamic_symbols.size(); ++i) { + 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. + 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) + return Address(); - 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) - return Address(); - - Error 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, false, error, addr)) - return addr; - } - if (symbol.d_tag == DT_MIPS_RLD_MAP_REL) - { - // DT_MIPS_RLD_MAP_REL tag stores the offset to the debug pointer, relative to the address of the tag. - uint64_t rel_offset; - rel_offset = target->ReadUnsignedIntegerFromMemory(dyn_base + offset, false, GetAddressByteSize(), UINT64_MAX, error); - if (error.Success() && rel_offset != UINT64_MAX) - { - Address addr; - addr_t debug_ptr_address = dyn_base + (offset - GetAddressByteSize()) + rel_offset; - addr.SetOffset (debug_ptr_address); - return addr; - } - } + Error 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, false, error, + addr)) + return addr; + } + if (symbol.d_tag == DT_MIPS_RLD_MAP_REL) { + // DT_MIPS_RLD_MAP_REL tag stores the offset to the debug pointer, + // relative to the address of the tag. + uint64_t rel_offset; + rel_offset = target->ReadUnsignedIntegerFromMemory( + dyn_base + offset, false, GetAddressByteSize(), UINT64_MAX, error); + if (error.Success() && rel_offset != UINT64_MAX) { + Address addr; + addr_t debug_ptr_address = + dyn_base + (offset - GetAddressByteSize()) + rel_offset; + addr.SetOffset(debug_ptr_address); + return addr; } + } } + } - return Address(); + return Address(); } -lldb_private::Address -ObjectFileELF::GetEntryPointAddress () -{ - if (m_entry_point_address.IsValid()) - return m_entry_point_address; +lldb_private::Address ObjectFileELF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; - if (!ParseHeader() || !IsExecutable()) - return m_entry_point_address; + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; - SectionList *section_list = GetSectionList(); - addr_t offset = m_header.e_entry; + SectionList *section_list = GetSectionList(); + addr_t offset = m_header.e_entry; - if (!section_list) - m_entry_point_address.SetOffset(offset); - else - m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); - return m_entry_point_address; + if (!section_list) + m_entry_point_address.SetOffset(offset); + else + m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); + return m_entry_point_address; } //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- -size_t -ObjectFileELF::ParseDependentModules() -{ - if (m_filespec_ap.get()) - return m_filespec_ap->GetSize(); +size_t ObjectFileELF::ParseDependentModules() { + if (m_filespec_ap.get()) + return m_filespec_ap->GetSize(); - m_filespec_ap.reset(new FileSpecList()); + m_filespec_ap.reset(new FileSpecList()); - if (!ParseSectionHeaders()) - return 0; + 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 + 1).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; + SectionList *section_list = GetSectionList(); + if (!section_list) + return 0; - if (symbol.d_tag != DT_NEEDED) - continue; + // Find the SHT_DYNAMIC section. + Section *dynsym = + section_list->FindSectionByType(eSectionTypeELFDynamicLinkInfo, true) + .get(); + if (!dynsym) + return 0; + assert(dynsym->GetObjectFile() == this); - 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)); - } + 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 + 1).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) + continue; + + 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)); } + } - return m_filespec_ap->GetSize(); + return m_filespec_ap->GetSize(); } //---------------------------------------------------------------------- // GetProgramHeaderInfo //---------------------------------------------------------------------- -size_t -ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, - const SetDataFunction &set_data, - const ELFHeader &header) -{ - // We have already parsed the program headers - if (!program_headers.empty()) - return program_headers.size(); - - // If there are no program headers to read we are done. - if (header.e_phnum == 0) - return 0; - - program_headers.resize(header.e_phnum); - if (program_headers.size() != header.e_phnum) - return 0; - - const size_t ph_size = header.e_phnum * header.e_phentsize; - const elf_off ph_offset = header.e_phoff; - DataExtractor data; - if (set_data(data, ph_offset, ph_size) != ph_size) - return 0; - - 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) - break; - } +size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, + const SetDataFunction &set_data, + const ELFHeader &header) { + // We have already parsed the program headers + if (!program_headers.empty()) + return program_headers.size(); - if (idx < program_headers.size()) - program_headers.resize(idx); + // If there are no program headers to read we are done. + if (header.e_phnum == 0) + return 0; - return program_headers.size(); + program_headers.resize(header.e_phnum); + if (program_headers.size() != header.e_phnum) + return 0; + + const size_t ph_size = header.e_phnum * header.e_phentsize; + const elf_off ph_offset = header.e_phoff; + DataExtractor data; + if (set_data(data, ph_offset, ph_size) != ph_size) + return 0; + + 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) + break; + } + if (idx < program_headers.size()) + program_headers.resize(idx); + + return program_headers.size(); } //---------------------------------------------------------------------- // ParseProgramHeaders //---------------------------------------------------------------------- -size_t -ObjectFileELF::ParseProgramHeaders() -{ - using namespace std::placeholders; - return GetProgramHeaderInfo(m_program_headers, - std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, _3), - m_header); +size_t ObjectFileELF::ParseProgramHeaders() { + using namespace std::placeholders; + return GetProgramHeaderInfo( + m_program_headers, + std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, + _3), + m_header); } lldb_private::Error -ObjectFileELF::RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); - Error error; +ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, + lldb_private::ArchSpec &arch_spec, + lldb_private::UUID &uuid) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); + Error error; + + lldb::offset_t offset = 0; + + while (true) { + // Parse the note header. If this fails, bail out. + const lldb::offset_t note_offset = offset; + ELFNote note = ELFNote(); + if (!note.Parse(data, &offset)) { + // We're done. + return error; + } + + if (log) + log->Printf("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, + __FUNCTION__, note.n_name.c_str(), note.n_type); + + // Process FreeBSD ELF notes. + if ((note.n_name == LLDB_NT_OWNER_FREEBSD) && + (note.n_type == LLDB_NT_FREEBSD_ABI_TAG) && + (note.n_descsz == LLDB_NT_FREEBSD_ABI_SIZE)) { + // Pull out the min version info. + uint32_t version_info; + if (data.GetU32(&offset, &version_info, 1) == nullptr) { + error.SetErrorString("failed to read FreeBSD ABI note payload"); + return error; + } + + // Convert the version info into a major/minor number. + const uint32_t version_major = version_info / 100000; + const uint32_t version_minor = (version_info / 1000) % 100; + + char os_name[32]; + snprintf(os_name, sizeof(os_name), "freebsd%" PRIu32 ".%" PRIu32, + version_major, version_minor); + + // Set the elf OS version to FreeBSD. Also clear the vendor. + arch_spec.GetTriple().setOSName(os_name); + arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); + + if (log) + log->Printf("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 + ".%" PRIu32, + __FUNCTION__, version_major, version_minor, + static_cast<uint32_t>(version_info % 1000)); + } + // Process GNU ELF notes. + else if (note.n_name == LLDB_NT_OWNER_GNU) { + switch (note.n_type) { + case LLDB_NT_GNU_ABI_TAG: + if (note.n_descsz == LLDB_NT_GNU_ABI_SIZE) { + // Pull out the min OS version supporting the ABI. + uint32_t version_info[4]; + if (data.GetU32(&offset, &version_info[0], note.n_descsz / 4) == + nullptr) { + error.SetErrorString("failed to read GNU ABI note payload"); + return error; + } - lldb::offset_t offset = 0; + // Set the OS per the OS field. + switch (version_info[0]) { + case LLDB_NT_GNU_ABI_OS_LINUX: + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + arch_spec.GetTriple().setVendor( + llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf( + "ObjectFileELF::%s detected Linux, min version %" PRIu32 + ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); + // FIXME we have the minimal version number, we could be propagating + // that. version_info[1] = OS Major, version_info[2] = OS Minor, + // version_info[3] = Revision. + break; + case LLDB_NT_GNU_ABI_OS_HURD: + arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); + arch_spec.GetTriple().setVendor( + llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf("ObjectFileELF::%s detected Hurd (unsupported), min " + "version %" PRIu32 ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); + break; + case LLDB_NT_GNU_ABI_OS_SOLARIS: + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Solaris); + arch_spec.GetTriple().setVendor( + llvm::Triple::VendorType::UnknownVendor); + if (log) + log->Printf( + "ObjectFileELF::%s detected Solaris, min version %" PRIu32 + ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[1], version_info[2], + version_info[3]); + break; + default: + if (log) + log->Printf( + "ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 + ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, + __FUNCTION__, version_info[0], version_info[1], + version_info[2], version_info[3]); + break; + } + } + break; + + case LLDB_NT_GNU_BUILD_ID_TAG: + // 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) { + error.SetErrorString("failed to read GNU_BUILD_ID note payload"); + return error; + } - while (true) - { - // Parse the note header. If this fails, bail out. - const lldb::offset_t note_offset = offset; - ELFNote note = ELFNote(); - if (!note.Parse(data, &offset)) - { - // We're done. + // Save the build id as the UUID for the module. + uuid.SetBytes(uuidbuf, note.n_descsz); + } + } + break; + } + } + // Process NetBSD ELF notes. + else if ((note.n_name == LLDB_NT_OWNER_NETBSD) && + (note.n_type == LLDB_NT_NETBSD_ABI_TAG) && + (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) { + // Pull out the min version info. + uint32_t version_info; + if (data.GetU32(&offset, &version_info, 1) == nullptr) { + error.SetErrorString("failed to read NetBSD ABI note payload"); + return error; + } + + // Set the elf OS version to NetBSD. Also clear the vendor. + arch_spec.GetTriple().setOS(llvm::Triple::OSType::NetBSD); + arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor); + + if (log) + log->Printf( + "ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, + __FUNCTION__, version_info); + } + // Process CSR kalimba notes + else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) && + (note.n_name == LLDB_NT_OWNER_CSR)) { + arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); + 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. + if (note.n_descsz) { + const char *cstr = + data.GetCStr(&offset, llvm::alignTo(note.n_descsz, 4)); + (void)cstr; + } + } else if (note.n_name == LLDB_NT_OWNER_ANDROID) { + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + arch_spec.GetTriple().setEnvironment( + llvm::Triple::EnvironmentType::Android); + } else if (note.n_name == LLDB_NT_OWNER_LINUX) { + // This is sometimes found in core files and usually contains extended + // 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 + // [ 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). + if (note.n_type == NT_FILE) { + uint64_t count = data.GetAddress(&offset); + const char *cstr; + data.GetAddress(&offset); // Skip page size + offset += count * 3 * + data.GetAddressByteSize(); // Skip all start/end/file_ofs + for (size_t i = 0; i < count; ++i) { + cstr = data.GetCStr(&offset); + if (cstr == nullptr) { + error.SetErrorStringWithFormat("ObjectFileELF::%s trying to read " + "at an offset after the end " + "(GetCStr returned nullptr)", + __FUNCTION__); return error; + } + llvm::StringRef path(cstr); + if (path.startswith("/lib/x86_64-linux-gnu") || + path.startswith("/lib/i386-linux-gnu")) { + arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); + break; + } } + } + } - if (log) - log->Printf ("ObjectFileELF::%s parsing note name='%s', type=%" PRIu32, __FUNCTION__, note.n_name.c_str (), note.n_type); - - // Process FreeBSD ELF notes. - if ((note.n_name == LLDB_NT_OWNER_FREEBSD) && - (note.n_type == LLDB_NT_FREEBSD_ABI_TAG) && - (note.n_descsz == LLDB_NT_FREEBSD_ABI_SIZE)) - { - // Pull out the min version info. - uint32_t version_info; - if (data.GetU32 (&offset, &version_info, 1) == nullptr) - { - error.SetErrorString ("failed to read FreeBSD ABI note payload"); - return error; - } + // 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(); + } - // Convert the version info into a major/minor number. - const uint32_t version_major = version_info / 100000; - const uint32_t version_minor = (version_info / 1000) % 100; + return error; +} - char os_name[32]; - snprintf (os_name, sizeof (os_name), "freebsd%" PRIu32 ".%" PRIu32, version_major, version_minor); +void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, + ArchSpec &arch_spec) { + lldb::offset_t Offset = 0; - // Set the elf OS version to FreeBSD. Also clear the vendor. - arch_spec.GetTriple ().setOSName (os_name); - arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + uint8_t FormatVersion = data.GetU8(&Offset); + if (FormatVersion != llvm::ARMBuildAttrs::Format_Version) + return; - if (log) - log->Printf ("ObjectFileELF::%s detected FreeBSD %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_major, version_minor, static_cast<uint32_t> (version_info % 1000)); - } - // Process GNU ELF notes. - else if (note.n_name == LLDB_NT_OWNER_GNU) - { - switch (note.n_type) - { - case LLDB_NT_GNU_ABI_TAG: - if (note.n_descsz == LLDB_NT_GNU_ABI_SIZE) - { - // Pull out the min OS version supporting the ABI. - uint32_t version_info[4]; - if (data.GetU32 (&offset, &version_info[0], note.n_descsz / 4) == nullptr) - { - error.SetErrorString ("failed to read GNU ABI note payload"); - return error; - } - - // Set the OS per the OS field. - switch (version_info[0]) - { - case LLDB_NT_GNU_ABI_OS_LINUX: - arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Linux); - arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf ("ObjectFileELF::%s detected Linux, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); - // FIXME we have the minimal version number, we could be propagating that. version_info[1] = OS Major, version_info[2] = OS Minor, version_info[3] = Revision. - break; - case LLDB_NT_GNU_ABI_OS_HURD: - arch_spec.GetTriple ().setOS (llvm::Triple::OSType::UnknownOS); - arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf ("ObjectFileELF::%s detected Hurd (unsupported), min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); - break; - case LLDB_NT_GNU_ABI_OS_SOLARIS: - arch_spec.GetTriple ().setOS (llvm::Triple::OSType::Solaris); - arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); - if (log) - log->Printf ("ObjectFileELF::%s detected Solaris, min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[1], version_info[2], version_info[3]); - break; - default: - if (log) - log->Printf ("ObjectFileELF::%s unrecognized OS in note, id %" PRIu32 ", min version %" PRIu32 ".%" PRIu32 ".%" PRIu32, __FUNCTION__, version_info[0], version_info[1], version_info[2], version_info[3]); - break; - } - } - break; - - case LLDB_NT_GNU_BUILD_ID_TAG: - // 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) - { - 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; - } - } - // Process NetBSD ELF notes. - else if ((note.n_name == LLDB_NT_OWNER_NETBSD) && - (note.n_type == LLDB_NT_NETBSD_ABI_TAG) && - (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) - { - // Pull out the min version info. - uint32_t version_info; - if (data.GetU32 (&offset, &version_info, 1) == nullptr) - { - error.SetErrorString ("failed to read NetBSD ABI note payload"); - return error; - } + Offset = Offset + sizeof(uint32_t); // Section Length + llvm::StringRef VendorName = data.GetCStr(&Offset); - // Set the elf OS version to NetBSD. Also clear the vendor. - arch_spec.GetTriple ().setOS (llvm::Triple::OSType::NetBSD); - arch_spec.GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor); + if (VendorName != "aeabi") + return; - if (log) - log->Printf ("ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32, __FUNCTION__, version_info); - } - // Process CSR kalimba notes - else if ((note.n_type == LLDB_NT_GNU_ABI_TAG) && - (note.n_name == LLDB_NT_OWNER_CSR)) - { - arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS); - 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. - if(note.n_descsz) - { - const char *cstr = data.GetCStr(&offset, llvm::alignTo (note.n_descsz, 4)); - (void)cstr; - } - } - else if (note.n_name == LLDB_NT_OWNER_ANDROID) - { - arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); - arch_spec.GetTriple().setEnvironment(llvm::Triple::EnvironmentType::Android); - } - else if (note.n_name == LLDB_NT_OWNER_LINUX) - { - // This is sometimes found in core files and usually contains extended 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 - // [ 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). - if (note.n_type == NT_FILE) - { - uint64_t count = data.GetAddress(&offset); - const char *cstr; - data.GetAddress(&offset); // Skip page size - offset += count * 3 * data.GetAddressByteSize(); // Skip all start/end/file_ofs - for (size_t i=0; i<count; ++i) - { - cstr = data.GetCStr(&offset); - if(cstr == nullptr) - { - error.SetErrorStringWithFormat("ObjectFileELF::%s trying to read at an offset after the end (GetCStr returned nullptr)", __FUNCTION__); - return error; - } - llvm::StringRef path(cstr); - if (path.startswith("/lib/x86_64-linux-gnu") || path.startswith("/lib/i386-linux-gnu")) - { - arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux); - break; - } - } - } - } + if (arch_spec.GetTriple().getEnvironment() == + llvm::Triple::UnknownEnvironment) + arch_spec.GetTriple().setEnvironment(llvm::Triple::EABI); - // 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(); - } + while (Offset < length) { + uint8_t Tag = data.GetU8(&Offset); + uint32_t Size = data.GetU32(&Offset); - return error; -} + if (Tag != llvm::ARMBuildAttrs::File || Size == 0) + continue; -void -ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, ArchSpec &arch_spec) -{ - lldb::offset_t Offset = 0; + while (Offset < length) { + uint64_t Tag = data.GetULEB128(&Offset); + switch (Tag) { + default: + if (Tag < 32) + data.GetULEB128(&Offset); + else if (Tag % 2 == 0) + data.GetULEB128(&Offset); + else + data.GetCStr(&Offset); - uint8_t FormatVersion = data.GetU8(&Offset); - if (FormatVersion != llvm::ARMBuildAttrs::Format_Version) - return; + break; - Offset = Offset + sizeof(uint32_t); // Section Length - llvm::StringRef VendorName = data.GetCStr(&Offset); + case llvm::ARMBuildAttrs::CPU_raw_name: + case llvm::ARMBuildAttrs::CPU_name: + data.GetCStr(&Offset); - if (VendorName != "aeabi") - return; + break; - if (arch_spec.GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment) - arch_spec.GetTriple().setEnvironment(llvm::Triple::EABI); + case llvm::ARMBuildAttrs::ABI_VFP_args: { + uint64_t VFPArgs = data.GetULEB128(&Offset); - while (Offset < length) - { - uint8_t Tag = data.GetU8(&Offset); - uint32_t Size = data.GetU32(&Offset); + if (VFPArgs == llvm::ARMBuildAttrs::BaseAAPCS) { + if (arch_spec.GetTriple().getEnvironment() == + llvm::Triple::UnknownEnvironment || + arch_spec.GetTriple().getEnvironment() == llvm::Triple::EABIHF) + arch_spec.GetTriple().setEnvironment(llvm::Triple::EABI); - if (Tag != llvm::ARMBuildAttrs::File || Size == 0) - continue; + arch_spec.SetFlags(ArchSpec::eARM_abi_soft_float); + } else if (VFPArgs == llvm::ARMBuildAttrs::HardFPAAPCS) { + if (arch_spec.GetTriple().getEnvironment() == + llvm::Triple::UnknownEnvironment || + arch_spec.GetTriple().getEnvironment() == llvm::Triple::EABI) + arch_spec.GetTriple().setEnvironment(llvm::Triple::EABIHF); - while (Offset < length) - { - uint64_t Tag = data.GetULEB128(&Offset); - switch (Tag) - { - default: - if (Tag < 32) - data.GetULEB128(&Offset); - else if (Tag % 2 == 0) - data.GetULEB128(&Offset); - else - data.GetCStr(&Offset); - - break; - - case llvm::ARMBuildAttrs::CPU_raw_name: - case llvm::ARMBuildAttrs::CPU_name: - data.GetCStr(&Offset); - - break; - - case llvm::ARMBuildAttrs::ABI_VFP_args: - { - uint64_t VFPArgs = data.GetULEB128(&Offset); - - if (VFPArgs == llvm::ARMBuildAttrs::BaseAAPCS) - { - if (arch_spec.GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment || - arch_spec.GetTriple().getEnvironment() == llvm::Triple::EABIHF) - arch_spec.GetTriple().setEnvironment(llvm::Triple::EABI); - - arch_spec.SetFlags(ArchSpec::eARM_abi_soft_float); - } - else if (VFPArgs == llvm::ARMBuildAttrs::HardFPAAPCS) - { - if (arch_spec.GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment || - arch_spec.GetTriple().getEnvironment() == llvm::Triple::EABI) - arch_spec.GetTriple().setEnvironment(llvm::Triple::EABIHF); - - arch_spec.SetFlags(ArchSpec::eARM_abi_hard_float); - } - - break; - } - } + arch_spec.SetFlags(ArchSpec::eARM_abi_hard_float); } + + break; + } + } } + } } //---------------------------------------------------------------------- // GetSectionHeaderInfo //---------------------------------------------------------------------- -size_t -ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, - const SetDataFunction &set_data, - const elf::ELFHeader &header, - lldb_private::UUID &uuid, - std::string &gnu_debuglink_file, - uint32_t &gnu_debuglink_crc, - ArchSpec &arch_spec) -{ - // Don't reparse the section headers if we already did that. - if (!section_headers.empty()) - return section_headers.size(); - - // Only initialize the arch_spec to okay defaults if they're not already set. - // We'll refine this with note data as we parse the notes. - if (arch_spec.GetTriple ().getOS () == llvm::Triple::OSType::UnknownOS) - { - llvm::Triple::OSType ostype; - llvm::Triple::OSType spec_ostype; - 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 - GetOsFromOSABI (header.e_ident[EI_OSABI], ostype); - spec_ostype = arch_spec.GetTriple ().getOS (); - assert(spec_ostype == ostype); - } - - if (arch_spec.GetMachine() == llvm::Triple::mips || arch_spec.GetMachine() == llvm::Triple::mipsel - || arch_spec.GetMachine() == llvm::Triple::mips64 || arch_spec.GetMachine() == llvm::Triple::mips64el) - { - switch (header.e_flags & llvm::ELF::EF_MIPS_ARCH_ASE) - { - case llvm::ELF::EF_MIPS_MICROMIPS: - arch_spec.SetFlags (ArchSpec::eMIPSAse_micromips); - break; - case llvm::ELF::EF_MIPS_ARCH_ASE_M16: - arch_spec.SetFlags (ArchSpec::eMIPSAse_mips16); - break; - case llvm::ELF::EF_MIPS_ARCH_ASE_MDMX: - arch_spec.SetFlags (ArchSpec::eMIPSAse_mdmx); - break; - default: - break; - } +size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, + const SetDataFunction &set_data, + const elf::ELFHeader &header, + lldb_private::UUID &uuid, + std::string &gnu_debuglink_file, + uint32_t &gnu_debuglink_crc, + ArchSpec &arch_spec) { + // Don't reparse the section headers if we already did that. + if (!section_headers.empty()) + return section_headers.size(); + + // Only initialize the arch_spec to okay defaults if they're not already set. + // We'll refine this with note data as we parse the notes. + if (arch_spec.GetTriple().getOS() == llvm::Triple::OSType::UnknownOS) { + llvm::Triple::OSType ostype; + llvm::Triple::OSType spec_ostype; + 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 + GetOsFromOSABI(header.e_ident[EI_OSABI], ostype); + spec_ostype = arch_spec.GetTriple().getOS(); + assert(spec_ostype == ostype); + } + + if (arch_spec.GetMachine() == llvm::Triple::mips || + arch_spec.GetMachine() == llvm::Triple::mipsel || + arch_spec.GetMachine() == llvm::Triple::mips64 || + arch_spec.GetMachine() == llvm::Triple::mips64el) { + switch (header.e_flags & llvm::ELF::EF_MIPS_ARCH_ASE) { + case llvm::ELF::EF_MIPS_MICROMIPS: + arch_spec.SetFlags(ArchSpec::eMIPSAse_micromips); + break; + case llvm::ELF::EF_MIPS_ARCH_ASE_M16: + arch_spec.SetFlags(ArchSpec::eMIPSAse_mips16); + break; + case llvm::ELF::EF_MIPS_ARCH_ASE_MDMX: + arch_spec.SetFlags(ArchSpec::eMIPSAse_mdmx); + break; + default: + break; } + } - if (arch_spec.GetMachine() == llvm::Triple::arm || - arch_spec.GetMachine() == llvm::Triple::thumb) - { - if (header.e_flags & llvm::ELF::EF_ARM_SOFT_FLOAT) - arch_spec.SetFlags (ArchSpec::eARM_abi_soft_float); - else if (header.e_flags & llvm::ELF::EF_ARM_VFP_FLOAT) - arch_spec.SetFlags (ArchSpec::eARM_abi_hard_float); - } + if (arch_spec.GetMachine() == llvm::Triple::arm || + arch_spec.GetMachine() == llvm::Triple::thumb) { + if (header.e_flags & llvm::ELF::EF_ARM_SOFT_FLOAT) + arch_spec.SetFlags(ArchSpec::eARM_abi_soft_float); + else if (header.e_flags & llvm::ELF::EF_ARM_VFP_FLOAT) + arch_spec.SetFlags(ArchSpec::eARM_abi_hard_float); + } - // If there are no section headers we are done. - if (header.e_shnum == 0) - return 0; + // If there are no section headers we are done. + if (header.e_shnum == 0) + return 0; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES)); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES)); - section_headers.resize(header.e_shnum); - if (section_headers.size() != header.e_shnum) - return 0; + section_headers.resize(header.e_shnum); + if (section_headers.size() != header.e_shnum) + return 0; - const size_t sh_size = header.e_shnum * header.e_shentsize; - const elf_off sh_offset = header.e_shoff; - DataExtractor sh_data; - if (set_data (sh_data, sh_offset, sh_size) != sh_size) - return 0; + const size_t sh_size = header.e_shnum * header.e_shentsize; + const elf_off sh_offset = header.e_shoff; + DataExtractor sh_data; + if (set_data(sh_data, sh_offset, sh_size) != sh_size) + return 0; - 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) + 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) + break; + } + if (idx < section_headers.size()) + section_headers.resize(idx); + + const unsigned strtab_idx = header.e_shstrndx; + if (strtab_idx && strtab_idx < section_headers.size()) { + const ELFSectionHeaderInfo &sheader = section_headers[strtab_idx]; + const size_t byte_size = sheader.sh_size; + const Elf64_Off offset = sheader.sh_offset; + lldb_private::DataExtractor shstr_data; + + if (set_data(shstr_data, offset, byte_size) == byte_size) { + for (SectionHeaderCollIter I = section_headers.begin(); + I != section_headers.end(); ++I) { + static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink"); + const ELFSectionHeaderInfo &sheader = *I; + const uint64_t section_size = + sheader.sh_type == SHT_NOBITS ? 0 : sheader.sh_size; + ConstString name(shstr_data.PeekCStr(I->sh_name)); + + I->section_name = name; + + if (arch_spec.IsMIPS()) { + uint32_t arch_flags = arch_spec.GetFlags(); + DataExtractor data; + if (sheader.sh_type == SHT_MIPS_ABIFLAGS) { + + if (section_size && (set_data(data, sheader.sh_offset, + section_size) == section_size)) { + // MIPS ASE Mask is at offset 12 in MIPS.abiflags section + lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0 + arch_flags |= data.GetU32(&offset); + + // The floating point ABI is at offset 7 + offset = 7; + switch (data.GetU8(&offset)) { + case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_ANY; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_DOUBLE; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_SINGLE; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_OLD_64; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_XX; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_64: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_64; + break; + case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A: + arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_64A; + break; + } + } + } + // Settings appropriate ArchSpec ABI Flags + switch (header.e_flags & llvm::ELF::EF_MIPS_ABI) { + case llvm::ELF::EF_MIPS_ABI_O32: + arch_flags |= lldb_private::ArchSpec::eMIPSABI_O32; break; - } - if (idx < section_headers.size()) - section_headers.resize(idx); - - const unsigned strtab_idx = header.e_shstrndx; - if (strtab_idx && strtab_idx < section_headers.size()) - { - const ELFSectionHeaderInfo &sheader = section_headers[strtab_idx]; - const size_t byte_size = sheader.sh_size; - const Elf64_Off offset = sheader.sh_offset; - lldb_private::DataExtractor shstr_data; - - if (set_data (shstr_data, offset, byte_size) == byte_size) - { - for (SectionHeaderCollIter I = section_headers.begin(); - I != section_headers.end(); ++I) - { - static ConstString g_sect_name_gnu_debuglink (".gnu_debuglink"); - const ELFSectionHeaderInfo &sheader = *I; - const uint64_t section_size = sheader.sh_type == SHT_NOBITS ? 0 : sheader.sh_size; - ConstString name(shstr_data.PeekCStr(I->sh_name)); - - I->section_name = name; - - if (arch_spec.IsMIPS()) - { - uint32_t arch_flags = arch_spec.GetFlags (); - DataExtractor data; - if (sheader.sh_type == SHT_MIPS_ABIFLAGS) - { - - if (section_size && (set_data (data, sheader.sh_offset, section_size) == section_size)) - { - // MIPS ASE Mask is at offset 12 in MIPS.abiflags section - lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0 - arch_flags |= data.GetU32 (&offset); - - // The floating point ABI is at offset 7 - offset = 7; - switch (data.GetU8 (&offset)) - { - case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_ANY; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_DOUBLE; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_SINGLE; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64 : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_OLD_64; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_XX; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_64 : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_64; - break; - case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A : - arch_flags |= lldb_private::ArchSpec::eMIPS_ABI_FP_64A; - break; - } - } - } - // Settings appropriate ArchSpec ABI Flags - switch(header.e_flags & llvm::ELF::EF_MIPS_ABI) - { - case llvm::ELF::EF_MIPS_ABI_O32: - arch_flags |= lldb_private::ArchSpec::eMIPSABI_O32; - break; - case EF_MIPS_ABI_O64: - arch_flags |= lldb_private::ArchSpec::eMIPSABI_O64; - break; - case EF_MIPS_ABI_EABI32: - arch_flags |= lldb_private::ArchSpec::eMIPSABI_EABI32; - break; - case EF_MIPS_ABI_EABI64: - arch_flags |= lldb_private::ArchSpec::eMIPSABI_EABI64; - break; - default: - // ABI Mask doesn't cover N32 and N64 ABI. - if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64) - arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64; - else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2) - arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32; - break; - } - arch_spec.SetFlags (arch_flags); - } + case EF_MIPS_ABI_O64: + arch_flags |= lldb_private::ArchSpec::eMIPSABI_O64; + break; + case EF_MIPS_ABI_EABI32: + arch_flags |= lldb_private::ArchSpec::eMIPSABI_EABI32; + break; + case EF_MIPS_ABI_EABI64: + arch_flags |= lldb_private::ArchSpec::eMIPSABI_EABI64; + break; + default: + // ABI Mask doesn't cover N32 and N64 ABI. + if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64) + arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64; + else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2) + arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32; + break; + } + arch_spec.SetFlags(arch_flags); + } - if (arch_spec.GetMachine() == llvm::Triple::arm || arch_spec.GetMachine() == llvm::Triple::thumb) - { - DataExtractor data; + if (arch_spec.GetMachine() == llvm::Triple::arm || + arch_spec.GetMachine() == llvm::Triple::thumb) { + DataExtractor data; - if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 && - set_data(data, sheader.sh_offset, section_size) == section_size) - ParseARMAttributes(data, section_size, arch_spec); - } + if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 && + set_data(data, sheader.sh_offset, section_size) == section_size) + ParseARMAttributes(data, section_size, arch_spec); + } - if (name == g_sect_name_gnu_debuglink) - { - DataExtractor data; - if (section_size && (set_data (data, sheader.sh_offset, section_size) == section_size)) - { - lldb::offset_t gnu_debuglink_offset = 0; - gnu_debuglink_file = data.GetCStr (&gnu_debuglink_offset); - gnu_debuglink_offset = llvm::alignTo (gnu_debuglink_offset, 4); - data.GetU32 (&gnu_debuglink_offset, &gnu_debuglink_crc, 1); - } - } + if (name == g_sect_name_gnu_debuglink) { + DataExtractor data; + if (section_size && (set_data(data, sheader.sh_offset, + section_size) == section_size)) { + lldb::offset_t gnu_debuglink_offset = 0; + gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset); + gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4); + data.GetU32(&gnu_debuglink_offset, &gnu_debuglink_crc, 1); + } + } - // Process ELF note section entries. - bool is_note_header = (sheader.sh_type == SHT_NOTE); - - // The section header ".note.android.ident" is stored as a - // PROGBITS type header but it is actually a note header. - static ConstString g_sect_name_android_ident (".note.android.ident"); - if (!is_note_header && name == g_sect_name_android_ident) - is_note_header = true; - - if (is_note_header) - { - // Allow notes to refine module info. - DataExtractor data; - if (section_size && (set_data (data, sheader.sh_offset, section_size) == section_size)) - { - Error error = RefineModuleDetailsFromNote (data, arch_spec, uuid); - if (error.Fail ()) - { - if (log) - log->Printf ("ObjectFileELF::%s ELF note processing failed: %s", __FUNCTION__, error.AsCString ()); - } - } - } + // Process ELF note section entries. + bool is_note_header = (sheader.sh_type == SHT_NOTE); + + // The section header ".note.android.ident" is stored as a + // PROGBITS type header but it is actually a note header. + static ConstString g_sect_name_android_ident(".note.android.ident"); + if (!is_note_header && name == g_sect_name_android_ident) + is_note_header = true; + + if (is_note_header) { + // Allow notes to refine module info. + DataExtractor data; + if (section_size && (set_data(data, sheader.sh_offset, + section_size) == section_size)) { + Error error = RefineModuleDetailsFromNote(data, arch_spec, uuid); + if (error.Fail()) { + if (log) + log->Printf("ObjectFileELF::%s ELF note processing failed: %s", + __FUNCTION__, error.AsCString()); } + } + } + } - // Make any unknown triple components to be unspecified unknowns. - if (arch_spec.GetTriple().getVendor() == llvm::Triple::UnknownVendor) - arch_spec.GetTriple().setVendorName (llvm::StringRef()); - if (arch_spec.GetTriple().getOS() == llvm::Triple::UnknownOS) - arch_spec.GetTriple().setOSName (llvm::StringRef()); + // Make any unknown triple components to be unspecified unknowns. + if (arch_spec.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_spec.GetTriple().setVendorName(llvm::StringRef()); + if (arch_spec.GetTriple().getOS() == llvm::Triple::UnknownOS) + arch_spec.GetTriple().setOSName(llvm::StringRef()); - return section_headers.size(); - } + return section_headers.size(); } + } - section_headers.clear(); - return 0; + section_headers.clear(); + return 0; } -size_t -ObjectFileELF::GetProgramHeaderCount() -{ - return ParseProgramHeaders(); -} +size_t ObjectFileELF::GetProgramHeaderCount() { return ParseProgramHeaders(); } const elf::ELFProgramHeader * -ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id) -{ - if (!id || !ParseProgramHeaders()) - return NULL; +ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id) { + if (!id || !ParseProgramHeaders()) + return NULL; - if (--id < m_program_headers.size()) - return &m_program_headers[id]; + if (--id < m_program_headers.size()) + return &m_program_headers[id]; - return NULL; + 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); +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); } std::string -ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const -{ - size_t pos = symbol_name.find('@'); - return symbol_name.substr(0, pos).str(); +ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { + size_t pos = symbol_name.find('@'); + return symbol_name.substr(0, pos).str(); } //---------------------------------------------------------------------- // ParseSectionHeaders //---------------------------------------------------------------------- -size_t -ObjectFileELF::ParseSectionHeaders() -{ - using namespace std::placeholders; +size_t ObjectFileELF::ParseSectionHeaders() { + using namespace std::placeholders; - return GetSectionHeaderInfo(m_section_headers, - std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, _3), - m_header, - m_uuid, - m_gnu_debuglink_file, - m_gnu_debuglink_crc, - m_arch_spec); + return GetSectionHeaderInfo( + m_section_headers, + std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, + _3), + m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec); } -lldb::offset_t -ObjectFileELF::SetData(const lldb_private::DataExtractor &src, lldb_private::DataExtractor &dst, lldb::offset_t offset, lldb::offset_t length) -{ - return dst.SetData(src, offset, length); +lldb::offset_t ObjectFileELF::SetData(const lldb_private::DataExtractor &src, + lldb_private::DataExtractor &dst, + lldb::offset_t offset, + lldb::offset_t length) { + return dst.SetData(src, offset, length); } lldb::offset_t -ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, lldb::offset_t offset, lldb::offset_t length) -{ - if (offset + length <= m_data.GetByteSize()) - return dst.SetData(m_data, offset, length); - - const auto process_sp = m_process_wp.lock(); - if (process_sp != nullptr) - { - addr_t file_size = offset + length; - - DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); - if (!data_sp) - return false; - m_data.SetData(data_sp, 0, file_size); - } - +ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, + lldb::offset_t offset, + lldb::offset_t length) { + if (offset + length <= m_data.GetByteSize()) return dst.SetData(m_data, offset, length); + + const auto process_sp = m_process_wp.lock(); + if (process_sp != nullptr) { + addr_t file_size = offset + length; + + DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); + if (!data_sp) + return false; + m_data.SetData(data_sp, 0, file_size); + } + + return dst.SetData(m_data, offset, length); } const ObjectFileELF::ELFSectionHeaderInfo * -ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) -{ - if (!id || !ParseSectionHeaders()) - return NULL; +ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id) { + if (!id || !ParseSectionHeaders()) + return NULL; - if (--id < m_section_headers.size()) - return &m_section_headers[id]; + if (--id < m_section_headers.size()) + return &m_section_headers[id]; - return NULL; + return NULL; } -lldb::user_id_t -ObjectFileELF::GetSectionIndexByName(const char* name) -{ - if (!name || !name[0] || !ParseSectionHeaders()) - return 0; - for (size_t i = 1; i < m_section_headers.size(); ++i) - if (m_section_headers[i].section_name == ConstString(name)) - return i; +lldb::user_id_t ObjectFileELF::GetSectionIndexByName(const char *name) { + if (!name || !name[0] || !ParseSectionHeaders()) return 0; + for (size_t i = 1; i < m_section_headers.size(); ++i) + if (m_section_headers[i].section_name == ConstString(name)) + return i; + 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 : 0) | - ((header.sh_flags & SHF_WRITE) ? ePermissionsWritable : 0) | - ((header.sh_flags & SHF_EXECINSTR) ? ePermissionsExecutable : 0); - 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; - } - - 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); - } - - 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); - } - } +void ObjectFileELF::CreateSections(SectionList &unified_section_list) { + if (!m_sections_ap.get() && ParseSectionHeaders()) { + m_sections_ap.reset(new SectionList()); - 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); - } - } - } - else - { - unified_section_list = *m_sections_ap; + 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 : 0) | + ((header.sh_flags & SHF_WRITE) ? ePermissionsWritable : 0) | + ((header.sh_flags & SHF_EXECINSTR) ? ePermissionsExecutable : 0); + 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; + } + + 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); + } + + 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); + } + } + + 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); } + } + } else { + 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 +// 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 // objcopy then the mapping symbols are also prefixed. -static char -FindArmAarch64MappingSymbol(const char* symbol_name) -{ - if (!symbol_name) - return '\0'; - - const char* dollar_pos = ::strchr(symbol_name, '$'); - if (!dollar_pos || dollar_pos[1] == '\0') - return '\0'; +static char FindArmAarch64MappingSymbol(const char *symbol_name) { + if (!symbol_name) + return '\0'; - if (dollar_pos[2] == '\0' || dollar_pos[2] == '.') - return dollar_pos[1]; + const char *dollar_pos = ::strchr(symbol_name, '$'); + if (!dollar_pos || dollar_pos[1] == '\0') return '\0'; + + if (dollar_pos[2] == '\0' || dollar_pos[2] == '.') + return dollar_pos[1]; + return '\0'; } -#define STO_MIPS_ISA (3 << 6) -#define STO_MICROMIPS (2 << 6) -#define IS_MICROMIPS(ST_OTHER) (((ST_OTHER) & STO_MIPS_ISA) == STO_MICROMIPS) +#define STO_MIPS_ISA (3 << 6) +#define STO_MICROMIPS (2 << 6) +#define IS_MICROMIPS(ST_OTHER) (((ST_OTHER)&STO_MIPS_ISA) == STO_MICROMIPS) // private -unsigned -ObjectFileELF::ParseSymbols (Symtab *symtab, - user_id_t start_id, - SectionList *section_list, - const size_t num_symbols, - const DataExtractor &symtab_data, - const DataExtractor &strtab_data) -{ - ELFSymbol symbol; - lldb::offset_t offset = 0; +unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, + SectionList *section_list, + const size_t num_symbols, + const DataExtractor &symtab_data, + const DataExtractor &strtab_data) { + ELFSymbol symbol; + lldb::offset_t offset = 0; + + static ConstString text_section_name(".text"); + static ConstString init_section_name(".init"); + static ConstString fini_section_name(".fini"); + static ConstString ctors_section_name(".ctors"); + static ConstString dtors_section_name(".dtors"); + + static ConstString data_section_name(".data"); + static ConstString rodata_section_name(".rodata"); + static ConstString rodata1_section_name(".rodata1"); + static ConstString data2_section_name(".data1"); + static ConstString bss_section_name(".bss"); + 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. + ConstString file_extension = m_file.GetFileNameExtension(); + bool skip_oatdata_oatexec = file_extension == ConstString("oat") || + file_extension == ConstString("odex"); + + ArchSpec arch; + GetArchitecture(arch); + 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 + 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) + break; + + const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); + if (!symbol_name) + symbol_name = ""; + + // No need to add non-section symbols that have no names + if (symbol.getType() != STT_SECTION && + (symbol_name == nullptr || symbol_name[0] == '\0')) + continue; + + // Skipping oatdata and oatexec sections if it is requested. See details + // 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; + + switch (section_idx) { + case SHN_ABS: + symbol_type = eSymbolTypeAbsolute; + break; + case SHN_UNDEF: + symbol_type = eSymbolTypeUndefined; + break; + default: + symbol_section_sp = section_list->GetSectionAtIndex(section_idx); + break; + } - static ConstString text_section_name(".text"); - static ConstString init_section_name(".init"); - static ConstString fini_section_name(".fini"); - static ConstString ctors_section_name(".ctors"); - static ConstString dtors_section_name(".dtors"); - - static ConstString data_section_name(".data"); - static ConstString rodata_section_name(".rodata"); - static ConstString rodata1_section_name(".rodata1"); - static ConstString data2_section_name(".data1"); - static ConstString bss_section_name(".bss"); - 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. - ConstString file_extension = m_file.GetFileNameExtension(); - bool skip_oatdata_oatexec = file_extension == ConstString("oat") || file_extension == ConstString("odex"); - - ArchSpec arch; - GetArchitecture(arch); - 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 - 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) - break; + // If a symbol is undefined do not process it further even if it has a STT + // type + if (symbol_type != eSymbolTypeUndefined) { + switch (symbol.getType()) { + default: + case STT_NOTYPE: + // The symbol's type is not specified. + break; - const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); - if (!symbol_name) - symbol_name = ""; + case STT_OBJECT: + // The symbol is associated with a data object, such as a variable, + // an array, etc. + symbol_type = eSymbolTypeData; + break; - // No need to add non-section symbols that have no names - if (symbol.getType() != STT_SECTION && - (symbol_name == nullptr || symbol_name[0] == '\0')) - continue; + case STT_FUNC: + // The symbol is associated with a function or other executable code. + symbol_type = eSymbolTypeCode; + break; - // Skipping oatdata and oatexec sections if it is requested. See details 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; + 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. + break; - SectionSP symbol_section_sp; - SymbolType symbol_type = eSymbolTypeInvalid; - Elf64_Half section_idx = symbol.st_shndx; + 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 + // 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; + break; - switch (section_idx) - { - case SHN_ABS: - symbol_type = eSymbolTypeAbsolute; - break; - case SHN_UNDEF: - symbol_type = eSymbolTypeUndefined; - break; - default: - symbol_section_sp = section_list->GetSectionAtIndex(section_idx); - break; + case STT_GNU_IFUNC: + // The symbol is associated with an indirect function. The actual + // function will be resolved if it is referenced. + symbol_type = eSymbolTypeResolver; + break; + } + } + + if (symbol_type == eSymbolTypeInvalid && symbol.getType() != STT_SECTION) { + if (symbol_section_sp) { + const ConstString §_name = symbol_section_sp->GetName(); + if (sect_name == text_section_name || sect_name == init_section_name || + sect_name == fini_section_name || sect_name == ctors_section_name || + sect_name == dtors_section_name) { + symbol_type = eSymbolTypeCode; + } else if (sect_name == data_section_name || + sect_name == data2_section_name || + sect_name == rodata_section_name || + sect_name == rodata1_section_name || + sect_name == bss_section_name) { + symbol_type = eSymbolTypeData; } - - // If a symbol is undefined do not process it further even if it has a STT type - if (symbol_type != eSymbolTypeUndefined) - { - switch (symbol.getType()) - { - default: - case STT_NOTYPE: - // The symbol's type is not specified. - break; - - case STT_OBJECT: - // The symbol is associated with a data object, such as a variable, - // an array, etc. - symbol_type = eSymbolTypeData; - break; - - case STT_FUNC: - // The symbol is associated with a function or other executable code. - symbol_type = eSymbolTypeCode; - break; - - 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. - 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 - // 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; - break; - - case STT_GNU_IFUNC: - // The symbol is associated with an indirect function. The actual - // function will be resolved if it is referenced. - symbol_type = eSymbolTypeResolver; - break; - } - } - - if (symbol_type == eSymbolTypeInvalid && symbol.getType() != STT_SECTION) - { - if (symbol_section_sp) - { - const ConstString §_name = symbol_section_sp->GetName(); - if (sect_name == text_section_name || - sect_name == init_section_name || - sect_name == fini_section_name || - sect_name == ctors_section_name || - sect_name == dtors_section_name) - { - symbol_type = eSymbolTypeCode; - } - else if (sect_name == data_section_name || - sect_name == data2_section_name || - sect_name == rodata_section_name || - sect_name == rodata1_section_name || - sect_name == bss_section_name) - { - symbol_type = eSymbolTypeData; - } + } + } + + int64_t symbol_value_offset = 0; + uint32_t additional_flags = 0; + + if (arch.IsValid()) { + if (arch.GetMachine() == llvm::Triple::arm) { + if (symbol.getBinding() == STB_LOCAL) { + char mapping_symbol = FindArmAarch64MappingSymbol(symbol_name); + if (symbol_type == eSymbolTypeCode) { + switch (mapping_symbol) { + case 'a': + // $a[.<any>]* - marks an ARM instruction sequence + m_address_class_map[symbol.st_value] = eAddressClassCode; + 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; + break; + case 'd': + // $d[.<any>]* - marks a data item sequence (e.g. lit pool) + m_address_class_map[symbol.st_value] = eAddressClassData; + break; } + } + if (mapping_symbol) + continue; } - - int64_t symbol_value_offset = 0; - uint32_t additional_flags = 0; - - if (arch.IsValid()) - { - if (arch.GetMachine() == llvm::Triple::arm) - { - if (symbol.getBinding() == STB_LOCAL) - { - char mapping_symbol = FindArmAarch64MappingSymbol(symbol_name); - if (symbol_type == eSymbolTypeCode) - { - switch (mapping_symbol) - { - case 'a': - // $a[.<any>]* - marks an ARM instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; - 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; - break; - case 'd': - // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; - break; - } - } - if (mapping_symbol) - continue; - } - } - else if (arch.GetMachine() == llvm::Triple::aarch64) - { - if (symbol.getBinding() == STB_LOCAL) - { - char mapping_symbol = FindArmAarch64MappingSymbol(symbol_name); - if (symbol_type == eSymbolTypeCode) - { - switch (mapping_symbol) - { - case 'x': - // $x[.<any>]* - marks an A64 instruction sequence - m_address_class_map[symbol.st_value] = eAddressClassCode; - break; - case 'd': - // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = eAddressClassData; - break; - } - } - if (mapping_symbol) - continue; - } - } - - 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. - symbol_value_offset = -1; - m_address_class_map[symbol.st_value^1] = eAddressClassCodeAlternateISA; - } - else - { - // This address is ARM - m_address_class_map[symbol.st_value] = eAddressClassCode; - } - } - } - - /* - * MIPS: - * The bit #0 of an address is used for ISA mode (1 for microMIPS, 0 for MIPS). - * This allows processor to switch between microMIPS and MIPS without any need - * for special mode-control register. However, apart from .debug_line, none of - * the ELF/DWARF sections set the ISA bit (for symbol or section). Use st_other - * flag to check whether the symbol is microMIPS and then set the address class - * accordingly. - */ - const llvm::Triple::ArchType llvm_arch = arch.GetMachine(); - if (llvm_arch == llvm::Triple::mips || llvm_arch == llvm::Triple::mipsel - || llvm_arch == llvm::Triple::mips64 || llvm_arch == llvm::Triple::mips64el) - { - if (IS_MICROMIPS(symbol.st_other)) - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; - else if ((symbol.st_value & 1) && (symbol_type == eSymbolTypeCode)) - { - symbol.st_value = symbol.st_value & (~1ull); - m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; - } - else - { - if (symbol_type == eSymbolTypeCode) - m_address_class_map[symbol.st_value] = eAddressClassCode; - else if (symbol_type == eSymbolTypeData) - m_address_class_map[symbol.st_value] = eAddressClassData; - else - m_address_class_map[symbol.st_value] = eAddressClassUnknown; - } + } else if (arch.GetMachine() == llvm::Triple::aarch64) { + if (symbol.getBinding() == STB_LOCAL) { + char mapping_symbol = FindArmAarch64MappingSymbol(symbol_name); + if (symbol_type == eSymbolTypeCode) { + switch (mapping_symbol) { + case 'x': + // $x[.<any>]* - marks an A64 instruction sequence + m_address_class_map[symbol.st_value] = eAddressClassCode; + break; + case 'd': + // $d[.<any>]* - marks a data item sequence (e.g. lit pool) + m_address_class_map[symbol.st_value] = eAddressClassData; + break; } + } + if (mapping_symbol) + continue; } - - // symbol_value_offset may contain 0 for ARM symbols or -1 for THUMB 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 && 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. - ConstString fake_section_name(std::string(".absolute.") + symbol_name); - symbol_section_sp = std::make_shared<Section>(module_sp, - this, - SHN_ABS, - fake_section_name, - eSectionTypeAbsoluteAddress, - symbol_value, - symbol.st_size, - 0, 0, 0, - SHF_ALLOC); - - module_section_list->AddSection(symbol_section_sp); - section_list->AddSection(symbol_section_sp); + } + + 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. + symbol_value_offset = -1; + m_address_class_map[symbol.st_value ^ 1] = + eAddressClassCodeAlternateISA; + } else { + // This address is ARM + m_address_class_map[symbol.st_value] = eAddressClassCode; + } } - - if (symbol_section_sp && CalculateType() != ObjectFile::Type::eTypeObjectFile) - symbol_value -= symbol_section_sp->GetFileAddress(); - - if (symbol_section_sp && module_section_list && module_section_list != section_list) - { - const ConstString §_name = symbol_section_sp->GetName(); - auto section_it = section_name_to_section.find(sect_name.GetCString()); - if (section_it == section_name_to_section.end()) - section_it = section_name_to_section.emplace( - sect_name.GetCString(), - module_section_list->FindSectionByName (sect_name)).first; - if (section_it->second && section_it->second->GetFileSize()) - symbol_section_sp = section_it->second; + } + + /* + * MIPS: + * The bit #0 of an address is used for ISA mode (1 for microMIPS, 0 for + * MIPS). + * This allows processor to switch between microMIPS and MIPS without any + * need + * for special mode-control register. However, apart from .debug_line, + * none of + * the ELF/DWARF sections set the ISA bit (for symbol or section). Use + * st_other + * flag to check whether the symbol is microMIPS and then set the address + * class + * accordingly. + */ + const llvm::Triple::ArchType llvm_arch = arch.GetMachine(); + if (llvm_arch == llvm::Triple::mips || + llvm_arch == llvm::Triple::mipsel || + llvm_arch == llvm::Triple::mips64 || + llvm_arch == llvm::Triple::mips64el) { + if (IS_MICROMIPS(symbol.st_other)) + m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + else if ((symbol.st_value & 1) && (symbol_type == eSymbolTypeCode)) { + symbol.st_value = symbol.st_value & (~1ull); + m_address_class_map[symbol.st_value] = eAddressClassCodeAlternateISA; + } else { + if (symbol_type == eSymbolTypeCode) + m_address_class_map[symbol.st_value] = eAddressClassCode; + else if (symbol_type == eSymbolTypeData) + m_address_class_map[symbol.st_value] = eAddressClassData; + else + m_address_class_map[symbol.st_value] = eAddressClassUnknown; } + } + } + + // symbol_value_offset may contain 0 for ARM symbols or -1 for THUMB + // 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 && + 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. + ConstString fake_section_name(std::string(".absolute.") + symbol_name); + symbol_section_sp = + std::make_shared<Section>(module_sp, this, SHN_ABS, fake_section_name, + eSectionTypeAbsoluteAddress, symbol_value, + symbol.st_size, 0, 0, 0, SHF_ALLOC); + + module_section_list->AddSection(symbol_section_sp); + section_list->AddSection(symbol_section_sp); + } + + if (symbol_section_sp && + CalculateType() != ObjectFile::Type::eTypeObjectFile) + symbol_value -= symbol_section_sp->GetFileAddress(); + + if (symbol_section_sp && module_section_list && + module_section_list != section_list) { + const ConstString §_name = symbol_section_sp->GetName(); + auto section_it = section_name_to_section.find(sect_name.GetCString()); + if (section_it == section_name_to_section.end()) + section_it = + section_name_to_section + .emplace(sect_name.GetCString(), + module_section_list->FindSectionByName(sect_name)) + .first; + if (section_it->second && section_it->second->GetFileSize()) + symbol_section_sp = section_it->second; + } + + bool is_global = symbol.getBinding() == STB_GLOBAL; + uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags; + bool is_mangled = (symbol_name[0] == '_' && symbol_name[1] == 'Z'); + + llvm::StringRef symbol_ref(symbol_name); + + // Symbol names may contain @VERSION suffixes. Find those and strip them + // temporarily. + size_t version_pos = symbol_ref.find('@'); + bool has_suffix = version_pos != llvm::StringRef::npos; + llvm::StringRef symbol_bare = symbol_ref.substr(0, version_pos); + Mangled mangled(ConstString(symbol_bare), is_mangled); + + // Now append the suffix back to mangled and unmangled names. Only do it if + // the + // demangling was successful (string is not empty). + if (has_suffix) { + llvm::StringRef suffix = symbol_ref.substr(version_pos); + + llvm::StringRef mangled_name = mangled.GetMangledName().GetStringRef(); + if (!mangled_name.empty()) + mangled.SetMangledName(ConstString((mangled_name + suffix).str())); + + ConstString demangled = + mangled.GetDemangledName(lldb::eLanguageTypeUnknown); + llvm::StringRef demangled_name = demangled.GetStringRef(); + if (!demangled_name.empty()) + mangled.SetDemangledName(ConstString((demangled_name + suffix).str())); + } + + // 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. + bool symbol_size_valid = + symbol.st_size != 0 || symbol.getType() != STT_FUNC; + + Symbol dc_symbol( + i + start_id, // ID is the original symbol table index. + mangled, + symbol_type, // Type of this symbol + is_global, // Is this globally visible? + false, // Is this symbol debug info? + false, // Is this symbol a trampoline? + false, // Is this symbol artificial? + AddressRange(symbol_section_sp, // Section in which this symbol is + // defined or null. + symbol_value, // Offset in section or symbol value. + symbol.st_size), // Size in bytes of this symbol. + symbol_size_valid, // Symbol size is valid + has_suffix, // Contains linker annotations? + flags); // Symbol flags. + symtab->AddSymbol(dc_symbol); + } + return i; +} + +unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, + user_id_t start_id, + 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. + ObjectFileELF *obj_file_elf = + static_cast<ObjectFileELF *>(symtab->GetObjectFile()); + return obj_file_elf->ParseSymbolTable(symbol_table, start_id, symtab); + } + + // Get section list for this object file. + SectionList *section_list = m_sections_ap.get(); + if (!section_list) + return 0; - bool is_global = symbol.getBinding() == STB_GLOBAL; - uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags; - bool is_mangled = (symbol_name[0] == '_' && symbol_name[1] == 'Z'); - - llvm::StringRef symbol_ref(symbol_name); - - // Symbol names may contain @VERSION suffixes. Find those and strip them temporarily. - size_t version_pos = symbol_ref.find('@'); - bool has_suffix = version_pos != llvm::StringRef::npos; - llvm::StringRef symbol_bare = symbol_ref.substr(0, version_pos); - Mangled mangled(ConstString(symbol_bare), is_mangled); + user_id_t symtab_id = symtab->GetID(); + const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id); + assert(symtab_hdr->sh_type == SHT_SYMTAB || + symtab_hdr->sh_type == SHT_DYNSYM); - // Now append the suffix back to mangled and unmangled names. Only do it if the - // demangling was successful (string is not empty). - if (has_suffix) - { - llvm::StringRef suffix = symbol_ref.substr(version_pos); + // 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; + Section *strtab = section_list->FindSectionByID(strtab_id).get(); - llvm::StringRef mangled_name = mangled.GetMangledName().GetStringRef(); - if (! mangled_name.empty()) - mangled.SetMangledName( ConstString((mangled_name + suffix).str()) ); + if (symtab && strtab) { + assert(symtab->GetObjectFile() == this); + assert(strtab->GetObjectFile() == this); - ConstString demangled = mangled.GetDemangledName(lldb::eLanguageTypeUnknown); - llvm::StringRef demangled_name = demangled.GetStringRef(); - if (!demangled_name.empty()) - mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) ); - } + DataExtractor symtab_data; + DataExtractor strtab_data; + if (ReadSectionData(symtab, symtab_data) && + ReadSectionData(strtab, strtab_data)) { + size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize; - // 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. - bool symbol_size_valid = symbol.st_size != 0 || symbol.getType() != STT_FUNC; - - Symbol dc_symbol( - i + start_id, // ID is the original symbol table index. - mangled, - symbol_type, // Type of this symbol - is_global, // Is this globally visible? - false, // Is this symbol debug info? - false, // Is this symbol a trampoline? - false, // Is this symbol artificial? - AddressRange( - symbol_section_sp, // Section in which this symbol is defined or null. - symbol_value, // Offset in section or symbol value. - symbol.st_size), // Size in bytes of this symbol. - symbol_size_valid, // Symbol size is valid - has_suffix, // Contains linker annotations? - flags); // Symbol flags. - symtab->AddSymbol(dc_symbol); + return ParseSymbols(symbol_table, start_id, section_list, num_symbols, + symtab_data, strtab_data); } - return i; -} + } -unsigned -ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, - user_id_t start_id, - 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. - ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile()); - return obj_file_elf->ParseSymbolTable (symbol_table, start_id, symtab); - } + return 0; +} - // Get section list for this object file. - SectionList *section_list = m_sections_ap.get(); - if (!section_list) - return 0; - - user_id_t symtab_id = symtab->GetID(); - const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id); - assert(symtab_hdr->sh_type == SHT_SYMTAB || - 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; - Section *strtab = section_list->FindSectionByID(strtab_id).get(); - - if (symtab && strtab) - { - assert (symtab->GetObjectFile() == this); - assert (strtab->GetObjectFile() == this); - - DataExtractor symtab_data; - DataExtractor strtab_data; - if (ReadSectionData(symtab, symtab_data) && - ReadSectionData(strtab, strtab_data)) - { - size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize; - - return ParseSymbols(symbol_table, start_id, section_list, - num_symbols, symtab_data, strtab_data); - } - } +size_t ObjectFileELF::ParseDynamicSymbols() { + if (m_dynamic_symbols.size()) + return m_dynamic_symbols.size(); + SectionList *section_list = GetSectionList(); + if (!section_list) return 0; -} -size_t -ObjectFileELF::ParseDynamicSymbols() -{ - if (m_dynamic_symbols.size()) - return m_dynamic_symbols.size(); - - 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); - // 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; - 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)) - break; + while (cursor < section_size) { + if (!symbol.Parse(dynsym_data, &cursor)) + break; - m_dynamic_symbols.push_back(symbol); - } + m_dynamic_symbols.push_back(symbol); } + } - return m_dynamic_symbols.size(); + return m_dynamic_symbols.size(); } -const ELFDynamic * -ObjectFileELF::FindDynamicSymbol(unsigned tag) -{ - if (!ParseDynamicSymbols()) - return NULL; +const ELFDynamic *ObjectFileELF::FindDynamicSymbol(unsigned tag) { + if (!ParseDynamicSymbols()) + return NULL; - DynamicSymbolCollIter I = m_dynamic_symbols.begin(); - DynamicSymbolCollIter E = m_dynamic_symbols.end(); - for ( ; I != E; ++I) - { - ELFDynamic *symbol = &*I; + 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; - } + if (symbol->d_tag == tag) + return symbol; + } - return NULL; + return NULL; } -unsigned -ObjectFileELF::PLTRelocationType() -{ - // DT_PLTREL - // This member specifies the type of relocation entry to which the - // procedure linkage table refers. The d_val member holds DT_REL or - // DT_RELA, as appropriate. All relocations in a procedure linkage table - // must use the same relocation. - const ELFDynamic *symbol = FindDynamicSymbol(DT_PLTREL); - - if (symbol) - return symbol->d_val; +unsigned ObjectFileELF::PLTRelocationType() { + // DT_PLTREL + // This member specifies the type of relocation entry to which the + // procedure linkage table refers. The d_val member holds DT_REL or + // DT_RELA, as appropriate. All relocations in a procedure linkage table + // must use the same relocation. + const ELFDynamic *symbol = FindDynamicSymbol(DT_PLTREL); - return 0; + if (symbol) + return symbol->d_val; + + 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 +// 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. - elf_xword plt_entsize = plt_hdr->sh_addralign ? - llvm::alignTo (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize; - - // Some linkers e.g ld for arm, fill plt_hdr->sh_entsize field incorrectly. - // PLT entries relocation code in general requires multiple instruction and - // should be greater than 4 bytes in most cases. Try to guess correct size 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. - if (plt_hdr->sh_addralign) - plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / (num_relocations + 1) * plt_hdr->sh_addralign; - else - plt_entsize = plt_hdr->sh_size / (num_relocations + 1); - } - - elf_xword plt_offset = plt_hdr->sh_size - num_relocations * plt_entsize; - - return std::make_pair(plt_entsize, plt_offset); -} - -static unsigned -ParsePLTRelocations(Symtab *symbol_table, - user_id_t start_id, - unsigned rel_type, - const ELFHeader *hdr, - const ELFSectionHeader *rel_hdr, - const ELFSectionHeader *plt_hdr, - const ELFSectionHeader *sym_hdr, - const lldb::SectionSP &plt_section_sp, - DataExtractor &rel_data, - DataExtractor &symtab_data, - DataExtractor &strtab_data) -{ - ELFRelocation rel(rel_type); - ELFSymbol symbol; - lldb::offset_t offset = 0; - - uint64_t plt_offset, plt_entsize; - std::tie(plt_entsize, plt_offset) = GetPltEntrySizeAndOffset(rel_hdr, plt_hdr); - const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; - - typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); - reloc_info_fn reloc_type; - reloc_info_fn reloc_symbol; - - if (hdr->Is32Bit()) - { - reloc_type = ELFRelocation::RelocType32; - reloc_symbol = ELFRelocation::RelocSymbol32; - } +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. + elf_xword plt_entsize = + plt_hdr->sh_addralign + ? llvm::alignTo(plt_hdr->sh_entsize, plt_hdr->sh_addralign) + : plt_hdr->sh_entsize; + + // Some linkers e.g ld for arm, fill plt_hdr->sh_entsize field incorrectly. + // PLT entries relocation code in general requires multiple instruction and + // should be greater than 4 bytes in most cases. Try to guess correct size + // 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. + if (plt_hdr->sh_addralign) + plt_entsize = plt_hdr->sh_size / plt_hdr->sh_addralign / + (num_relocations + 1) * plt_hdr->sh_addralign; else - { - reloc_type = ELFRelocation::RelocType64; - reloc_symbol = ELFRelocation::RelocSymbol64; - } - - unsigned slot_type = hdr->GetRelocationJumpSlotType(); - unsigned i; - for (i = 0; i < num_relocations; ++i) - { - if (rel.Parse(rel_data, &offset) == false) - break; - - if (reloc_type(rel) != slot_type) - continue; - - lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize; - if (!symbol.Parse(symtab_data, &symbol_offset)) - break; - - const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); - bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false; - uint64_t plt_index = plt_offset + i * plt_entsize; - - Symbol jump_symbol( - i + start_id, // Symbol table index - symbol_name, // symbol name. - is_mangled, // is the symbol name mangled? - eSymbolTypeTrampoline, // Type of this symbol - false, // Is this globally visible? - false, // Is this symbol debug info? - true, // Is this symbol a trampoline? - true, // Is this symbol artificial? - plt_section_sp, // Section in which this symbol is defined or null. - plt_index, // Offset in section or symbol value. - plt_entsize, // Size in bytes of this symbol. - true, // Size is valid - false, // Contains linker annotations? - 0); // Symbol flags. - - symbol_table->AddSymbol(jump_symbol); - } - - return i; + plt_entsize = plt_hdr->sh_size / (num_relocations + 1); + } + + elf_xword plt_offset = plt_hdr->sh_size - num_relocations * plt_entsize; + + return std::make_pair(plt_entsize, plt_offset); +} + +static unsigned ParsePLTRelocations( + Symtab *symbol_table, user_id_t start_id, unsigned rel_type, + const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, + const ELFSectionHeader *plt_hdr, const ELFSectionHeader *sym_hdr, + const lldb::SectionSP &plt_section_sp, DataExtractor &rel_data, + DataExtractor &symtab_data, DataExtractor &strtab_data) { + ELFRelocation rel(rel_type); + ELFSymbol symbol; + lldb::offset_t offset = 0; + + uint64_t plt_offset, plt_entsize; + std::tie(plt_entsize, plt_offset) = + GetPltEntrySizeAndOffset(rel_hdr, plt_hdr); + const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; + + typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); + reloc_info_fn reloc_type; + reloc_info_fn reloc_symbol; + + if (hdr->Is32Bit()) { + reloc_type = ELFRelocation::RelocType32; + reloc_symbol = ELFRelocation::RelocSymbol32; + } else { + reloc_type = ELFRelocation::RelocType64; + reloc_symbol = ELFRelocation::RelocSymbol64; + } + + unsigned slot_type = hdr->GetRelocationJumpSlotType(); + unsigned i; + for (i = 0; i < num_relocations; ++i) { + if (rel.Parse(rel_data, &offset) == false) + break; + + if (reloc_type(rel) != slot_type) + continue; + + lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize; + if (!symbol.Parse(symtab_data, &symbol_offset)) + break; + + const char *symbol_name = strtab_data.PeekCStr(symbol.st_name); + bool is_mangled = + symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false; + uint64_t plt_index = plt_offset + i * plt_entsize; + + Symbol jump_symbol( + i + start_id, // Symbol table index + symbol_name, // symbol name. + is_mangled, // is the symbol name mangled? + eSymbolTypeTrampoline, // Type of this symbol + false, // Is this globally visible? + false, // Is this symbol debug info? + true, // Is this symbol a trampoline? + true, // Is this symbol artificial? + plt_section_sp, // Section in which this symbol is defined or null. + plt_index, // Offset in section or symbol value. + plt_entsize, // Size in bytes of this symbol. + true, // Size is valid + false, // Contains linker annotations? + 0); // Symbol flags. + + symbol_table->AddSymbol(jump_symbol); + } + + return i; } unsigned -ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, - user_id_t start_id, +ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table, user_id_t start_id, const ELFSectionHeaderInfo *rel_hdr, - user_id_t rel_id) -{ - assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); - - // The link field points to the associated symbol table. - user_id_t symtab_id = rel_hdr->sh_link; - - // If the link field doesn't point to the appropriate symbol name table then - // try to find it by name as some compiler don't fill in the link fields. - if (!symtab_id) - symtab_id = GetSectionIndexByName(".dynsym"); + user_id_t rel_id) { + assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); - // Get PLT section. We cannot use rel_hdr->sh_info, since current linkers - // point that to the .got.plt or .got section instead of .plt. - user_id_t plt_id = GetSectionIndexByName(".plt"); + // The link field points to the associated symbol table. + user_id_t symtab_id = rel_hdr->sh_link; - if (!symtab_id || !plt_id) - return 0; + // If the link field doesn't point to the appropriate symbol name table then + // try to find it by name as some compiler don't fill in the link fields. + if (!symtab_id) + symtab_id = GetSectionIndexByName(".dynsym"); - // Section ID's are ones based; - symtab_id++; - plt_id++; + // Get PLT section. We cannot use rel_hdr->sh_info, since current linkers + // point that to the .got.plt or .got section instead of .plt. + user_id_t plt_id = GetSectionIndexByName(".plt"); - const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id); - if (!plt_hdr) - return 0; + if (!symtab_id || !plt_id) + return 0; - const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id); - if (!sym_hdr) - return 0; + // Section ID's are ones based; + symtab_id++; + plt_id++; - SectionList *section_list = m_sections_ap.get(); - if (!section_list) - return 0; + const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id); + if (!plt_hdr) + return 0; - Section *rel_section = section_list->FindSectionByID(rel_id).get(); - if (!rel_section) - return 0; + const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id); + if (!sym_hdr) + return 0; - SectionSP plt_section_sp (section_list->FindSectionByID(plt_id)); - if (!plt_section_sp) - return 0; + SectionList *section_list = m_sections_ap.get(); + if (!section_list) + return 0; - Section *symtab = section_list->FindSectionByID(symtab_id).get(); - if (!symtab) - return 0; + Section *rel_section = section_list->FindSectionByID(rel_id).get(); + if (!rel_section) + return 0; - // sh_link points to associated string table. - Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get(); - if (!strtab) - return 0; + SectionSP plt_section_sp(section_list->FindSectionByID(plt_id)); + if (!plt_section_sp) + return 0; - DataExtractor rel_data; - if (!ReadSectionData(rel_section, rel_data)) - return 0; + Section *symtab = section_list->FindSectionByID(symtab_id).get(); + if (!symtab) + return 0; - DataExtractor symtab_data; - if (!ReadSectionData(symtab, symtab_data)) - return 0; + // sh_link points to associated string table. + Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get(); + if (!strtab) + return 0; - DataExtractor strtab_data; - if (!ReadSectionData(strtab, strtab_data)) - return 0; - - unsigned rel_type = PLTRelocationType(); - if (!rel_type) - return 0; - - return ParsePLTRelocations (symbol_table, - start_id, - rel_type, - &m_header, - rel_hdr, - plt_hdr, - sym_hdr, - plt_section_sp, - rel_data, - symtab_data, - strtab_data); -} + DataExtractor rel_data; + if (!ReadSectionData(rel_section, rel_data)) + return 0; -unsigned -ObjectFileELF::RelocateSection(Symtab* symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, - const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, - DataExtractor &rel_data, DataExtractor &symtab_data, - DataExtractor &debug_data, Section* rel_section) -{ - ELFRelocation rel(rel_hdr->sh_type); - lldb::addr_t offset = 0; - const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; - typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); - reloc_info_fn reloc_type; - reloc_info_fn reloc_symbol; - - if (hdr->Is32Bit()) - { - reloc_type = ELFRelocation::RelocType32; - reloc_symbol = ELFRelocation::RelocSymbol32; - } - else - { - reloc_type = ELFRelocation::RelocType64; - reloc_symbol = ELFRelocation::RelocSymbol64; - } + DataExtractor symtab_data; + if (!ReadSectionData(symtab, symtab_data)) + return 0; - for (unsigned i = 0; i < num_relocations; ++i) - { - if (rel.Parse(rel_data, &offset) == false) - break; + DataExtractor strtab_data; + if (!ReadSectionData(strtab, strtab_data)) + return 0; - Symbol* symbol = NULL; + unsigned rel_type = PLTRelocationType(); + if (!rel_type) + return 0; - if (hdr->Is32Bit()) - { - switch (reloc_type(rel)) { - case R_386_32: - case R_386_PC32: - default: - assert(false && "unexpected relocation type"); - } - } else { - switch (reloc_type(rel)) { - case R_X86_64_64: - { - symbol = symtab->FindSymbolByID(reloc_symbol(rel)); - if (symbol) - { - addr_t value = symbol->GetAddressRef().GetFileAddress(); - DataBufferSP& data_buffer_sp = debug_data.GetSharedDataBuffer(); - uint64_t* dst = reinterpret_cast<uint64_t*>(data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + ELFRelocation::RelocOffset64(rel)); - *dst = value + ELFRelocation::RelocAddend64(rel); - } - break; - } - case R_X86_64_32: - case R_X86_64_32S: - { - 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)) || - (reloc_type(rel) == R_X86_64_32S && - ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); - 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; - } - break; - } - case R_X86_64_PC32: - default: - assert(false && "unexpected relocation type"); - } + return ParsePLTRelocations(symbol_table, start_id, rel_type, &m_header, + rel_hdr, plt_hdr, sym_hdr, plt_section_sp, + rel_data, symtab_data, strtab_data); +} + +unsigned ObjectFileELF::RelocateSection( + Symtab *symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr, + const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr, + DataExtractor &rel_data, DataExtractor &symtab_data, + DataExtractor &debug_data, Section *rel_section) { + ELFRelocation rel(rel_hdr->sh_type); + lldb::addr_t offset = 0; + const unsigned num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize; + typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel); + reloc_info_fn reloc_type; + reloc_info_fn reloc_symbol; + + if (hdr->Is32Bit()) { + reloc_type = ELFRelocation::RelocType32; + reloc_symbol = ELFRelocation::RelocSymbol32; + } else { + reloc_type = ELFRelocation::RelocType64; + reloc_symbol = ELFRelocation::RelocSymbol64; + } + + for (unsigned i = 0; i < num_relocations; ++i) { + if (rel.Parse(rel_data, &offset) == false) + break; + + Symbol *symbol = NULL; + + if (hdr->Is32Bit()) { + switch (reloc_type(rel)) { + case R_386_32: + case R_386_PC32: + default: + assert(false && "unexpected relocation type"); + } + } else { + switch (reloc_type(rel)) { + case R_X86_64_64: { + symbol = symtab->FindSymbolByID(reloc_symbol(rel)); + if (symbol) { + addr_t value = symbol->GetAddressRef().GetFileAddress(); + DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer(); + uint64_t *dst = reinterpret_cast<uint64_t *>( + data_buffer_sp->GetBytes() + rel_section->GetFileOffset() + + ELFRelocation::RelocOffset64(rel)); + *dst = value + ELFRelocation::RelocAddend64(rel); } + break; + } + case R_X86_64_32: + case R_X86_64_32S: { + 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)) || + (reloc_type(rel) == R_X86_64_32S && + ((int64_t)value <= INT32_MAX && (int64_t)value >= INT32_MIN))); + 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; + } + break; + } + case R_X86_64_PC32: + default: + assert(false && "unexpected relocation type"); + } } + } - return 0; + return 0; } -unsigned -ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, user_id_t rel_id) -{ - assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); +unsigned ObjectFileELF::RelocateDebugSections(const ELFSectionHeader *rel_hdr, + user_id_t rel_id) { + assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL); - // Parse in the section list if needed. - SectionList *section_list = GetSectionList(); - if (!section_list) - return 0; + // Parse in the section list if needed. + SectionList *section_list = GetSectionList(); + 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; + // 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; - const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); - if (!symtab_hdr) - return 0; + const ELFSectionHeader *symtab_hdr = GetSectionHeaderByIndex(symtab_id); + if (!symtab_hdr) + return 0; - const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id); - if (!debug_hdr) - return 0; + const ELFSectionHeader *debug_hdr = GetSectionHeaderByIndex(debug_id); + if (!debug_hdr) + return 0; - Section *rel = section_list->FindSectionByID(rel_id).get(); - if (!rel) - return 0; + Section *rel = section_list->FindSectionByID(rel_id).get(); + if (!rel) + return 0; - Section *symtab = section_list->FindSectionByID(symtab_id).get(); - if (!symtab) - return 0; + Section *symtab = section_list->FindSectionByID(symtab_id).get(); + if (!symtab) + return 0; - Section *debug = section_list->FindSectionByID(debug_id).get(); - if (!debug) - return 0; + Section *debug = section_list->FindSectionByID(debug_id).get(); + if (!debug) + return 0; - DataExtractor rel_data; - 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); - } + DataExtractor rel_data; + DataExtractor symtab_data; + DataExtractor debug_data; - return 0; + 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); + } + + return 0; } -Symtab * -ObjectFileELF::GetSymtab() -{ - ModuleSP module_sp(GetModule()); - if (!module_sp) - 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. - ObjectFile *module_obj_file = module_sp->GetObjectFile(); - if (module_obj_file && module_obj_file != this) - return module_obj_file->GetSymtab(); - - if (m_symtab_ap.get() == NULL) - { - SectionList *section_list = module_sp->GetSectionList(); - if (!section_list) - return NULL; - - uint64_t symbol_id = 0; - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - - // 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. - Section *symtab = section_list->FindSectionByType (eSectionTypeELFSymbolTable, true).get(); - if (!symtab) - { - // The symtab section is non-allocable and can be stripped, so if it doesn't exist - // then use the dynsym section which should always be there. - symtab = section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true).get(); - } - if (symtab) - { - m_symtab_ap.reset(new Symtab(symtab->GetObjectFile())); - symbol_id += ParseSymbolTable (m_symtab_ap.get(), symbol_id, symtab); - } +Symtab *ObjectFileELF::GetSymtab() { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return NULL; - // DT_JMPREL - // If present, this entry's d_ptr member holds the address of relocation - // entries associated solely with the procedure linkage table. Separating - // these relocation entries lets the dynamic linker ignore them during - // process initialization, if lazy binding is enabled. If this entry is - // present, the related entries of types DT_PLTRELSZ and DT_PLTREL must - // also be present. - const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL); - if (symbol) - { - // 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) - { - user_id_t reloc_id = reloc_section->GetID(); - const ELFSectionHeaderInfo *reloc_header = GetSectionHeaderByIndex(reloc_id); - assert(reloc_header); - - if (m_symtab_ap == nullptr) - m_symtab_ap.reset(new Symtab(reloc_section->GetObjectFile())); - - ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id); - } - } + // We always want to use the main object file so we (hopefully) only have one + // 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(); - DWARFCallFrameInfo* eh_frame = GetUnwindTable().GetEHFrameInfo(); - if (eh_frame) - { - if (m_symtab_ap == nullptr) - m_symtab_ap.reset(new Symtab(this)); - ParseUnwindSymbols (m_symtab_ap.get(), eh_frame); - } + if (m_symtab_ap.get() == NULL) { + SectionList *section_list = module_sp->GetSectionList(); + if (!section_list) + return NULL; - // If we still don't have any symtab then create an empty instance to avoid do the section - // lookup next time. - if (m_symtab_ap == nullptr) - m_symtab_ap.reset(new Symtab(this)); + uint64_t symbol_id = 0; + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - m_symtab_ap->CalculateSymbolSizes(); - } + // 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. + Section *symtab = + section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); + if (!symtab) { + // The symtab section is non-allocable and can be stripped, so if it + // doesn't exist + // then use the dynsym section which should always be there. + symtab = + section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) + .get(); + } + if (symtab) { + m_symtab_ap.reset(new Symtab(symtab->GetObjectFile())); + symbol_id += ParseSymbolTable(m_symtab_ap.get(), symbol_id, symtab); + } + + // DT_JMPREL + // If present, this entry's d_ptr member holds the address of + // relocation + // entries associated solely with the procedure linkage table. + // Separating + // these relocation entries lets the dynamic linker ignore them during + // process initialization, if lazy binding is enabled. If this entry is + // present, the related entries of types DT_PLTRELSZ and DT_PLTREL must + // also be present. + const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL); + if (symbol) { + // 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) { + user_id_t reloc_id = reloc_section->GetID(); + const ELFSectionHeaderInfo *reloc_header = + GetSectionHeaderByIndex(reloc_id); + assert(reloc_header); - 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); - } - } + if (m_symtab_ap == nullptr) + m_symtab_ap.reset(new Symtab(reloc_section->GetObjectFile())); + + ParseTrampolineSymbols(m_symtab_ap.get(), symbol_id, reloc_header, + reloc_id); + } + } + + DWARFCallFrameInfo *eh_frame = GetUnwindTable().GetEHFrameInfo(); + if (eh_frame) { + if (m_symtab_ap == nullptr) + m_symtab_ap.reset(new Symtab(this)); + ParseUnwindSymbols(m_symtab_ap.get(), eh_frame); + } + + // If we still don't have any symtab then create an empty instance to avoid + // do the section + // lookup next time. + if (m_symtab_ap == nullptr) + m_symtab_ap.reset(new Symtab(this)); + + m_symtab_ap->CalculateSymbolSizes(); + } + + 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); } + } + } + } + return m_symtab_ap.get(); +} + +void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, + DWARFCallFrameInfo *eh_frame) { + SectionList *section_list = GetSectionList(); + if (!section_list) + 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. + std::vector<Symbol> new_symbols; + + eh_frame->ForEachFDEEntries([this, symbol_table, section_list, &new_symbols]( + lldb::addr_t file_addr, uint32_t size, dw_offset_t) { + Symbol *symbol = symbol_table->FindSymbolAtFileAddress(file_addr); + if (symbol) { + if (!symbol->GetByteSizeIsValid()) { + symbol->SetByteSize(size); + symbol->SetSizeIsSynthesized(true); + } + } else { + SectionSP section_sp = + section_list->FindSectionContainingFileAddress(file_addr); + if (section_sp) { + addr_t offset = file_addr - section_sp->GetFileAddress(); + const char *symbol_name = GetNextSyntheticSymbolName().GetCString(); + uint64_t symbol_id = symbol_table->GetNumSymbols(); + Symbol eh_symbol( + symbol_id, // Symbol table index. + symbol_name, // Symbol name. + false, // Is the symbol name mangled? + eSymbolTypeCode, // Type of this symbol. + true, // Is this globally visible? + false, // Is this symbol debug info? + false, // Is this symbol a trampoline? + true, // Is this symbol artificial? + section_sp, // Section in which this symbol is defined or null. + offset, // Offset in section or symbol value. + 0, // Size: Don't specify the size as an FDE can + false, // Size is valid: cover multiple symbols. + false, // Contains linker annotations? + 0); // Symbol flags. + new_symbols.push_back(eh_symbol); + } } - return m_symtab_ap.get(); -} - -void -ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, DWARFCallFrameInfo* eh_frame) -{ - SectionList* section_list = GetSectionList(); - if (!section_list) - 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. - std::vector<Symbol> new_symbols; - - eh_frame->ForEachFDEEntries( - [this, symbol_table, section_list, &new_symbols](lldb::addr_t file_addr, - uint32_t size, - dw_offset_t) { - Symbol* symbol = symbol_table->FindSymbolAtFileAddress(file_addr); - if (symbol) - { - if (!symbol->GetByteSizeIsValid()) - { - symbol->SetByteSize(size); - symbol->SetSizeIsSynthesized(true); - } - } - else - { - SectionSP section_sp = section_list->FindSectionContainingFileAddress(file_addr); - if (section_sp) - { - addr_t offset = file_addr - section_sp->GetFileAddress(); - const char* symbol_name = GetNextSyntheticSymbolName().GetCString(); - uint64_t symbol_id = symbol_table->GetNumSymbols(); - Symbol eh_symbol( - symbol_id, // Symbol table index. - symbol_name, // Symbol name. - false, // Is the symbol name mangled? - eSymbolTypeCode, // Type of this symbol. - true, // Is this globally visible? - false, // Is this symbol debug info? - false, // Is this symbol a trampoline? - true, // Is this symbol artificial? - section_sp, // Section in which this symbol is defined or null. - offset, // Offset in section or symbol value. - 0, // Size: Don't specify the size as an FDE can - false, // Size is valid: cover multiple symbols. - false, // Contains linker annotations? - 0); // Symbol flags. - new_symbols.push_back(eh_symbol); - } - } - return true; - }); + return true; + }); - for (const Symbol& s : new_symbols) - symbol_table->AddSymbol(s); + for (const Symbol &s : new_symbols) + symbol_table->AddSymbol(s); } -bool -ObjectFileELF::IsStripped () -{ - // TODO: determine this for ELF - return false; +bool ObjectFileELF::IsStripped() { + // TODO: determine this for ELF + return false; } //===----------------------------------------------------------------------===// @@ -3142,40 +2995,38 @@ ObjectFileELF::IsStripped () // Dump the specifics of the runtime file container (such as any headers // segments, sections, etc). //---------------------------------------------------------------------- -void -ObjectFileELF::Dump(Stream *s) -{ - ModuleSP module_sp(GetModule()); - if (!module_sp) - { - return; - } - - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - s->Printf("%p: ", static_cast<void *>(this)); - s->Indent(); - s->PutCString("ObjectFileELF"); - - ArchSpec header_arch; - GetArchitecture(header_arch); - - *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; - - DumpELFHeader(s, m_header); - s->EOL(); - DumpELFProgramHeaders(s); - s->EOL(); - DumpELFSectionHeaders(s); - s->EOL(); - SectionList *section_list = GetSectionList(); - if (section_list) - section_list->Dump(s, NULL, true, UINT32_MAX); - Symtab *symtab = GetSymtab(); - if (symtab) - symtab->Dump(s, NULL, eSortOrderNone); - s->EOL(); - DumpDependentModules(s); - s->EOL(); +void ObjectFileELF::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (!module_sp) { + return; + } + + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + s->Printf("%p: ", static_cast<void *>(this)); + s->Indent(); + s->PutCString("ObjectFileELF"); + + ArchSpec header_arch; + GetArchitecture(header_arch); + + *s << ", file = '" << m_file + << "', arch = " << header_arch.GetArchitectureName() << "\n"; + + DumpELFHeader(s, m_header); + s->EOL(); + DumpELFProgramHeaders(s); + s->EOL(); + DumpELFSectionHeaders(s); + s->EOL(); + SectionList *section_list = GetSectionList(); + if (section_list) + section_list->Dump(s, NULL, true, UINT32_MAX); + Symtab *symtab = GetSymtab(); + if (symtab) + symtab->Dump(s, NULL, eSortOrderNone); + s->EOL(); + DumpDependentModules(s); + s->EOL(); } //---------------------------------------------------------------------- @@ -3183,38 +3034,36 @@ ObjectFileELF::Dump(Stream *s) // // Dump the ELF header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header) -{ - s->PutCString("ELF Header\n"); - s->Printf("e_ident[EI_MAG0 ] = 0x%2.2x\n", header.e_ident[EI_MAG0]); - s->Printf("e_ident[EI_MAG1 ] = 0x%2.2x '%c'\n", - header.e_ident[EI_MAG1], header.e_ident[EI_MAG1]); - s->Printf("e_ident[EI_MAG2 ] = 0x%2.2x '%c'\n", - header.e_ident[EI_MAG2], header.e_ident[EI_MAG2]); - s->Printf("e_ident[EI_MAG3 ] = 0x%2.2x '%c'\n", - header.e_ident[EI_MAG3], header.e_ident[EI_MAG3]); - - s->Printf("e_ident[EI_CLASS ] = 0x%2.2x\n", header.e_ident[EI_CLASS]); - s->Printf("e_ident[EI_DATA ] = 0x%2.2x ", header.e_ident[EI_DATA]); - DumpELFHeader_e_ident_EI_DATA(s, header.e_ident[EI_DATA]); - s->Printf ("\ne_ident[EI_VERSION] = 0x%2.2x\n", header.e_ident[EI_VERSION]); - s->Printf ("e_ident[EI_PAD ] = 0x%2.2x\n", header.e_ident[EI_PAD]); - - s->Printf("e_type = 0x%4.4x ", header.e_type); - DumpELFHeader_e_type(s, header.e_type); - s->Printf("\ne_machine = 0x%4.4x\n", header.e_machine); - s->Printf("e_version = 0x%8.8x\n", header.e_version); - s->Printf("e_entry = 0x%8.8" PRIx64 "\n", header.e_entry); - s->Printf("e_phoff = 0x%8.8" PRIx64 "\n", header.e_phoff); - s->Printf("e_shoff = 0x%8.8" PRIx64 "\n", header.e_shoff); - s->Printf("e_flags = 0x%8.8x\n", header.e_flags); - s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize); - s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize); - s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum); - s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize); - s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum); - s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx); +void ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header) { + s->PutCString("ELF Header\n"); + s->Printf("e_ident[EI_MAG0 ] = 0x%2.2x\n", header.e_ident[EI_MAG0]); + s->Printf("e_ident[EI_MAG1 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG1], + header.e_ident[EI_MAG1]); + s->Printf("e_ident[EI_MAG2 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG2], + header.e_ident[EI_MAG2]); + s->Printf("e_ident[EI_MAG3 ] = 0x%2.2x '%c'\n", header.e_ident[EI_MAG3], + header.e_ident[EI_MAG3]); + + s->Printf("e_ident[EI_CLASS ] = 0x%2.2x\n", header.e_ident[EI_CLASS]); + s->Printf("e_ident[EI_DATA ] = 0x%2.2x ", header.e_ident[EI_DATA]); + DumpELFHeader_e_ident_EI_DATA(s, header.e_ident[EI_DATA]); + s->Printf("\ne_ident[EI_VERSION] = 0x%2.2x\n", header.e_ident[EI_VERSION]); + s->Printf("e_ident[EI_PAD ] = 0x%2.2x\n", header.e_ident[EI_PAD]); + + s->Printf("e_type = 0x%4.4x ", header.e_type); + DumpELFHeader_e_type(s, header.e_type); + s->Printf("\ne_machine = 0x%4.4x\n", header.e_machine); + s->Printf("e_version = 0x%8.8x\n", header.e_version); + s->Printf("e_entry = 0x%8.8" PRIx64 "\n", header.e_entry); + s->Printf("e_phoff = 0x%8.8" PRIx64 "\n", header.e_phoff); + s->Printf("e_shoff = 0x%8.8" PRIx64 "\n", header.e_shoff); + s->Printf("e_flags = 0x%8.8x\n", header.e_flags); + s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize); + s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize); + s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum); + s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize); + s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum); + s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx); } //---------------------------------------------------------------------- @@ -3222,19 +3071,26 @@ ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header) // // Dump an token value for the ELF header member e_type //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFHeader_e_type(Stream *s, elf_half e_type) -{ - switch (e_type) - { - case ET_NONE: *s << "ET_NONE"; break; - case ET_REL: *s << "ET_REL"; break; - case ET_EXEC: *s << "ET_EXEC"; break; - case ET_DYN: *s << "ET_DYN"; break; - case ET_CORE: *s << "ET_CORE"; break; - default: - break; - } +void ObjectFileELF::DumpELFHeader_e_type(Stream *s, elf_half e_type) { + switch (e_type) { + case ET_NONE: + *s << "ET_NONE"; + break; + case ET_REL: + *s << "ET_REL"; + break; + case ET_EXEC: + *s << "ET_EXEC"; + break; + case ET_DYN: + *s << "ET_DYN"; + break; + case ET_CORE: + *s << "ET_CORE"; + break; + default: + break; + } } //---------------------------------------------------------------------- @@ -3242,34 +3098,38 @@ ObjectFileELF::DumpELFHeader_e_type(Stream *s, elf_half e_type) // // Dump an token value for the ELF header member e_ident[EI_DATA] //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFHeader_e_ident_EI_DATA(Stream *s, unsigned char ei_data) -{ - switch (ei_data) - { - case ELFDATANONE: *s << "ELFDATANONE"; break; - case ELFDATA2LSB: *s << "ELFDATA2LSB - Little Endian"; break; - case ELFDATA2MSB: *s << "ELFDATA2MSB - Big Endian"; break; - default: - break; - } +void ObjectFileELF::DumpELFHeader_e_ident_EI_DATA(Stream *s, + unsigned char ei_data) { + switch (ei_data) { + case ELFDATANONE: + *s << "ELFDATANONE"; + break; + case ELFDATA2LSB: + *s << "ELFDATA2LSB - Little Endian"; + break; + case ELFDATA2MSB: + *s << "ELFDATA2MSB - Big Endian"; + break; + default: + break; + } } - //---------------------------------------------------------------------- // DumpELFProgramHeader // // Dump a single ELF program header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFProgramHeader(Stream *s, const ELFProgramHeader &ph) -{ - DumpELFProgramHeader_p_type(s, ph.p_type); - s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, ph.p_offset, ph.p_vaddr, ph.p_paddr); - s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8x (", ph.p_filesz, ph.p_memsz, ph.p_flags); +void ObjectFileELF::DumpELFProgramHeader(Stream *s, + const ELFProgramHeader &ph) { + DumpELFProgramHeader_p_type(s, ph.p_type); + s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, ph.p_offset, + ph.p_vaddr, ph.p_paddr); + s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8x (", ph.p_filesz, ph.p_memsz, + ph.p_flags); - DumpELFProgramHeader_p_flags(s, ph.p_flags); - s->Printf(") %8.8" PRIx64, ph.p_align); + DumpELFProgramHeader_p_flags(s, ph.p_flags); + s->Printf(") %8.8" PRIx64, ph.p_align); } //---------------------------------------------------------------------- @@ -3278,41 +3138,35 @@ ObjectFileELF::DumpELFProgramHeader(Stream *s, const ELFProgramHeader &ph) // 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; - switch (p_type) - { - CASE_AND_STREAM(s, PT_NULL , kStrWidth); - CASE_AND_STREAM(s, PT_LOAD , kStrWidth); - CASE_AND_STREAM(s, PT_DYNAMIC , kStrWidth); - CASE_AND_STREAM(s, PT_INTERP , kStrWidth); - CASE_AND_STREAM(s, PT_NOTE , kStrWidth); - CASE_AND_STREAM(s, PT_SHLIB , kStrWidth); - CASE_AND_STREAM(s, PT_PHDR , kStrWidth); - CASE_AND_STREAM(s, PT_TLS , kStrWidth); +void ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, elf_word p_type) { + const int kStrWidth = 15; + switch (p_type) { + CASE_AND_STREAM(s, PT_NULL, kStrWidth); + CASE_AND_STREAM(s, PT_LOAD, kStrWidth); + CASE_AND_STREAM(s, PT_DYNAMIC, kStrWidth); + CASE_AND_STREAM(s, PT_INTERP, kStrWidth); + CASE_AND_STREAM(s, PT_NOTE, kStrWidth); + CASE_AND_STREAM(s, PT_SHLIB, kStrWidth); + CASE_AND_STREAM(s, PT_PHDR, kStrWidth); + CASE_AND_STREAM(s, PT_TLS, kStrWidth); CASE_AND_STREAM(s, PT_GNU_EH_FRAME, kStrWidth); - default: - s->Printf("0x%8.8x%*s", p_type, kStrWidth - 10, ""); - break; - } + default: + s->Printf("0x%8.8x%*s", p_type, kStrWidth - 10, ""); + break; + } } - //---------------------------------------------------------------------- // DumpELFProgramHeader_p_flags // // Dump an token value for the ELF program header member p_flags //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags) -{ - *s << ((p_flags & PF_X) ? "PF_X" : " ") - << (((p_flags & PF_X) && (p_flags & PF_W)) ? '+' : ' ') - << ((p_flags & PF_W) ? "PF_W" : " ") - << (((p_flags & PF_W) && (p_flags & PF_R)) ? '+' : ' ') - << ((p_flags & PF_R) ? "PF_R" : " "); +void ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags) { + *s << ((p_flags & PF_X) ? "PF_X" : " ") + << (((p_flags & PF_X) && (p_flags & PF_W)) ? '+' : ' ') + << ((p_flags & PF_W) ? "PF_W" : " ") + << (((p_flags & PF_W) && (p_flags & PF_R)) ? '+' : ' ') + << ((p_flags & PF_R) ? "PF_R" : " "); } //---------------------------------------------------------------------- @@ -3320,26 +3174,23 @@ ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags) // // Dump all of the ELF program header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFProgramHeaders(Stream *s) -{ - if (!ParseProgramHeaders()) - return; - - s->PutCString("Program Headers\n"); - s->PutCString("IDX p_type p_offset p_vaddr p_paddr " - "p_filesz p_memsz p_flags p_align\n"); - 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); - s->EOL(); - } +void ObjectFileELF::DumpELFProgramHeaders(Stream *s) { + if (!ParseProgramHeaders()) + return; + + s->PutCString("Program Headers\n"); + s->PutCString("IDX p_type p_offset p_vaddr p_paddr " + "p_filesz p_memsz p_flags p_align\n"); + 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); + s->EOL(); + } } //---------------------------------------------------------------------- @@ -3347,16 +3198,16 @@ ObjectFileELF::DumpELFProgramHeaders(Stream *s) // // Dump a single ELF section header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeaderInfo &sh) -{ - s->Printf("%8.8x ", sh.sh_name); - DumpELFSectionHeader_sh_type(s, sh.sh_type); - s->Printf(" %8.8" PRIx64 " (", sh.sh_flags); - DumpELFSectionHeader_sh_flags(s, sh.sh_flags); - s->Printf(") %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addr, sh.sh_offset, sh.sh_size); - s->Printf(" %8.8x %8.8x", sh.sh_link, sh.sh_info); - s->Printf(" %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addralign, sh.sh_entsize); +void ObjectFileELF::DumpELFSectionHeader(Stream *s, + const ELFSectionHeaderInfo &sh) { + s->Printf("%8.8x ", sh.sh_name); + DumpELFSectionHeader_sh_type(s, sh.sh_type); + s->Printf(" %8.8" PRIx64 " (", sh.sh_flags); + DumpELFSectionHeader_sh_flags(s, sh.sh_flags); + s->Printf(") %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addr, + sh.sh_offset, sh.sh_size); + s->Printf(" %8.8x %8.8x", sh.sh_link, sh.sh_info); + s->Printf(" %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addralign, sh.sh_entsize); } //---------------------------------------------------------------------- @@ -3365,32 +3216,29 @@ ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeaderInfo &sh) // Dump an token value for the ELF section header member sh_type which // describes the type of the section //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, elf_word sh_type) -{ - const int kStrWidth = 12; - switch (sh_type) - { - CASE_AND_STREAM(s, SHT_NULL , kStrWidth); - CASE_AND_STREAM(s, SHT_PROGBITS , kStrWidth); - CASE_AND_STREAM(s, SHT_SYMTAB , kStrWidth); - CASE_AND_STREAM(s, SHT_STRTAB , kStrWidth); - CASE_AND_STREAM(s, SHT_RELA , kStrWidth); - CASE_AND_STREAM(s, SHT_HASH , kStrWidth); - CASE_AND_STREAM(s, SHT_DYNAMIC , kStrWidth); - CASE_AND_STREAM(s, SHT_NOTE , kStrWidth); - CASE_AND_STREAM(s, SHT_NOBITS , kStrWidth); - CASE_AND_STREAM(s, SHT_REL , kStrWidth); - CASE_AND_STREAM(s, SHT_SHLIB , kStrWidth); - CASE_AND_STREAM(s, SHT_DYNSYM , kStrWidth); - CASE_AND_STREAM(s, SHT_LOPROC , kStrWidth); - CASE_AND_STREAM(s, SHT_HIPROC , kStrWidth); - CASE_AND_STREAM(s, SHT_LOUSER , kStrWidth); - CASE_AND_STREAM(s, SHT_HIUSER , kStrWidth); - default: - s->Printf("0x%8.8x%*s", sh_type, kStrWidth - 10, ""); - break; - } +void ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, elf_word sh_type) { + const int kStrWidth = 12; + switch (sh_type) { + CASE_AND_STREAM(s, SHT_NULL, kStrWidth); + CASE_AND_STREAM(s, SHT_PROGBITS, kStrWidth); + CASE_AND_STREAM(s, SHT_SYMTAB, kStrWidth); + CASE_AND_STREAM(s, SHT_STRTAB, kStrWidth); + CASE_AND_STREAM(s, SHT_RELA, kStrWidth); + CASE_AND_STREAM(s, SHT_HASH, kStrWidth); + CASE_AND_STREAM(s, SHT_DYNAMIC, kStrWidth); + CASE_AND_STREAM(s, SHT_NOTE, kStrWidth); + CASE_AND_STREAM(s, SHT_NOBITS, kStrWidth); + CASE_AND_STREAM(s, SHT_REL, kStrWidth); + CASE_AND_STREAM(s, SHT_SHLIB, kStrWidth); + CASE_AND_STREAM(s, SHT_DYNSYM, kStrWidth); + CASE_AND_STREAM(s, SHT_LOPROC, kStrWidth); + CASE_AND_STREAM(s, SHT_HIPROC, kStrWidth); + CASE_AND_STREAM(s, SHT_LOUSER, kStrWidth); + CASE_AND_STREAM(s, SHT_HIUSER, kStrWidth); + default: + s->Printf("0x%8.8x%*s", sh_type, kStrWidth - 10, ""); + break; + } } //---------------------------------------------------------------------- @@ -3398,14 +3246,13 @@ ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, elf_word sh_type) // // Dump an token value for the ELF section header member sh_flags //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, elf_xword sh_flags) -{ - *s << ((sh_flags & SHF_WRITE) ? "WRITE" : " ") - << (((sh_flags & SHF_WRITE) && (sh_flags & SHF_ALLOC)) ? '+' : ' ') - << ((sh_flags & SHF_ALLOC) ? "ALLOC" : " ") - << (((sh_flags & SHF_ALLOC) && (sh_flags & SHF_EXECINSTR)) ? '+' : ' ') - << ((sh_flags & SHF_EXECINSTR) ? "EXECINSTR" : " "); +void ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, + elf_xword sh_flags) { + *s << ((sh_flags & SHF_WRITE) ? "WRITE" : " ") + << (((sh_flags & SHF_WRITE) && (sh_flags & SHF_ALLOC)) ? '+' : ' ') + << ((sh_flags & SHF_ALLOC) ? "ALLOC" : " ") + << (((sh_flags & SHF_ALLOC) && (sh_flags & SHF_EXECINSTR)) ? '+' : ' ') + << ((sh_flags & SHF_EXECINSTR) ? "EXECINSTR" : " "); } //---------------------------------------------------------------------- @@ -3413,153 +3260,135 @@ ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, elf_xword sh_flags) // // Dump all of the ELF section header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFileELF::DumpELFSectionHeaders(Stream *s) -{ - if (!ParseSectionHeaders()) - return; - - s->PutCString("Section Headers\n"); - s->PutCString("IDX name type flags " - "addr offset size link info addralgn " - "entsize Name\n"); - s->PutCString("==== -------- ------------ -------------------------------- " - "-------- -------- -------- -------- -------- -------- " - "-------- ====================\n"); - - uint32_t idx = 0; - for (SectionHeaderCollConstIter I = m_section_headers.begin(); - I != m_section_headers.end(); ++I, ++idx) - { - s->Printf("[%2u] ", idx); - ObjectFileELF::DumpELFSectionHeader(s, *I); - const char* section_name = I->section_name.AsCString(""); - if (section_name) - *s << ' ' << section_name << "\n"; - } -} - -void -ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) -{ - size_t num_modules = ParseDependentModules(); +void ObjectFileELF::DumpELFSectionHeaders(Stream *s) { + if (!ParseSectionHeaders()) + return; + + s->PutCString("Section Headers\n"); + s->PutCString("IDX name type flags " + "addr offset size link info addralgn " + "entsize Name\n"); + s->PutCString("==== -------- ------------ -------------------------------- " + "-------- -------- -------- -------- -------- -------- " + "-------- ====================\n"); + + uint32_t idx = 0; + for (SectionHeaderCollConstIter I = m_section_headers.begin(); + I != m_section_headers.end(); ++I, ++idx) { + s->Printf("[%2u] ", idx); + ObjectFileELF::DumpELFSectionHeader(s, *I); + const char *section_name = I->section_name.AsCString(""); + if (section_name) + *s << ' ' << section_name << "\n"; + } +} + +void ObjectFileELF::DumpDependentModules(lldb_private::Stream *s) { + size_t num_modules = ParseDependentModules(); + + if (num_modules > 0) { + s->PutCString("Dependent Modules:\n"); + for (unsigned i = 0; i < num_modules; ++i) { + const FileSpec &spec = m_filespec_ap->GetFileSpecAtIndex(i); + s->Printf(" %s\n", spec.GetFilename().GetCString()); + } + } +} + +bool ObjectFileELF::GetArchitecture(ArchSpec &arch) { + if (!ParseHeader()) + return false; - if (num_modules > 0) - { - s->PutCString("Dependent Modules:\n"); - for (unsigned i = 0; i < num_modules; ++i) - { - const FileSpec &spec = m_filespec_ap->GetFileSpecAtIndex(i); - s->Printf(" %s\n", spec.GetFilename().GetCString()); + if (m_section_headers.empty()) { + // Allow elf notes to be parsed which may affect the detected architecture. + ParseSectionHeaders(); + } + + 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 = 0, 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); + } } + } } + } + arch = m_arch_spec; + return true; } -bool -ObjectFileELF::GetArchitecture (ArchSpec &arch) -{ - if (!ParseHeader()) - return false; +ObjectFile::Type ObjectFileELF::CalculateType() { + switch (m_header.e_type) { + case llvm::ELF::ET_NONE: + // 0 - No file type + return eTypeUnknown; - if (m_section_headers.empty()) - { - // Allow elf notes to be parsed which may affect the detected architecture. - ParseSectionHeaders(); - } + case llvm::ELF::ET_REL: + // 1 - Relocatable file + return eTypeObjectFile; - 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 = 0, 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); - } - } - } - } - } - arch = m_arch_spec; - return true; -} + case llvm::ELF::ET_EXEC: + // 2 - Executable file + return eTypeExecutable; -ObjectFile::Type -ObjectFileELF::CalculateType() -{ - switch (m_header.e_type) - { - case llvm::ELF::ET_NONE: - // 0 - No file type - return eTypeUnknown; + case llvm::ELF::ET_DYN: + // 3 - Shared object file + return eTypeSharedLibrary; - case llvm::ELF::ET_REL: - // 1 - Relocatable file - return eTypeObjectFile; + case ET_CORE: + // 4 - Core file + return eTypeCoreFile; - case llvm::ELF::ET_EXEC: - // 2 - Executable file - return eTypeExecutable; + default: + break; + } + return eTypeUnknown; +} - case llvm::ELF::ET_DYN: - // 3 - Shared object file - return eTypeSharedLibrary; +ObjectFile::Strata ObjectFileELF::CalculateStrata() { + switch (m_header.e_type) { + case llvm::ELF::ET_NONE: + // 0 - No file type + return eStrataUnknown; - case ET_CORE: - // 4 - Core file - return eTypeCoreFile; + case llvm::ELF::ET_REL: + // 1 - Relocatable file + return eStrataUnknown; - default: - break; - } - return eTypeUnknown; -} + 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??? + 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??? + return eStrataUnknown; -ObjectFile::Strata -ObjectFileELF::CalculateStrata() -{ - switch (m_header.e_type) - { - case llvm::ELF::ET_NONE: - // 0 - No file type - return eStrataUnknown; - - case llvm::ELF::ET_REL: - // 1 - Relocatable file - return eStrataUnknown; - - 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??? - 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??? - 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??? - return eStrataUnknown; - - default: - break; - } + 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??? return eStrataUnknown; -} + default: + break; + } + return eStrataUnknown; +} diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index e2f73f53ec6..4ce5648cfed 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -19,46 +19,40 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/UUID.h" #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Core/UUID.h" -#include "lldb/Core/ArchSpec.h" +#include "lldb/lldb-private.h" #include "ELFHeader.h" -struct ELFNote -{ - elf::elf_word n_namesz; - elf::elf_word n_descsz; - elf::elf_word n_type; - - std::string n_name; - - ELFNote() : n_namesz(0), n_descsz(0), n_type(0) - { - } - - /// Parse an ELFNote entry from the given DataExtractor starting at position - /// \p offset. - /// - /// @param[in] data - /// The DataExtractor to read from. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFRel entry was successfully read and false otherwise. - bool - Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); - - size_t - GetByteSize() const - { - return 12 + llvm::alignTo (n_namesz, 4) + llvm::alignTo (n_descsz, 4); - } +struct ELFNote { + elf::elf_word n_namesz; + elf::elf_word n_descsz; + elf::elf_word n_type; + + std::string n_name; + + ELFNote() : n_namesz(0), n_descsz(0), n_type(0) {} + + /// Parse an ELFNote entry from the given DataExtractor starting at position + /// \p offset. + /// + /// @param[in] data + /// The DataExtractor to read from. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFRel entry was successfully read and false otherwise. + bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); + + size_t GetByteSize() const { + return 12 + llvm::alignTo(n_namesz, 4) + llvm::alignTo(n_descsz, 4); + } }; //------------------------------------------------------------------------------ @@ -67,390 +61,332 @@ struct ELFNote /// /// This class provides a generic ELF (32/64 bit) reader plugin implementing the /// ObjectFile protocol. -class ObjectFileELF : - public lldb_private::ObjectFile -{ +class ObjectFileELF : public lldb_private::ObjectFile { public: - ~ObjectFileELF() override; + ~ObjectFileELF() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + //------------------------------------------------------------------ + // ObjectFile Protocol. + //------------------------------------------------------------------ + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + lldb_private::Symtab *GetSymtab() override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + bool GetArchitecture(lldb_private::ArchSpec &arch) override; + + bool GetUUID(lldb_private::UUID *uuid) override; + + lldb_private::FileSpecList GetDebugSymbolFilePaths() override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::Address + GetImageInfoAddress(lldb_private::Target *target) override; + + lldb_private::Address GetEntryPointAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + // Returns number of program headers found in the ELF file. + size_t GetProgramHeaderCount(); + + // Returns the program header with the given index. + const elf::ELFProgramHeader *GetProgramHeaderByIndex(lldb::user_id_t id); + + // Returns segment data for the given index. + lldb_private::DataExtractor GetSegmentDataByIndex(lldb::user_id_t id); - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - static lldb_private::ObjectFile * - CreateInstance(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length); - - static lldb_private::ObjectFile * - CreateMemoryInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - static size_t - GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs); - - static bool - MagicBytesMatch (lldb::DataBufferSP& data_sp, - lldb::addr_t offset, - lldb::addr_t length); - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - //------------------------------------------------------------------ - // ObjectFile Protocol. - //------------------------------------------------------------------ - bool - ParseHeader() override; - - bool - SetLoadAddress (lldb_private::Target &target, - lldb::addr_t value, - bool value_is_offset) override; - - lldb::ByteOrder - GetByteOrder() const override; - - bool - IsExecutable () const override; - - uint32_t - GetAddressByteSize() const override; - - lldb::AddressClass - GetAddressClass (lldb::addr_t file_addr) override; - - lldb_private::Symtab * - GetSymtab() override; - - bool - IsStripped () override; - - void - CreateSections (lldb_private::SectionList &unified_section_list) override; - - void - Dump(lldb_private::Stream *s) override; - - bool - GetArchitecture (lldb_private::ArchSpec &arch) override; - - bool - GetUUID(lldb_private::UUID* uuid) override; - - lldb_private::FileSpecList - GetDebugSymbolFilePaths() override; - - uint32_t - GetDependentModules(lldb_private::FileSpecList& files) override; - - lldb_private::Address - GetImageInfoAddress(lldb_private::Target *target) override; - - lldb_private::Address - GetEntryPointAddress () override; - - ObjectFile::Type - CalculateType() override; - - ObjectFile::Strata - CalculateStrata() override; - - // Returns number of program headers found in the ELF file. - size_t - GetProgramHeaderCount(); - - // Returns the program header with the given index. - const elf::ELFProgramHeader * - GetProgramHeaderByIndex(lldb::user_id_t id); - - // Returns segment data for the given index. - lldb_private::DataExtractor - GetSegmentDataByIndex(lldb::user_id_t id); - - std::string - StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; + std::string + StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; private: - ObjectFileELF(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t offset, - lldb::offset_t length); - - ObjectFileELF (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& header_data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; - typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; - typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; - - struct ELFSectionHeaderInfo : public elf::ELFSectionHeader - { - lldb_private::ConstString section_name; - }; - - typedef std::vector<ELFSectionHeaderInfo> SectionHeaderColl; - typedef SectionHeaderColl::iterator SectionHeaderCollIter; - typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; - - typedef std::vector<elf::ELFDynamic> DynamicSymbolColl; - typedef DynamicSymbolColl::iterator DynamicSymbolCollIter; - typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter; - - typedef std::map<lldb::addr_t, lldb::AddressClass> FileAddressToAddressClassMap; - typedef std::function<lldb::offset_t (lldb_private::DataExtractor &, lldb::offset_t, lldb::offset_t)> SetDataFunction; - - /// Version of this reader common to all plugins based on this class. - static const uint32_t m_plugin_version = 1; - static const uint32_t g_core_uuid_magic; - - /// ELF file header. - elf::ELFHeader m_header; - - /// ELF build ID. - lldb_private::UUID m_uuid; - - /// ELF .gnu_debuglink file and crc data if available. - std::string m_gnu_debuglink_file; - uint32_t m_gnu_debuglink_crc; - - /// Collection of program headers. - ProgramHeaderColl m_program_headers; - - /// Collection of section headers. - SectionHeaderColl m_section_headers; - - /// Collection of symbols from the dynamic table. - DynamicSymbolColl m_dynamic_symbols; - - /// List of file specifications corresponding to the modules (shared - /// libraries) on which this object file depends. - mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_ap; - - /// Cached value of the entry point for this module. - lldb_private::Address m_entry_point_address; - - /// The architecture detected from parsing elf file contents. - lldb_private::ArchSpec m_arch_spec; - - /// The address class for each symbol in the elf file - FileAddressToAddressClassMap m_address_class_map; - - /// Returns a 1 based index of the given section header. - size_t - SectionIndex(const SectionHeaderCollIter &I); - - /// Returns a 1 based index of the given section header. - size_t - SectionIndex(const SectionHeaderCollConstIter &I) const; - - // Parses the ELF program headers. - static size_t - GetProgramHeaderInfo(ProgramHeaderColl &program_headers, - const SetDataFunction &set_data, - const elf::ELFHeader &header); - - // Finds PT_NOTE segments and calculates their crc sum. - static uint32_t - CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl& program_headers, - lldb_private::DataExtractor &data); - - /// Parses all section headers present in this object file and populates - /// m_program_headers. This method will compute the header list only once. - /// Returns the number of headers parsed. - size_t - ParseProgramHeaders(); - - /// Parses all section headers present in this object file and populates - /// m_section_headers. This method will compute the header list only once. - /// Returns the number of headers parsed. - size_t - ParseSectionHeaders(); - - static void - ParseARMAttributes(lldb_private::DataExtractor &data, uint64_t length, - lldb_private::ArchSpec &arch_spec); - - /// Parses the elf section headers and returns the uuid, debug link name, crc, archspec. - static size_t - GetSectionHeaderInfo(SectionHeaderColl §ion_headers, - const SetDataFunction &set_data, - const elf::ELFHeader &header, - lldb_private::UUID &uuid, - std::string &gnu_debuglink_file, - uint32_t &gnu_debuglink_crc, - lldb_private::ArchSpec &arch_spec); - - /// Scans the dynamic section and locates all dependent modules (shared - /// libraries) populating m_filespec_ap. This method will compute the - /// dependent module list only once. Returns the number of dependent - /// modules parsed. - size_t - ParseDependentModules(); - - /// Parses the dynamic symbol table and populates m_dynamic_symbols. The - /// vector retains the order as found in the object file. Returns the - /// number of dynamic symbols parsed. - size_t - ParseDynamicSymbols(); - - /// Populates m_symtab_ap will all non-dynamic linker symbols. This method - /// will parse the symbols only once. Returns the number of symbols parsed. - unsigned - ParseSymbolTable(lldb_private::Symtab *symbol_table, - lldb::user_id_t start_id, - lldb_private::Section *symtab); - - /// Helper routine for ParseSymbolTable(). - unsigned - ParseSymbols(lldb_private::Symtab *symbol_table, - lldb::user_id_t start_id, - lldb_private::SectionList *section_list, - const size_t num_symbols, - const lldb_private::DataExtractor &symtab_data, - const lldb_private::DataExtractor &strtab_data); - - /// Scans the relocation entries and adds a set of artificial symbols to the - /// given symbol table for each PLT slot. Returns the number of symbols - /// added. - unsigned - ParseTrampolineSymbols(lldb_private::Symtab *symbol_table, - lldb::user_id_t start_id, - const ELFSectionHeaderInfo *rela_hdr, - lldb::user_id_t section_id); - - void - ParseUnwindSymbols(lldb_private::Symtab *symbol_table, - lldb_private::DWARFCallFrameInfo* eh_frame); - - /// Relocates debug sections - unsigned - RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, lldb::user_id_t rel_id); - - unsigned - RelocateSection(lldb_private::Symtab* symtab, const elf::ELFHeader *hdr, const elf::ELFSectionHeader *rel_hdr, - const elf::ELFSectionHeader *symtab_hdr, const elf::ELFSectionHeader *debug_hdr, - lldb_private::DataExtractor &rel_data, lldb_private::DataExtractor &symtab_data, - lldb_private::DataExtractor &debug_data, lldb_private::Section* rel_section); - - /// Loads the section name string table into m_shstr_data. Returns the - /// number of bytes constituting the table. - size_t - GetSectionHeaderStringTable(); - - /// Utility method for looking up a section given its name. Returns the - /// index of the corresponding section or zero if no section with the given - /// name can be found (note that section indices are always 1 based, and so - /// section index 0 is never valid). - lldb::user_id_t - GetSectionIndexByName(const char *name); - - // Returns the ID of the first section that has the given type. - lldb::user_id_t - GetSectionIndexByType(unsigned type); - - /// Returns the section header with the given id or NULL. - const ELFSectionHeaderInfo * - GetSectionHeaderByIndex(lldb::user_id_t id); - - /// @name ELF header dump routines - //@{ - static void - DumpELFHeader(lldb_private::Stream *s, const elf::ELFHeader& header); - - static void - DumpELFHeader_e_ident_EI_DATA(lldb_private::Stream *s, - unsigned char ei_data); - - static void - DumpELFHeader_e_type(lldb_private::Stream *s, elf::elf_half e_type); - //@} - - /// @name ELF program header dump routines - //@{ - void - DumpELFProgramHeaders(lldb_private::Stream *s); - - static void - DumpELFProgramHeader(lldb_private::Stream *s, - const elf::ELFProgramHeader &ph); - - static void - DumpELFProgramHeader_p_type(lldb_private::Stream *s, elf::elf_word p_type); - - static void - DumpELFProgramHeader_p_flags(lldb_private::Stream *s, - elf::elf_word p_flags); - //@} - - /// @name ELF section header dump routines - //@{ - void - DumpELFSectionHeaders(lldb_private::Stream *s); - - static void - DumpELFSectionHeader(lldb_private::Stream *s, - const ELFSectionHeaderInfo& sh); - - static void - DumpELFSectionHeader_sh_type(lldb_private::Stream *s, - elf::elf_word sh_type); - - static void - DumpELFSectionHeader_sh_flags(lldb_private::Stream *s, - elf::elf_xword sh_flags); - //@} - - /// ELF dependent module dump routine. - void - DumpDependentModules(lldb_private::Stream *s); - - const elf::ELFDynamic * - FindDynamicSymbol(unsigned tag); - - unsigned - PLTRelocationType(); - - static lldb_private::Error - RefineModuleDetailsFromNote (lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid); - - - static lldb::offset_t - SetData(const lldb_private::DataExtractor &src, lldb_private::DataExtractor &dst, lldb::offset_t offset, lldb::offset_t length); - - lldb::offset_t - SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, lldb::offset_t offset, lldb::offset_t length); + ObjectFileELF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + ObjectFileELF(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; + typedef ProgramHeaderColl::iterator ProgramHeaderCollIter; + typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter; + + struct ELFSectionHeaderInfo : public elf::ELFSectionHeader { + lldb_private::ConstString section_name; + }; + + typedef std::vector<ELFSectionHeaderInfo> SectionHeaderColl; + typedef SectionHeaderColl::iterator SectionHeaderCollIter; + typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; + + typedef std::vector<elf::ELFDynamic> DynamicSymbolColl; + typedef DynamicSymbolColl::iterator DynamicSymbolCollIter; + typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter; + + typedef std::map<lldb::addr_t, lldb::AddressClass> + FileAddressToAddressClassMap; + typedef std::function<lldb::offset_t(lldb_private::DataExtractor &, + lldb::offset_t, lldb::offset_t)> + SetDataFunction; + + /// Version of this reader common to all plugins based on this class. + static const uint32_t m_plugin_version = 1; + static const uint32_t g_core_uuid_magic; + + /// ELF file header. + elf::ELFHeader m_header; + + /// ELF build ID. + lldb_private::UUID m_uuid; + + /// ELF .gnu_debuglink file and crc data if available. + std::string m_gnu_debuglink_file; + uint32_t m_gnu_debuglink_crc; + + /// Collection of program headers. + ProgramHeaderColl m_program_headers; + + /// Collection of section headers. + SectionHeaderColl m_section_headers; + + /// Collection of symbols from the dynamic table. + DynamicSymbolColl m_dynamic_symbols; + + /// List of file specifications corresponding to the modules (shared + /// libraries) on which this object file depends. + mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_ap; + + /// Cached value of the entry point for this module. + lldb_private::Address m_entry_point_address; + + /// The architecture detected from parsing elf file contents. + lldb_private::ArchSpec m_arch_spec; + + /// The address class for each symbol in the elf file + FileAddressToAddressClassMap m_address_class_map; + + /// Returns a 1 based index of the given section header. + size_t SectionIndex(const SectionHeaderCollIter &I); + + /// Returns a 1 based index of the given section header. + size_t SectionIndex(const SectionHeaderCollConstIter &I) const; + + // Parses the ELF program headers. + static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers, + const SetDataFunction &set_data, + const elf::ELFHeader &header); + + // Finds PT_NOTE segments and calculates their crc sum. + static uint32_t + CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl &program_headers, + lldb_private::DataExtractor &data); + + /// Parses all section headers present in this object file and populates + /// m_program_headers. This method will compute the header list only once. + /// Returns the number of headers parsed. + size_t ParseProgramHeaders(); + + /// Parses all section headers present in this object file and populates + /// m_section_headers. This method will compute the header list only once. + /// Returns the number of headers parsed. + size_t ParseSectionHeaders(); + + static void ParseARMAttributes(lldb_private::DataExtractor &data, + uint64_t length, + lldb_private::ArchSpec &arch_spec); + + /// Parses the elf section headers and returns the uuid, debug link name, crc, + /// archspec. + static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers, + const SetDataFunction &set_data, + const elf::ELFHeader &header, + lldb_private::UUID &uuid, + std::string &gnu_debuglink_file, + uint32_t &gnu_debuglink_crc, + lldb_private::ArchSpec &arch_spec); + + /// Scans the dynamic section and locates all dependent modules (shared + /// libraries) populating m_filespec_ap. This method will compute the + /// dependent module list only once. Returns the number of dependent + /// modules parsed. + size_t ParseDependentModules(); + + /// Parses the dynamic symbol table and populates m_dynamic_symbols. The + /// vector retains the order as found in the object file. Returns the + /// number of dynamic symbols parsed. + size_t ParseDynamicSymbols(); + + /// Populates m_symtab_ap will all non-dynamic linker symbols. This method + /// will parse the symbols only once. Returns the number of symbols parsed. + unsigned ParseSymbolTable(lldb_private::Symtab *symbol_table, + lldb::user_id_t start_id, + lldb_private::Section *symtab); + + /// Helper routine for ParseSymbolTable(). + unsigned ParseSymbols(lldb_private::Symtab *symbol_table, + lldb::user_id_t start_id, + lldb_private::SectionList *section_list, + const size_t num_symbols, + const lldb_private::DataExtractor &symtab_data, + const lldb_private::DataExtractor &strtab_data); + + /// Scans the relocation entries and adds a set of artificial symbols to the + /// given symbol table for each PLT slot. Returns the number of symbols + /// added. + unsigned ParseTrampolineSymbols(lldb_private::Symtab *symbol_table, + lldb::user_id_t start_id, + const ELFSectionHeaderInfo *rela_hdr, + lldb::user_id_t section_id); + + void ParseUnwindSymbols(lldb_private::Symtab *symbol_table, + lldb_private::DWARFCallFrameInfo *eh_frame); + + /// Relocates debug sections + unsigned RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, + lldb::user_id_t rel_id); + + unsigned RelocateSection(lldb_private::Symtab *symtab, + const elf::ELFHeader *hdr, + const elf::ELFSectionHeader *rel_hdr, + const elf::ELFSectionHeader *symtab_hdr, + const elf::ELFSectionHeader *debug_hdr, + lldb_private::DataExtractor &rel_data, + lldb_private::DataExtractor &symtab_data, + lldb_private::DataExtractor &debug_data, + lldb_private::Section *rel_section); + + /// Loads the section name string table into m_shstr_data. Returns the + /// number of bytes constituting the table. + size_t GetSectionHeaderStringTable(); + + /// Utility method for looking up a section given its name. Returns the + /// index of the corresponding section or zero if no section with the given + /// name can be found (note that section indices are always 1 based, and so + /// section index 0 is never valid). + lldb::user_id_t GetSectionIndexByName(const char *name); + + // Returns the ID of the first section that has the given type. + lldb::user_id_t GetSectionIndexByType(unsigned type); + + /// Returns the section header with the given id or NULL. + const ELFSectionHeaderInfo *GetSectionHeaderByIndex(lldb::user_id_t id); + + /// @name ELF header dump routines + //@{ + static void DumpELFHeader(lldb_private::Stream *s, + const elf::ELFHeader &header); + + static void DumpELFHeader_e_ident_EI_DATA(lldb_private::Stream *s, + unsigned char ei_data); + + static void DumpELFHeader_e_type(lldb_private::Stream *s, + elf::elf_half e_type); + //@} + + /// @name ELF program header dump routines + //@{ + void DumpELFProgramHeaders(lldb_private::Stream *s); + + static void DumpELFProgramHeader(lldb_private::Stream *s, + const elf::ELFProgramHeader &ph); + + static void DumpELFProgramHeader_p_type(lldb_private::Stream *s, + elf::elf_word p_type); + + static void DumpELFProgramHeader_p_flags(lldb_private::Stream *s, + elf::elf_word p_flags); + //@} + + /// @name ELF section header dump routines + //@{ + void DumpELFSectionHeaders(lldb_private::Stream *s); + + static void DumpELFSectionHeader(lldb_private::Stream *s, + const ELFSectionHeaderInfo &sh); + + static void DumpELFSectionHeader_sh_type(lldb_private::Stream *s, + elf::elf_word sh_type); + + static void DumpELFSectionHeader_sh_flags(lldb_private::Stream *s, + elf::elf_xword sh_flags); + //@} + + /// ELF dependent module dump routine. + void DumpDependentModules(lldb_private::Stream *s); + + const elf::ELFDynamic *FindDynamicSymbol(unsigned tag); + + unsigned PLTRelocationType(); + + static lldb_private::Error + RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, + lldb_private::ArchSpec &arch_spec, + lldb_private::UUID &uuid); + + static lldb::offset_t SetData(const lldb_private::DataExtractor &src, + lldb_private::DataExtractor &dst, + lldb::offset_t offset, lldb::offset_t length); + + lldb::offset_t SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, + lldb::offset_t offset, + lldb::offset_t length); }; #endif // liblldb_ObjectFileELF_h_ diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index e3d83833371..b5b5e38e1f6 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -26,8 +26,8 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/UUID.h" -#include "lldb/Host/Host.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -41,322 +41,227 @@ using namespace lldb; using namespace lldb_private; - -void -ObjectFileJIT::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - CreateMemoryInstance, - GetModuleSpecifications); +void ObjectFileJIT::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); } -void -ObjectFileJIT::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); -} - - -lldb_private::ConstString -ObjectFileJIT::GetPluginNameStatic() -{ - static ConstString g_name("jit"); - return g_name; +void ObjectFileJIT::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -const char * -ObjectFileJIT::GetPluginDescriptionStatic() -{ - return "JIT code object file"; +lldb_private::ConstString ObjectFileJIT::GetPluginNameStatic() { + static ConstString g_name("jit"); + return g_name; } -ObjectFile * -ObjectFileJIT::CreateInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - lldb::offset_t data_offset, - const FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) -{ - // JIT'ed object file is backed by the ObjectFileJITDelegate, never - // read from a file - return NULL; +const char *ObjectFileJIT::GetPluginDescriptionStatic() { + return "JIT code object file"; } -ObjectFile * -ObjectFileJIT::CreateMemoryInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - const ProcessSP &process_sp, - lldb::addr_t header_addr) -{ - // JIT'ed object file is backed by the ObjectFileJITDelegate, never - // read from memory - return NULL; +ObjectFile *ObjectFileJIT::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + lldb::offset_t data_offset, + const FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + // JIT'ed object file is backed by the ObjectFileJITDelegate, never + // read from a file + return NULL; } -size_t -ObjectFileJIT::GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs) -{ - // JIT'ed object file can't be read from a file on disk - return 0; +ObjectFile *ObjectFileJIT::CreateMemoryInstance(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + lldb::addr_t header_addr) { + // JIT'ed object file is backed by the ObjectFileJITDelegate, never + // read from memory + return NULL; } -ObjectFileJIT::ObjectFileJIT (const lldb::ModuleSP &module_sp, - const ObjectFileJITDelegateSP &delegate_sp) : - ObjectFile(module_sp, NULL, 0, 0, DataBufferSP(), 0), - m_delegate_wp () -{ - if (delegate_sp) - { - m_delegate_wp = delegate_sp; - m_data.SetByteOrder(delegate_sp->GetByteOrder()); - m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize()); - } +size_t ObjectFileJIT::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + // JIT'ed object file can't be read from a file on disk + return 0; } -ObjectFileJIT::~ObjectFileJIT() -{ +ObjectFileJIT::ObjectFileJIT(const lldb::ModuleSP &module_sp, + const ObjectFileJITDelegateSP &delegate_sp) + : ObjectFile(module_sp, NULL, 0, 0, DataBufferSP(), 0), m_delegate_wp() { + if (delegate_sp) { + m_delegate_wp = delegate_sp; + m_data.SetByteOrder(delegate_sp->GetByteOrder()); + m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize()); + } } +ObjectFileJIT::~ObjectFileJIT() {} -bool -ObjectFileJIT::ParseHeader () -{ - // JIT code is never in a file, nor is it required to have any header - return false; +bool ObjectFileJIT::ParseHeader() { + // JIT code is never in a file, nor is it required to have any header + return false; } -ByteOrder -ObjectFileJIT::GetByteOrder () const -{ - return m_data.GetByteOrder(); -} +ByteOrder ObjectFileJIT::GetByteOrder() const { return m_data.GetByteOrder(); } -bool -ObjectFileJIT::IsExecutable() const -{ - return false; -} +bool ObjectFileJIT::IsExecutable() const { return false; } -uint32_t -ObjectFileJIT::GetAddressByteSize () const -{ - return m_data.GetAddressByteSize(); +uint32_t ObjectFileJIT::GetAddressByteSize() const { + return m_data.GetAddressByteSize(); } - -Symtab * -ObjectFileJIT::GetSymtab() -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - if (m_symtab_ap.get() == NULL) - { - m_symtab_ap.reset(new Symtab(this)); - std::lock_guard<std::recursive_mutex> symtab_guard(m_symtab_ap->GetMutex()); - ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); - if (delegate_sp) - delegate_sp->PopulateSymtab(this, *m_symtab_ap); - // TODO: get symbols from delegate - m_symtab_ap->Finalize (); - } +Symtab *ObjectFileJIT::GetSymtab() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_symtab_ap.get() == NULL) { + m_symtab_ap.reset(new Symtab(this)); + std::lock_guard<std::recursive_mutex> symtab_guard( + m_symtab_ap->GetMutex()); + ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); + if (delegate_sp) + delegate_sp->PopulateSymtab(this, *m_symtab_ap); + // TODO: get symbols from delegate + m_symtab_ap->Finalize(); } - return m_symtab_ap.get(); + } + return m_symtab_ap.get(); } -bool -ObjectFileJIT::IsStripped () -{ - return false; // JIT code that is in a module is never stripped +bool ObjectFileJIT::IsStripped() { + return false; // JIT code that is in a module is never stripped } -void -ObjectFileJIT::CreateSections (SectionList &unified_section_list) -{ - if (!m_sections_ap.get()) - { - m_sections_ap.reset(new SectionList()); - ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); - if (delegate_sp) - { - delegate_sp->PopulateSectionList(this, *m_sections_ap); - unified_section_list = *m_sections_ap; - } +void ObjectFileJIT::CreateSections(SectionList &unified_section_list) { + if (!m_sections_ap.get()) { + m_sections_ap.reset(new SectionList()); + ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); + if (delegate_sp) { + delegate_sp->PopulateSectionList(this, *m_sections_ap); + unified_section_list = *m_sections_ap; } + } } -void -ObjectFileJIT::Dump (Stream *s) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - s->Printf("%p: ", static_cast<void*>(this)); - s->Indent(); - s->PutCString("ObjectFileJIT"); - - ArchSpec arch; - if (GetArchitecture(arch)) - *s << ", arch = " << arch.GetArchitectureName(); - - s->EOL(); - - SectionList *sections = GetSectionList(); - if (sections) - sections->Dump(s, NULL, true, UINT32_MAX); - - if (m_symtab_ap.get()) - m_symtab_ap->Dump(s, NULL, eSortOrderNone); - } -} +void ObjectFileJIT::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + s->Printf("%p: ", static_cast<void *>(this)); + s->Indent(); + s->PutCString("ObjectFileJIT"); -bool -ObjectFileJIT::GetUUID (lldb_private::UUID* uuid) -{ - // TODO: maybe get from delegate, not needed for first pass - return false; -} + ArchSpec arch; + if (GetArchitecture(arch)) + *s << ", arch = " << arch.GetArchitectureName(); + s->EOL(); -uint32_t -ObjectFileJIT::GetDependentModules (FileSpecList& files) -{ - // JIT modules don't have dependencies, but they could - // if external functions are called and we know where they are - files.Clear(); - return 0; -} + SectionList *sections = GetSectionList(); + if (sections) + sections->Dump(s, NULL, true, UINT32_MAX); -lldb_private::Address -ObjectFileJIT::GetEntryPointAddress () -{ - return Address(); + if (m_symtab_ap.get()) + m_symtab_ap->Dump(s, NULL, eSortOrderNone); + } } -lldb_private::Address -ObjectFileJIT::GetHeaderAddress () -{ - return Address(); +bool ObjectFileJIT::GetUUID(lldb_private::UUID *uuid) { + // TODO: maybe get from delegate, not needed for first pass + return false; } - - -ObjectFile::Type -ObjectFileJIT::CalculateType() -{ - return eTypeJIT; +uint32_t ObjectFileJIT::GetDependentModules(FileSpecList &files) { + // JIT modules don't have dependencies, but they could + // if external functions are called and we know where they are + files.Clear(); + return 0; } -ObjectFile::Strata -ObjectFileJIT::CalculateStrata() -{ - return eStrataJIT; +lldb_private::Address ObjectFileJIT::GetEntryPointAddress() { + return Address(); } +lldb_private::Address ObjectFileJIT::GetHeaderAddress() { return Address(); } + +ObjectFile::Type ObjectFileJIT::CalculateType() { return eTypeJIT; } + +ObjectFile::Strata ObjectFileJIT::CalculateStrata() { return eStrataJIT; } -bool -ObjectFileJIT::GetArchitecture (ArchSpec &arch) -{ - ObjectFileJITDelegateSP delegate_sp (m_delegate_wp.lock()); - if (delegate_sp) - return delegate_sp->GetArchitecture(arch); - return false; +bool ObjectFileJIT::GetArchitecture(ArchSpec &arch) { + ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); + if (delegate_sp) + return delegate_sp->GetArchitecture(arch); + return false; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -ObjectFileJIT::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ObjectFileJIT::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ObjectFileJIT::GetPluginVersion() -{ - return 1; -} - - -bool -ObjectFileJIT::SetLoadAddress (Target &target, - lldb::addr_t value, - bool value_is_offset) -{ - size_t num_loaded_sections = 0; - SectionList *section_list = GetSectionList (); - if (section_list) - { - const size_t num_sections = section_list->GetSize(); - // "value" is an offset to apply to each top level segment - for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) - { - // Iterate through the object file sections to find all - // of the sections that size on disk (to avoid __PAGEZERO) - // and load them - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - if (section_sp && - section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false) - { - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) - ++num_loaded_sections; - } - } +uint32_t ObjectFileJIT::GetPluginVersion() { return 1; } + +bool ObjectFileJIT::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + // "value" is an offset to apply to each top level segment + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all + // of the sections that size on disk (to avoid __PAGEZERO) + // and load them + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && section_sp->GetFileSize() > 0 && + section_sp->IsThreadSpecific() == false) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } } - return num_loaded_sections > 0; + } + return num_loaded_sections > 0; } - -size_t -ObjectFileJIT::ReadSectionData (const lldb_private::Section *section, - lldb::offset_t section_offset, - void *dst, - size_t dst_len) const -{ - lldb::offset_t file_size = section->GetFileSize(); - if (section_offset < file_size) - { - size_t src_len = file_size - section_offset; - if (src_len > dst_len) - src_len = dst_len; - const uint8_t *src = ((uint8_t *)(uintptr_t)section->GetFileOffset()) + section_offset; - - memcpy (dst, src, src_len); - return src_len; - } - return 0; +size_t ObjectFileJIT::ReadSectionData(const lldb_private::Section *section, + lldb::offset_t section_offset, void *dst, + size_t dst_len) const { + lldb::offset_t file_size = section->GetFileSize(); + if (section_offset < file_size) { + size_t src_len = file_size - section_offset; + if (src_len > dst_len) + src_len = dst_len; + const uint8_t *src = + ((uint8_t *)(uintptr_t)section->GetFileOffset()) + section_offset; + + memcpy(dst, src, src_len); + return src_len; + } + return 0; } -size_t -ObjectFileJIT::ReadSectionData (const lldb_private::Section *section, - lldb_private::DataExtractor& section_data) const -{ - if (section->GetFileSize()) - { - const void *src = (void *)(uintptr_t)section->GetFileOffset(); - - DataBufferSP data_sp (new lldb_private::DataBufferHeap(src, section->GetFileSize())); - if (data_sp) - { - section_data.SetData (data_sp, 0, data_sp->GetByteSize()); - section_data.SetByteOrder (GetByteOrder()); - section_data.SetAddressByteSize (GetAddressByteSize()); - return section_data.GetByteSize(); - } +size_t ObjectFileJIT::ReadSectionData( + const lldb_private::Section *section, + lldb_private::DataExtractor §ion_data) const { + if (section->GetFileSize()) { + const void *src = (void *)(uintptr_t)section->GetFileOffset(); + + DataBufferSP data_sp( + new lldb_private::DataBufferHeap(src, section->GetFileSize())); + if (data_sp) { + section_data.SetData(data_sp, 0, data_sp->GetByteSize()); + section_data.SetByteOrder(GetByteOrder()); + section_data.SetAddressByteSize(GetAddressByteSize()); + return section_data.GetByteSize(); } - section_data.Clear(); - return 0; + } + section_data.Clear(); + return 0; } - diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index 39dbb3fb047..a211645d5d8 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -21,126 +21,93 @@ // This class needs to be hidden as eventually belongs in a plugin that // will export the ObjectFile protocol //---------------------------------------------------------------------- -class ObjectFileJIT : - public lldb_private::ObjectFile -{ +class ObjectFileJIT : public lldb_private::ObjectFile { public: - ObjectFileJIT(const lldb::ModuleSP &module_sp, - const lldb::ObjectFileJITDelegateSP &delegate_sp); - - ~ObjectFileJIT() override; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - static lldb_private::ObjectFile * - CreateInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length); - - static lldb_private::ObjectFile * - CreateMemoryInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - static size_t - GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs); - - //------------------------------------------------------------------ - // Member Functions - //------------------------------------------------------------------ - bool - ParseHeader() override; - - bool - SetLoadAddress(lldb_private::Target &target, - lldb::addr_t value, - bool value_is_offset) override; - - lldb::ByteOrder - GetByteOrder() const override; - - bool - IsExecutable() const override; - - uint32_t - GetAddressByteSize() const override; - - lldb_private::Symtab * - GetSymtab() override; - - bool - IsStripped() override; - - void - CreateSections(lldb_private::SectionList &unified_section_list) override; - - void - Dump(lldb_private::Stream *s) override; - - bool - GetArchitecture(lldb_private::ArchSpec &arch) override; - - bool - GetUUID(lldb_private::UUID* uuid) override; - - uint32_t - GetDependentModules(lldb_private::FileSpecList& files) override; - - size_t - ReadSectionData(const lldb_private::Section *section, - lldb::offset_t section_offset, - void *dst, - size_t dst_len) const override; - - size_t - ReadSectionData(const lldb_private::Section *section, - lldb_private::DataExtractor& section_data) const override; - - lldb_private::Address - GetEntryPointAddress() override; - - lldb_private::Address - GetHeaderAddress() override; - - ObjectFile::Type - CalculateType() override; - - ObjectFile::Strata - CalculateStrata() override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; + ObjectFileJIT(const lldb::ModuleSP &module_sp, + const lldb::ObjectFileJITDelegateSP &delegate_sp); + + ~ObjectFileJIT() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + //------------------------------------------------------------------ + // Member Functions + //------------------------------------------------------------------ + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb_private::Symtab *GetSymtab() override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + bool GetArchitecture(lldb_private::ArchSpec &arch) override; + + bool GetUUID(lldb_private::UUID *uuid) override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + size_t ReadSectionData(const lldb_private::Section *section, + lldb::offset_t section_offset, void *dst, + size_t dst_len) const override; + + size_t + ReadSectionData(const lldb_private::Section *section, + lldb_private::DataExtractor §ion_data) const override; + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetHeaderAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; protected: - lldb::ObjectFileJITDelegateWP m_delegate_wp; + lldb::ObjectFileJITDelegateWP m_delegate_wp; }; #endif // liblldb_ObjectFileJIT_h_ diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 2f34c19048b..69ff3512ce3 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -10,9 +10,13 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringRef.h" // Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" +#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" +#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" +#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Debugger.h" @@ -28,8 +32,8 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/UUID.h" -#include "lldb/Host/Host.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" @@ -40,16 +44,13 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadList.h" -#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" -#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" -#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" -#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" #include "lldb/Utility/SafeMachO.h" #include "ObjectFileMachO.h" -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) // GetLLDBSharedCacheUUID() needs to call dlsym() #include <dlfcn.h> #endif @@ -66,3872 +67,2963 @@ using namespace llvm::MachO; // Some structure definitions needed for parsing the dyld shared cache files // found on iOS devices. -struct lldb_copy_dyld_cache_header_v1 -{ - char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc. - uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info - uint32_t mappingCount; // number of dyld_cache_mapping_info entries - uint32_t imagesOffset; - uint32_t imagesCount; - uint64_t dyldBaseAddress; - uint64_t codeSignatureOffset; - uint64_t codeSignatureSize; - uint64_t slideInfoOffset; - uint64_t slideInfoSize; - uint64_t localSymbolsOffset; - uint64_t localSymbolsSize; - uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13 and later +struct lldb_copy_dyld_cache_header_v1 { + char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc. + uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info + uint32_t mappingCount; // number of dyld_cache_mapping_info entries + uint32_t imagesOffset; + uint32_t imagesCount; + uint64_t dyldBaseAddress; + uint64_t codeSignatureOffset; + uint64_t codeSignatureSize; + uint64_t slideInfoOffset; + uint64_t slideInfoSize; + uint64_t localSymbolsOffset; + uint64_t localSymbolsSize; + uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13 + // and later }; -struct lldb_copy_dyld_cache_mapping_info -{ - uint64_t address; - uint64_t size; - uint64_t fileOffset; - uint32_t maxProt; - uint32_t initProt; +struct lldb_copy_dyld_cache_mapping_info { + uint64_t address; + uint64_t size; + uint64_t fileOffset; + uint32_t maxProt; + uint32_t initProt; }; -struct lldb_copy_dyld_cache_local_symbols_info -{ - uint32_t nlistOffset; - uint32_t nlistCount; - uint32_t stringsOffset; - uint32_t stringsSize; - uint32_t entriesOffset; - uint32_t entriesCount; +struct lldb_copy_dyld_cache_local_symbols_info { + uint32_t nlistOffset; + uint32_t nlistCount; + uint32_t stringsOffset; + uint32_t stringsSize; + uint32_t entriesOffset; + uint32_t entriesCount; }; -struct lldb_copy_dyld_cache_local_symbols_entry -{ - uint32_t dylibOffset; - uint32_t nlistStartIndex; - uint32_t nlistCount; +struct lldb_copy_dyld_cache_local_symbols_entry { + uint32_t dylibOffset; + uint32_t nlistStartIndex; + uint32_t nlistCount; }; - -class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64 -{ +class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64 { public: - RegisterContextDarwin_x86_64_Mach (lldb_private::Thread &thread, const DataExtractor &data) : - RegisterContextDarwin_x86_64 (thread, 0) - { - SetRegisterDataFrom_LC_THREAD (data); - } + RegisterContextDarwin_x86_64_Mach(lldb_private::Thread &thread, + const DataExtractor &data) + : RegisterContextDarwin_x86_64(thread, 0) { + SetRegisterDataFrom_LC_THREAD(data); + } - void - InvalidateAllRegisters() override - { - // Do nothing... registers are always valid... - } - - void - SetRegisterDataFrom_LC_THREAD (const DataExtractor &data) - { - lldb::offset_t offset = 0; - SetError (GPRRegSet, Read, -1); - SetError (FPURegSet, Read, -1); - SetError (EXCRegSet, Read, -1); - bool done = false; - - while (!done) - { - int flavor = data.GetU32 (&offset); - if (flavor == 0) - done = true; - else - { - uint32_t i; - uint32_t count = data.GetU32 (&offset); - switch (flavor) - { - case GPRRegSet: - for (i=0; i<count; ++i) - (&gpr.rax)[i] = data.GetU64(&offset); - SetError (GPRRegSet, Read, 0); - done = true; + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } - break; - case FPURegSet: - // TODO: fill in FPU regs.... - //SetError (FPURegSet, Read, -1); - done = true; - - break; - case EXCRegSet: - exc.trapno = data.GetU32(&offset); - exc.err = data.GetU32(&offset); - exc.faultvaddr = data.GetU64(&offset); - SetError (EXCRegSet, Read, 0); - done = true; - break; - case 7: - case 8: - case 9: - // fancy flavors that encapsulate of the above - // flavors... - break; + void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { + lldb::offset_t offset = 0; + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + bool done = false; + + while (!done) { + int flavor = data.GetU32(&offset); + if (flavor == 0) + done = true; + else { + uint32_t i; + uint32_t count = data.GetU32(&offset); + switch (flavor) { + case GPRRegSet: + for (i = 0; i < count; ++i) + (&gpr.rax)[i] = data.GetU64(&offset); + SetError(GPRRegSet, Read, 0); + done = true; + + break; + case FPURegSet: + // TODO: fill in FPU regs.... + // SetError (FPURegSet, Read, -1); + done = true; + + break; + case EXCRegSet: + exc.trapno = data.GetU32(&offset); + exc.err = data.GetU32(&offset); + exc.faultvaddr = data.GetU64(&offset); + SetError(EXCRegSet, Read, 0); + done = true; + break; + case 7: + case 8: + case 9: + // fancy flavors that encapsulate of the above + // flavors... + break; - default: - done = true; - break; - } - } + default: + done = true; + break; } + } } - - static size_t - WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); - if (reg_info == NULL) - reg_info = reg_ctx->GetRegisterInfoByName(alt_name); - if (reg_info) - { - lldb_private::RegisterValue reg_value; - if (reg_ctx->ReadRegister(reg_info, reg_value)) - { - if (reg_info->byte_size >= reg_byte_size) - data.Write(reg_value.GetBytes(), reg_byte_size); - else - { - data.Write(reg_value.GetBytes(), reg_info->byte_size); - for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i) - data.PutChar(0); - } - return reg_byte_size; - } - } - // Just write zeros if all else fails - for (size_t i=0; i<reg_byte_size; ++ i) + } + + static size_t WriteRegister(RegisterContext *reg_ctx, const char *name, + const char *alt_name, size_t reg_byte_size, + Stream &data) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); + if (reg_info == NULL) + reg_info = reg_ctx->GetRegisterInfoByName(alt_name); + if (reg_info) { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (reg_info->byte_size >= reg_byte_size) + data.Write(reg_value.GetBytes(), reg_byte_size); + else { + data.Write(reg_value.GetBytes(), reg_info->byte_size); + for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n; + ++i) data.PutChar(0); + } return reg_byte_size; + } } - - static bool - Create_LC_THREAD (Thread *thread, Stream &data) - { - RegisterContextSP reg_ctx_sp (thread->GetRegisterContext()); - if (reg_ctx_sp) - { - RegisterContext *reg_ctx = reg_ctx_sp.get(); - - data.PutHex32 (GPRRegSet); // Flavor - data.PutHex32 (GPRWordCount); - WriteRegister (reg_ctx, "rax", NULL, 8, data); - WriteRegister (reg_ctx, "rbx", NULL, 8, data); - WriteRegister (reg_ctx, "rcx", NULL, 8, data); - WriteRegister (reg_ctx, "rdx", NULL, 8, data); - WriteRegister (reg_ctx, "rdi", NULL, 8, data); - WriteRegister (reg_ctx, "rsi", NULL, 8, data); - WriteRegister (reg_ctx, "rbp", NULL, 8, data); - WriteRegister (reg_ctx, "rsp", NULL, 8, data); - WriteRegister (reg_ctx, "r8", NULL, 8, data); - WriteRegister (reg_ctx, "r9", NULL, 8, data); - WriteRegister (reg_ctx, "r10", NULL, 8, data); - WriteRegister (reg_ctx, "r11", NULL, 8, data); - WriteRegister (reg_ctx, "r12", NULL, 8, data); - WriteRegister (reg_ctx, "r13", NULL, 8, data); - WriteRegister (reg_ctx, "r14", NULL, 8, data); - WriteRegister (reg_ctx, "r15", NULL, 8, data); - WriteRegister (reg_ctx, "rip", NULL, 8, data); - WriteRegister (reg_ctx, "rflags", NULL, 8, data); - WriteRegister (reg_ctx, "cs", NULL, 8, data); - WriteRegister (reg_ctx, "fs", NULL, 8, data); - WriteRegister (reg_ctx, "gs", NULL, 8, data); - -// // Write out the FPU registers -// const size_t fpu_byte_size = sizeof(FPU); -// size_t bytes_written = 0; -// data.PutHex32 (FPURegSet); -// data.PutHex32 (fpu_byte_size/sizeof(uint64_t)); -// bytes_written += data.PutHex32(0); // uint32_t pad[0] -// bytes_written += data.PutHex32(0); // uint32_t pad[1] -// bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, data); // uint16_t fcw; // "fctrl" -// bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, data); // uint16_t fsw; // "fstat" -// bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, data); // uint8_t ftw; // "ftag" -// bytes_written += data.PutHex8 (0); // uint8_t pad1; -// bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, data); // uint16_t fop; // "fop" -// bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, data); // uint32_t ip; // "fioff" -// bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, data); // uint16_t cs; // "fiseg" -// bytes_written += data.PutHex16 (0); // uint16_t pad2; -// bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, data); // uint32_t dp; // "fooff" -// bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, data); // uint16_t ds; // "foseg" -// bytes_written += data.PutHex16 (0); // uint16_t pad3; -// bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, data); // uint32_t mxcsr; -// bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, 4, data);// uint32_t mxcsrmask; -// bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, sizeof(MMSReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, sizeof(XMMReg), data); -// bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, sizeof(XMMReg), data); -// -// // Fill rest with zeros -// for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++ i) -// data.PutChar(0); - - // Write out the EXC registers - data.PutHex32 (EXCRegSet); - data.PutHex32 (EXCWordCount); - WriteRegister (reg_ctx, "trapno", NULL, 4, data); - WriteRegister (reg_ctx, "err", NULL, 4, data); - WriteRegister (reg_ctx, "faultvaddr", NULL, 8, data); - return true; - } - return false; + // Just write zeros if all else fails + for (size_t i = 0; i < reg_byte_size; ++i) + data.PutChar(0); + return reg_byte_size; + } + + static bool Create_LC_THREAD(Thread *thread, Stream &data) { + RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); + if (reg_ctx_sp) { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32(GPRRegSet); // Flavor + data.PutHex32(GPRWordCount); + WriteRegister(reg_ctx, "rax", NULL, 8, data); + WriteRegister(reg_ctx, "rbx", NULL, 8, data); + WriteRegister(reg_ctx, "rcx", NULL, 8, data); + WriteRegister(reg_ctx, "rdx", NULL, 8, data); + WriteRegister(reg_ctx, "rdi", NULL, 8, data); + WriteRegister(reg_ctx, "rsi", NULL, 8, data); + WriteRegister(reg_ctx, "rbp", NULL, 8, data); + WriteRegister(reg_ctx, "rsp", NULL, 8, data); + WriteRegister(reg_ctx, "r8", NULL, 8, data); + WriteRegister(reg_ctx, "r9", NULL, 8, data); + WriteRegister(reg_ctx, "r10", NULL, 8, data); + WriteRegister(reg_ctx, "r11", NULL, 8, data); + WriteRegister(reg_ctx, "r12", NULL, 8, data); + WriteRegister(reg_ctx, "r13", NULL, 8, data); + WriteRegister(reg_ctx, "r14", NULL, 8, data); + WriteRegister(reg_ctx, "r15", NULL, 8, data); + WriteRegister(reg_ctx, "rip", NULL, 8, data); + WriteRegister(reg_ctx, "rflags", NULL, 8, data); + WriteRegister(reg_ctx, "cs", NULL, 8, data); + WriteRegister(reg_ctx, "fs", NULL, 8, data); + WriteRegister(reg_ctx, "gs", NULL, 8, data); + + // // Write out the FPU registers + // const size_t fpu_byte_size = sizeof(FPU); + // size_t bytes_written = 0; + // data.PutHex32 (FPURegSet); + // data.PutHex32 (fpu_byte_size/sizeof(uint64_t)); + // bytes_written += data.PutHex32(0); // uint32_t pad[0] + // bytes_written += data.PutHex32(0); // uint32_t pad[1] + // bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, + // data); // uint16_t fcw; // "fctrl" + // bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, + // data); // uint16_t fsw; // "fstat" + // bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, + // data); // uint8_t ftw; // "ftag" + // bytes_written += data.PutHex8 (0); // uint8_t pad1; + // bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, + // data); // uint16_t fop; // "fop" + // bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, + // data); // uint32_t ip; // "fioff" + // bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, + // data); // uint16_t cs; // "fiseg" + // bytes_written += data.PutHex16 (0); // uint16_t pad2; + // bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, + // data); // uint32_t dp; // "fooff" + // bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, + // data); // uint16_t ds; // "foseg" + // bytes_written += data.PutHex16 (0); // uint16_t pad3; + // bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, + // data); // uint32_t mxcsr; + // bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, + // 4, data);// uint32_t mxcsrmask; + // bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, + // sizeof(MMSReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, + // sizeof(XMMReg), data); + // bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, + // sizeof(XMMReg), data); + // + // // Fill rest with zeros + // for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++ + // i) + // data.PutChar(0); + + // Write out the EXC registers + data.PutHex32(EXCRegSet); + data.PutHex32(EXCWordCount); + WriteRegister(reg_ctx, "trapno", NULL, 4, data); + WriteRegister(reg_ctx, "err", NULL, 4, data); + WriteRegister(reg_ctx, "faultvaddr", NULL, 8, data); + return true; } + return false; + } protected: - int - DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override - { - return 0; - } + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; } - int - DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override - { - return 0; - } + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; } - int - DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override - { - return 0; - } + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; } - int - DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override - { - return 0; - } + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { + return 0; + } - int - DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override - { - return 0; - } + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { + return 0; + } - int - DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override - { - return 0; - } + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { + return 0; + } }; -class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386 -{ +class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386 { public: - RegisterContextDarwin_i386_Mach (lldb_private::Thread &thread, const DataExtractor &data) : - RegisterContextDarwin_i386 (thread, 0) - { - SetRegisterDataFrom_LC_THREAD (data); - } - - void - InvalidateAllRegisters() override - { - // Do nothing... registers are always valid... - } + RegisterContextDarwin_i386_Mach(lldb_private::Thread &thread, + const DataExtractor &data) + : RegisterContextDarwin_i386(thread, 0) { + SetRegisterDataFrom_LC_THREAD(data); + } - void - SetRegisterDataFrom_LC_THREAD (const DataExtractor &data) - { - lldb::offset_t offset = 0; - SetError (GPRRegSet, Read, -1); - SetError (FPURegSet, Read, -1); - SetError (EXCRegSet, Read, -1); - bool done = false; - - while (!done) - { - int flavor = data.GetU32 (&offset); - if (flavor == 0) - done = true; - else - { - uint32_t i; - uint32_t count = data.GetU32 (&offset); - switch (flavor) - { - case GPRRegSet: - for (i=0; i<count; ++i) - (&gpr.eax)[i] = data.GetU32(&offset); - SetError (GPRRegSet, Read, 0); - done = true; - - break; - case FPURegSet: - // TODO: fill in FPU regs.... - //SetError (FPURegSet, Read, -1); - done = true; + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } - break; - case EXCRegSet: - exc.trapno = data.GetU32(&offset); - exc.err = data.GetU32(&offset); - exc.faultvaddr = data.GetU32(&offset); - SetError (EXCRegSet, Read, 0); - done = true; - break; - case 7: - case 8: - case 9: - // fancy flavors that encapsulate of the above - // flavors... - break; + void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { + lldb::offset_t offset = 0; + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + bool done = false; + + while (!done) { + int flavor = data.GetU32(&offset); + if (flavor == 0) + done = true; + else { + uint32_t i; + uint32_t count = data.GetU32(&offset); + switch (flavor) { + case GPRRegSet: + for (i = 0; i < count; ++i) + (&gpr.eax)[i] = data.GetU32(&offset); + SetError(GPRRegSet, Read, 0); + done = true; + + break; + case FPURegSet: + // TODO: fill in FPU regs.... + // SetError (FPURegSet, Read, -1); + done = true; + + break; + case EXCRegSet: + exc.trapno = data.GetU32(&offset); + exc.err = data.GetU32(&offset); + exc.faultvaddr = data.GetU32(&offset); + SetError(EXCRegSet, Read, 0); + done = true; + break; + case 7: + case 8: + case 9: + // fancy flavors that encapsulate of the above + // flavors... + break; - default: - done = true; - break; - } - } + default: + done = true; + break; } + } } - - static size_t - WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); - if (reg_info == NULL) - reg_info = reg_ctx->GetRegisterInfoByName(alt_name); - if (reg_info) - { - lldb_private::RegisterValue reg_value; - if (reg_ctx->ReadRegister(reg_info, reg_value)) - { - if (reg_info->byte_size >= reg_byte_size) - data.Write(reg_value.GetBytes(), reg_byte_size); - else - { - data.Write(reg_value.GetBytes(), reg_info->byte_size); - for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i) - data.PutChar(0); - } - return reg_byte_size; - } - } - // Just write zeros if all else fails - for (size_t i=0; i<reg_byte_size; ++ i) + } + + static size_t WriteRegister(RegisterContext *reg_ctx, const char *name, + const char *alt_name, size_t reg_byte_size, + Stream &data) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); + if (reg_info == NULL) + reg_info = reg_ctx->GetRegisterInfoByName(alt_name); + if (reg_info) { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (reg_info->byte_size >= reg_byte_size) + data.Write(reg_value.GetBytes(), reg_byte_size); + else { + data.Write(reg_value.GetBytes(), reg_info->byte_size); + for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n; + ++i) data.PutChar(0); + } return reg_byte_size; + } } - - static bool - Create_LC_THREAD (Thread *thread, Stream &data) - { - RegisterContextSP reg_ctx_sp (thread->GetRegisterContext()); - if (reg_ctx_sp) - { - RegisterContext *reg_ctx = reg_ctx_sp.get(); - - data.PutHex32 (GPRRegSet); // Flavor - data.PutHex32 (GPRWordCount); - WriteRegister (reg_ctx, "eax", NULL, 4, data); - WriteRegister (reg_ctx, "ebx", NULL, 4, data); - WriteRegister (reg_ctx, "ecx", NULL, 4, data); - WriteRegister (reg_ctx, "edx", NULL, 4, data); - WriteRegister (reg_ctx, "edi", NULL, 4, data); - WriteRegister (reg_ctx, "esi", NULL, 4, data); - WriteRegister (reg_ctx, "ebp", NULL, 4, data); - WriteRegister (reg_ctx, "esp", NULL, 4, data); - WriteRegister (reg_ctx, "ss", NULL, 4, data); - WriteRegister (reg_ctx, "eflags", NULL, 4, data); - WriteRegister (reg_ctx, "eip", NULL, 4, data); - WriteRegister (reg_ctx, "cs", NULL, 4, data); - WriteRegister (reg_ctx, "ds", NULL, 4, data); - WriteRegister (reg_ctx, "es", NULL, 4, data); - WriteRegister (reg_ctx, "fs", NULL, 4, data); - WriteRegister (reg_ctx, "gs", NULL, 4, data); - - // Write out the EXC registers - data.PutHex32 (EXCRegSet); - data.PutHex32 (EXCWordCount); - WriteRegister (reg_ctx, "trapno", NULL, 4, data); - WriteRegister (reg_ctx, "err", NULL, 4, data); - WriteRegister (reg_ctx, "faultvaddr", NULL, 4, data); - return true; - } - return false; + // Just write zeros if all else fails + for (size_t i = 0; i < reg_byte_size; ++i) + data.PutChar(0); + return reg_byte_size; + } + + static bool Create_LC_THREAD(Thread *thread, Stream &data) { + RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); + if (reg_ctx_sp) { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32(GPRRegSet); // Flavor + data.PutHex32(GPRWordCount); + WriteRegister(reg_ctx, "eax", NULL, 4, data); + WriteRegister(reg_ctx, "ebx", NULL, 4, data); + WriteRegister(reg_ctx, "ecx", NULL, 4, data); + WriteRegister(reg_ctx, "edx", NULL, 4, data); + WriteRegister(reg_ctx, "edi", NULL, 4, data); + WriteRegister(reg_ctx, "esi", NULL, 4, data); + WriteRegister(reg_ctx, "ebp", NULL, 4, data); + WriteRegister(reg_ctx, "esp", NULL, 4, data); + WriteRegister(reg_ctx, "ss", NULL, 4, data); + WriteRegister(reg_ctx, "eflags", NULL, 4, data); + WriteRegister(reg_ctx, "eip", NULL, 4, data); + WriteRegister(reg_ctx, "cs", NULL, 4, data); + WriteRegister(reg_ctx, "ds", NULL, 4, data); + WriteRegister(reg_ctx, "es", NULL, 4, data); + WriteRegister(reg_ctx, "fs", NULL, 4, data); + WriteRegister(reg_ctx, "gs", NULL, 4, data); + + // Write out the EXC registers + data.PutHex32(EXCRegSet); + data.PutHex32(EXCWordCount); + WriteRegister(reg_ctx, "trapno", NULL, 4, data); + WriteRegister(reg_ctx, "err", NULL, 4, data); + WriteRegister(reg_ctx, "faultvaddr", NULL, 4, data); + return true; } + return false; + } protected: - int - DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override - { - return 0; - } + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; } - int - DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override - { - return 0; - } + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; } - int - DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override - { - return 0; - } + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; } - int - DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override - { - return 0; - } + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { + return 0; + } - int - DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override - { - return 0; - } + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { + return 0; + } - int - DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override - { - return 0; - } + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { + return 0; + } }; -class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm -{ +class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm { public: - RegisterContextDarwin_arm_Mach (lldb_private::Thread &thread, const DataExtractor &data) : - RegisterContextDarwin_arm (thread, 0) - { - SetRegisterDataFrom_LC_THREAD (data); - } - - void - InvalidateAllRegisters() override - { - // Do nothing... registers are always valid... - } - - void - SetRegisterDataFrom_LC_THREAD (const DataExtractor &data) - { - lldb::offset_t offset = 0; - SetError (GPRRegSet, Read, -1); - SetError (FPURegSet, Read, -1); - SetError (EXCRegSet, Read, -1); - bool done = false; - - while (!done) - { - int flavor = data.GetU32 (&offset); - uint32_t count = data.GetU32 (&offset); - lldb::offset_t next_thread_state = offset + (count * 4); - switch (flavor) - { - case GPRAltRegSet: - case GPRRegSet: - for (uint32_t i=0; i<count; ++i) - { - gpr.r[i] = data.GetU32(&offset); - } - - // Note that gpr.cpsr is also copied by the above loop; this loop technically extends - // one element past the end of the gpr.r[] array. + RegisterContextDarwin_arm_Mach(lldb_private::Thread &thread, + const DataExtractor &data) + : RegisterContextDarwin_arm(thread, 0) { + SetRegisterDataFrom_LC_THREAD(data); + } - SetError (GPRRegSet, Read, 0); - offset = next_thread_state; - break; + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } - case FPURegSet: - { - uint8_t *fpu_reg_buf = (uint8_t*) &fpu.floats.s[0]; - const int fpu_reg_buf_size = sizeof (fpu.floats); - if (data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size) - { - offset += fpu_reg_buf_size; - fpu.fpscr = data.GetU32(&offset); - SetError (FPURegSet, Read, 0); - } - else - { - done = true; - } - } - offset = next_thread_state; - break; - - case EXCRegSet: - if (count == 3) - { - exc.exception = data.GetU32(&offset); - exc.fsr = data.GetU32(&offset); - exc.far = data.GetU32(&offset); - SetError (EXCRegSet, Read, 0); - } - done = true; - offset = next_thread_state; - break; - - // Unknown register set flavor, stop trying to parse. - default: - done = true; - } + void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { + lldb::offset_t offset = 0; + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + bool done = false; + + while (!done) { + int flavor = data.GetU32(&offset); + uint32_t count = data.GetU32(&offset); + lldb::offset_t next_thread_state = offset + (count * 4); + switch (flavor) { + case GPRAltRegSet: + case GPRRegSet: + for (uint32_t i = 0; i < count; ++i) { + gpr.r[i] = data.GetU32(&offset); } - } - static size_t - WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); - if (reg_info == NULL) - reg_info = reg_ctx->GetRegisterInfoByName(alt_name); - if (reg_info) - { - lldb_private::RegisterValue reg_value; - if (reg_ctx->ReadRegister(reg_info, reg_value)) - { - if (reg_info->byte_size >= reg_byte_size) - data.Write(reg_value.GetBytes(), reg_byte_size); - else - { - data.Write(reg_value.GetBytes(), reg_info->byte_size); - for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i) - data.PutChar(0); - } - return reg_byte_size; - } + // Note that gpr.cpsr is also copied by the above loop; this loop + // technically extends + // one element past the end of the gpr.r[] array. + + SetError(GPRRegSet, Read, 0); + offset = next_thread_state; + break; + + case FPURegSet: { + uint8_t *fpu_reg_buf = (uint8_t *)&fpu.floats.s[0]; + const int fpu_reg_buf_size = sizeof(fpu.floats); + if (data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle, + fpu_reg_buf) == fpu_reg_buf_size) { + offset += fpu_reg_buf_size; + fpu.fpscr = data.GetU32(&offset); + SetError(FPURegSet, Read, 0); + } else { + done = true; } - // Just write zeros if all else fails - for (size_t i=0; i<reg_byte_size; ++ i) + } + offset = next_thread_state; + break; + + case EXCRegSet: + if (count == 3) { + exc.exception = data.GetU32(&offset); + exc.fsr = data.GetU32(&offset); + exc.far = data.GetU32(&offset); + SetError(EXCRegSet, Read, 0); + } + done = true; + offset = next_thread_state; + break; + + // Unknown register set flavor, stop trying to parse. + default: + done = true; + } + } + } + + static size_t WriteRegister(RegisterContext *reg_ctx, const char *name, + const char *alt_name, size_t reg_byte_size, + Stream &data) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); + if (reg_info == NULL) + reg_info = reg_ctx->GetRegisterInfoByName(alt_name); + if (reg_info) { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (reg_info->byte_size >= reg_byte_size) + data.Write(reg_value.GetBytes(), reg_byte_size); + else { + data.Write(reg_value.GetBytes(), reg_info->byte_size); + for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n; + ++i) data.PutChar(0); + } return reg_byte_size; + } } - - static bool - Create_LC_THREAD (Thread *thread, Stream &data) - { - RegisterContextSP reg_ctx_sp (thread->GetRegisterContext()); - if (reg_ctx_sp) - { - RegisterContext *reg_ctx = reg_ctx_sp.get(); - - data.PutHex32 (GPRRegSet); // Flavor - data.PutHex32 (GPRWordCount); - WriteRegister (reg_ctx, "r0", NULL, 4, data); - WriteRegister (reg_ctx, "r1", NULL, 4, data); - WriteRegister (reg_ctx, "r2", NULL, 4, data); - WriteRegister (reg_ctx, "r3", NULL, 4, data); - WriteRegister (reg_ctx, "r4", NULL, 4, data); - WriteRegister (reg_ctx, "r5", NULL, 4, data); - WriteRegister (reg_ctx, "r6", NULL, 4, data); - WriteRegister (reg_ctx, "r7", NULL, 4, data); - WriteRegister (reg_ctx, "r8", NULL, 4, data); - WriteRegister (reg_ctx, "r9", NULL, 4, data); - WriteRegister (reg_ctx, "r10", NULL, 4, data); - WriteRegister (reg_ctx, "r11", NULL, 4, data); - WriteRegister (reg_ctx, "r12", NULL, 4, data); - WriteRegister (reg_ctx, "sp", NULL, 4, data); - WriteRegister (reg_ctx, "lr", NULL, 4, data); - WriteRegister (reg_ctx, "pc", NULL, 4, data); - WriteRegister (reg_ctx, "cpsr", NULL, 4, data); - - // Write out the EXC registers -// data.PutHex32 (EXCRegSet); -// data.PutHex32 (EXCWordCount); -// WriteRegister (reg_ctx, "exception", NULL, 4, data); -// WriteRegister (reg_ctx, "fsr", NULL, 4, data); -// WriteRegister (reg_ctx, "far", NULL, 4, data); - return true; - } - return false; + // Just write zeros if all else fails + for (size_t i = 0; i < reg_byte_size; ++i) + data.PutChar(0); + return reg_byte_size; + } + + static bool Create_LC_THREAD(Thread *thread, Stream &data) { + RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); + if (reg_ctx_sp) { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32(GPRRegSet); // Flavor + data.PutHex32(GPRWordCount); + WriteRegister(reg_ctx, "r0", NULL, 4, data); + WriteRegister(reg_ctx, "r1", NULL, 4, data); + WriteRegister(reg_ctx, "r2", NULL, 4, data); + WriteRegister(reg_ctx, "r3", NULL, 4, data); + WriteRegister(reg_ctx, "r4", NULL, 4, data); + WriteRegister(reg_ctx, "r5", NULL, 4, data); + WriteRegister(reg_ctx, "r6", NULL, 4, data); + WriteRegister(reg_ctx, "r7", NULL, 4, data); + WriteRegister(reg_ctx, "r8", NULL, 4, data); + WriteRegister(reg_ctx, "r9", NULL, 4, data); + WriteRegister(reg_ctx, "r10", NULL, 4, data); + WriteRegister(reg_ctx, "r11", NULL, 4, data); + WriteRegister(reg_ctx, "r12", NULL, 4, data); + WriteRegister(reg_ctx, "sp", NULL, 4, data); + WriteRegister(reg_ctx, "lr", NULL, 4, data); + WriteRegister(reg_ctx, "pc", NULL, 4, data); + WriteRegister(reg_ctx, "cpsr", NULL, 4, data); + + // Write out the EXC registers + // data.PutHex32 (EXCRegSet); + // data.PutHex32 (EXCWordCount); + // WriteRegister (reg_ctx, "exception", NULL, 4, data); + // WriteRegister (reg_ctx, "fsr", NULL, 4, data); + // WriteRegister (reg_ctx, "far", NULL, 4, data); + return true; } + return false; + } protected: - int - DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override - { - return -1; - } + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; } - int - DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override - { - return -1; - } + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; } - int - DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override - { - return -1; - } + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; } - int - DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override - { - return -1; - } + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; } - int - DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override - { - return 0; - } + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { + return 0; + } - int - DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override - { - return 0; - } + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { + return 0; + } - int - DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override - { - return 0; - } + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { + return 0; + } - int - DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override - { - return -1; - } + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override { + return -1; + } }; -class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 -{ +class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 { public: - RegisterContextDarwin_arm64_Mach (lldb_private::Thread &thread, const DataExtractor &data) : - RegisterContextDarwin_arm64 (thread, 0) - { - SetRegisterDataFrom_LC_THREAD (data); - } - - void - InvalidateAllRegisters() override - { - // Do nothing... registers are always valid... - } - - void - SetRegisterDataFrom_LC_THREAD (const DataExtractor &data) - { - lldb::offset_t offset = 0; - SetError (GPRRegSet, Read, -1); - SetError (FPURegSet, Read, -1); - SetError (EXCRegSet, Read, -1); - bool done = false; - while (!done) - { - int flavor = data.GetU32 (&offset); - uint32_t count = data.GetU32 (&offset); - lldb::offset_t next_thread_state = offset + (count * 4); - switch (flavor) - { - case GPRRegSet: - // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 32-bit register) - if (count >= (33 * 2) + 1) - { - for (uint32_t i=0; i<33; ++i) - gpr.x[i] = data.GetU64(&offset); - gpr.cpsr = data.GetU32(&offset); - SetError (GPRRegSet, Read, 0); - } - offset = next_thread_state; - break; - case FPURegSet: - { - uint8_t *fpu_reg_buf = (uint8_t*) &fpu.v[0]; - const int fpu_reg_buf_size = sizeof (fpu); - if (fpu_reg_buf_size == count - && data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size) - { - SetError (FPURegSet, Read, 0); - } - else - { - done = true; - } - } - offset = next_thread_state; - break; - case EXCRegSet: - if (count == 4) - { - exc.far = data.GetU64(&offset); - exc.esr = data.GetU32(&offset); - exc.exception = data.GetU32(&offset); - SetError (EXCRegSet, Read, 0); - } - offset = next_thread_state; - break; - default: - done = true; - break; - } - } - } + RegisterContextDarwin_arm64_Mach(lldb_private::Thread &thread, + const DataExtractor &data) + : RegisterContextDarwin_arm64(thread, 0) { + SetRegisterDataFrom_LC_THREAD(data); + } - static size_t - WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); - if (reg_info == NULL) - reg_info = reg_ctx->GetRegisterInfoByName(alt_name); - if (reg_info) - { - lldb_private::RegisterValue reg_value; - if (reg_ctx->ReadRegister(reg_info, reg_value)) - { - if (reg_info->byte_size >= reg_byte_size) - data.Write(reg_value.GetBytes(), reg_byte_size); - else - { - data.Write(reg_value.GetBytes(), reg_info->byte_size); - for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i) - data.PutChar(0); - } - return reg_byte_size; - } + void InvalidateAllRegisters() override { + // Do nothing... registers are always valid... + } + + void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { + lldb::offset_t offset = 0; + SetError(GPRRegSet, Read, -1); + SetError(FPURegSet, Read, -1); + SetError(EXCRegSet, Read, -1); + bool done = false; + while (!done) { + int flavor = data.GetU32(&offset); + uint32_t count = data.GetU32(&offset); + lldb::offset_t next_thread_state = offset + (count * 4); + switch (flavor) { + case GPRRegSet: + // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 + // 32-bit register) + if (count >= (33 * 2) + 1) { + for (uint32_t i = 0; i < 33; ++i) + gpr.x[i] = data.GetU64(&offset); + gpr.cpsr = data.GetU32(&offset); + SetError(GPRRegSet, Read, 0); + } + offset = next_thread_state; + break; + case FPURegSet: { + uint8_t *fpu_reg_buf = (uint8_t *)&fpu.v[0]; + const int fpu_reg_buf_size = sizeof(fpu); + if (fpu_reg_buf_size == count && + data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle, + fpu_reg_buf) == fpu_reg_buf_size) { + SetError(FPURegSet, Read, 0); + } else { + done = true; } - // Just write zeros if all else fails - for (size_t i=0; i<reg_byte_size; ++ i) + } + offset = next_thread_state; + break; + case EXCRegSet: + if (count == 4) { + exc.far = data.GetU64(&offset); + exc.esr = data.GetU32(&offset); + exc.exception = data.GetU32(&offset); + SetError(EXCRegSet, Read, 0); + } + offset = next_thread_state; + break; + default: + done = true; + break; + } + } + } + + static size_t WriteRegister(RegisterContext *reg_ctx, const char *name, + const char *alt_name, size_t reg_byte_size, + Stream &data) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); + if (reg_info == NULL) + reg_info = reg_ctx->GetRegisterInfoByName(alt_name); + if (reg_info) { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (reg_info->byte_size >= reg_byte_size) + data.Write(reg_value.GetBytes(), reg_byte_size); + else { + data.Write(reg_value.GetBytes(), reg_info->byte_size); + for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n; + ++i) data.PutChar(0); + } return reg_byte_size; + } } - - static bool - Create_LC_THREAD (Thread *thread, Stream &data) - { - RegisterContextSP reg_ctx_sp (thread->GetRegisterContext()); - if (reg_ctx_sp) - { - RegisterContext *reg_ctx = reg_ctx_sp.get(); - - data.PutHex32 (GPRRegSet); // Flavor - data.PutHex32 (GPRWordCount); - WriteRegister (reg_ctx, "x0", NULL, 8, data); - WriteRegister (reg_ctx, "x1", NULL, 8, data); - WriteRegister (reg_ctx, "x2", NULL, 8, data); - WriteRegister (reg_ctx, "x3", NULL, 8, data); - WriteRegister (reg_ctx, "x4", NULL, 8, data); - WriteRegister (reg_ctx, "x5", NULL, 8, data); - WriteRegister (reg_ctx, "x6", NULL, 8, data); - WriteRegister (reg_ctx, "x7", NULL, 8, data); - WriteRegister (reg_ctx, "x8", NULL, 8, data); - WriteRegister (reg_ctx, "x9", NULL, 8, data); - WriteRegister (reg_ctx, "x10", NULL, 8, data); - WriteRegister (reg_ctx, "x11", NULL, 8, data); - WriteRegister (reg_ctx, "x12", NULL, 8, data); - WriteRegister (reg_ctx, "x13", NULL, 8, data); - WriteRegister (reg_ctx, "x14", NULL, 8, data); - WriteRegister (reg_ctx, "x15", NULL, 8, data); - WriteRegister (reg_ctx, "x16", NULL, 8, data); - WriteRegister (reg_ctx, "x17", NULL, 8, data); - WriteRegister (reg_ctx, "x18", NULL, 8, data); - WriteRegister (reg_ctx, "x19", NULL, 8, data); - WriteRegister (reg_ctx, "x20", NULL, 8, data); - WriteRegister (reg_ctx, "x21", NULL, 8, data); - WriteRegister (reg_ctx, "x22", NULL, 8, data); - WriteRegister (reg_ctx, "x23", NULL, 8, data); - WriteRegister (reg_ctx, "x24", NULL, 8, data); - WriteRegister (reg_ctx, "x25", NULL, 8, data); - WriteRegister (reg_ctx, "x26", NULL, 8, data); - WriteRegister (reg_ctx, "x27", NULL, 8, data); - WriteRegister (reg_ctx, "x28", NULL, 8, data); - WriteRegister (reg_ctx, "fp", NULL, 8, data); - WriteRegister (reg_ctx, "lr", NULL, 8, data); - WriteRegister (reg_ctx, "sp", NULL, 8, data); - WriteRegister (reg_ctx, "pc", NULL, 8, data); - WriteRegister (reg_ctx, "cpsr", NULL, 4, data); - - // Write out the EXC registers -// data.PutHex32 (EXCRegSet); -// data.PutHex32 (EXCWordCount); -// WriteRegister (reg_ctx, "far", NULL, 8, data); -// WriteRegister (reg_ctx, "esr", NULL, 4, data); -// WriteRegister (reg_ctx, "exception", NULL, 4, data); - return true; - } - return false; + // Just write zeros if all else fails + for (size_t i = 0; i < reg_byte_size; ++i) + data.PutChar(0); + return reg_byte_size; + } + + static bool Create_LC_THREAD(Thread *thread, Stream &data) { + RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); + if (reg_ctx_sp) { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32(GPRRegSet); // Flavor + data.PutHex32(GPRWordCount); + WriteRegister(reg_ctx, "x0", NULL, 8, data); + WriteRegister(reg_ctx, "x1", NULL, 8, data); + WriteRegister(reg_ctx, "x2", NULL, 8, data); + WriteRegister(reg_ctx, "x3", NULL, 8, data); + WriteRegister(reg_ctx, "x4", NULL, 8, data); + WriteRegister(reg_ctx, "x5", NULL, 8, data); + WriteRegister(reg_ctx, "x6", NULL, 8, data); + WriteRegister(reg_ctx, "x7", NULL, 8, data); + WriteRegister(reg_ctx, "x8", NULL, 8, data); + WriteRegister(reg_ctx, "x9", NULL, 8, data); + WriteRegister(reg_ctx, "x10", NULL, 8, data); + WriteRegister(reg_ctx, "x11", NULL, 8, data); + WriteRegister(reg_ctx, "x12", NULL, 8, data); + WriteRegister(reg_ctx, "x13", NULL, 8, data); + WriteRegister(reg_ctx, "x14", NULL, 8, data); + WriteRegister(reg_ctx, "x15", NULL, 8, data); + WriteRegister(reg_ctx, "x16", NULL, 8, data); + WriteRegister(reg_ctx, "x17", NULL, 8, data); + WriteRegister(reg_ctx, "x18", NULL, 8, data); + WriteRegister(reg_ctx, "x19", NULL, 8, data); + WriteRegister(reg_ctx, "x20", NULL, 8, data); + WriteRegister(reg_ctx, "x21", NULL, 8, data); + WriteRegister(reg_ctx, "x22", NULL, 8, data); + WriteRegister(reg_ctx, "x23", NULL, 8, data); + WriteRegister(reg_ctx, "x24", NULL, 8, data); + WriteRegister(reg_ctx, "x25", NULL, 8, data); + WriteRegister(reg_ctx, "x26", NULL, 8, data); + WriteRegister(reg_ctx, "x27", NULL, 8, data); + WriteRegister(reg_ctx, "x28", NULL, 8, data); + WriteRegister(reg_ctx, "fp", NULL, 8, data); + WriteRegister(reg_ctx, "lr", NULL, 8, data); + WriteRegister(reg_ctx, "sp", NULL, 8, data); + WriteRegister(reg_ctx, "pc", NULL, 8, data); + WriteRegister(reg_ctx, "cpsr", NULL, 4, data); + + // Write out the EXC registers + // data.PutHex32 (EXCRegSet); + // data.PutHex32 (EXCWordCount); + // WriteRegister (reg_ctx, "far", NULL, 8, data); + // WriteRegister (reg_ctx, "esr", NULL, 4, data); + // WriteRegister (reg_ctx, "exception", NULL, 4, data); + return true; } + return false; + } protected: - int - DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override - { - return -1; - } - - int - DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override - { - return -1; - } - - int - DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override - { - return -1; - } + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; } - int - DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override - { - return -1; - } - - int - DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override - { - return 0; - } - - int - DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override - { - return 0; - } - - int - DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override - { - return 0; - } - - int - DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override - { - return -1; - } -}; + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; } -static uint32_t -MachHeaderSizeFromMagic(uint32_t magic) -{ - switch (magic) - { - case MH_MAGIC: - case MH_CIGAM: - return sizeof(struct mach_header); - - case MH_MAGIC_64: - case MH_CIGAM_64: - return sizeof(struct mach_header_64); - break; - - default: - break; - } + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; } + + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; } + + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { + return 0; + } + + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { return 0; + } + + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { + return 0; + } + + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override { + return -1; + } +}; + +static uint32_t MachHeaderSizeFromMagic(uint32_t magic) { + switch (magic) { + case MH_MAGIC: + case MH_CIGAM: + return sizeof(struct mach_header); + + case MH_MAGIC_64: + case MH_CIGAM_64: + return sizeof(struct mach_header_64); + break; + + default: + break; + } + return 0; } #define MACHO_NLIST_ARM_SYMBOL_IS_THUMB 0x0008 -void -ObjectFileMachO::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - CreateMemoryInstance, - GetModuleSpecifications, - SaveCore); +void ObjectFileMachO::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications, SaveCore); } -void -ObjectFileMachO::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void ObjectFileMachO::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -ObjectFileMachO::GetPluginNameStatic() -{ - static ConstString g_name("mach-o"); - return g_name; +lldb_private::ConstString ObjectFileMachO::GetPluginNameStatic() { + static ConstString g_name("mach-o"); + return g_name; } -const char * -ObjectFileMachO::GetPluginDescriptionStatic() -{ - return "Mach-o object file reader (32 and 64 bit)"; +const char *ObjectFileMachO::GetPluginDescriptionStatic() { + return "Mach-o object file reader (32 and 64 bit)"; } -ObjectFile * -ObjectFileMachO::CreateInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - lldb::offset_t data_offset, - const FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) -{ - if (!data_sp) - { - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - data_offset = 0; - } - - if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) - { - // Update the data to contain the entire file if it doesn't already - if (data_sp->GetByteSize() < length) - { - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - data_offset = 0; - } - std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, data_offset, file, file_offset, length)); - if (objfile_ap.get() && objfile_ap->ParseHeader()) - return objfile_ap.release(); +ObjectFile *ObjectFileMachO::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + lldb::offset_t data_offset, + const FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + data_offset = 0; + } + + if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) { + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) { + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + data_offset = 0; } - return NULL; + std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO( + module_sp, data_sp, data_offset, file, file_offset, length)); + if (objfile_ap.get() && objfile_ap->ParseHeader()) + return objfile_ap.release(); + } + return NULL; } -ObjectFile * -ObjectFileMachO::CreateMemoryInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - const ProcessSP &process_sp, - lldb::addr_t header_addr) -{ - if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) - { - std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, process_sp, header_addr)); - if (objfile_ap.get() && objfile_ap->ParseHeader()) - return objfile_ap.release(); - } - return NULL; +ObjectFile *ObjectFileMachO::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, + const ProcessSP &process_sp, lldb::addr_t header_addr) { + if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + std::unique_ptr<ObjectFile> objfile_ap( + new ObjectFileMachO(module_sp, data_sp, process_sp, header_addr)); + if (objfile_ap.get() && objfile_ap->ParseHeader()) + return objfile_ap.release(); + } + return NULL; } -size_t -ObjectFileMachO::GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs) -{ - const size_t initial_count = specs.GetSize(); - - if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) - { - DataExtractor data; +size_t ObjectFileMachO::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { + DataExtractor data; + data.SetData(data_sp); + llvm::MachO::mach_header header; + if (ParseHeader(data, &data_offset, header)) { + size_t header_and_load_cmds = + header.sizeofcmds + MachHeaderSizeFromMagic(header.magic); + if (header_and_load_cmds >= data_sp->GetByteSize()) { + data_sp = file.ReadFileContents(file_offset, header_and_load_cmds); data.SetData(data_sp); - llvm::MachO::mach_header header; - if (ParseHeader (data, &data_offset, header)) - { - size_t header_and_load_cmds = header.sizeofcmds + MachHeaderSizeFromMagic(header.magic); - if (header_and_load_cmds >= data_sp->GetByteSize()) - { - data_sp = file.ReadFileContents(file_offset, header_and_load_cmds); - data.SetData(data_sp); - data_offset = MachHeaderSizeFromMagic(header.magic); - } - if (data_sp) - { - ModuleSpec spec; - spec.GetFileSpec() = file; - spec.SetObjectOffset(file_offset); - spec.SetObjectSize(length); - - if (GetArchitecture (header, data, data_offset, spec.GetArchitecture())) - { - if (spec.GetArchitecture().IsValid()) - { - GetUUID (header, data, data_offset, spec.GetUUID()); - specs.Append(spec); - } - } - } + data_offset = MachHeaderSizeFromMagic(header.magic); + } + if (data_sp) { + ModuleSpec spec; + spec.GetFileSpec() = file; + spec.SetObjectOffset(file_offset); + spec.SetObjectSize(length); + + if (GetArchitecture(header, data, data_offset, + spec.GetArchitecture())) { + if (spec.GetArchitecture().IsValid()) { + GetUUID(header, data, data_offset, spec.GetUUID()); + specs.Append(spec); + } } + } } - return specs.GetSize() - initial_count; + } + return specs.GetSize() - initial_count; } -const ConstString & -ObjectFileMachO::GetSegmentNameTEXT() -{ - static ConstString g_segment_name_TEXT ("__TEXT"); - return g_segment_name_TEXT; +const ConstString &ObjectFileMachO::GetSegmentNameTEXT() { + static ConstString g_segment_name_TEXT("__TEXT"); + return g_segment_name_TEXT; } -const ConstString & -ObjectFileMachO::GetSegmentNameDATA() -{ - static ConstString g_segment_name_DATA ("__DATA"); - return g_segment_name_DATA; +const ConstString &ObjectFileMachO::GetSegmentNameDATA() { + static ConstString g_segment_name_DATA("__DATA"); + return g_segment_name_DATA; } -const ConstString & -ObjectFileMachO::GetSegmentNameDATA_DIRTY() -{ - static ConstString g_segment_name ("__DATA_DIRTY"); - return g_segment_name; +const ConstString &ObjectFileMachO::GetSegmentNameDATA_DIRTY() { + static ConstString g_segment_name("__DATA_DIRTY"); + return g_segment_name; } -const ConstString & -ObjectFileMachO::GetSegmentNameDATA_CONST() -{ - static ConstString g_segment_name ("__DATA_CONST"); - return g_segment_name; +const ConstString &ObjectFileMachO::GetSegmentNameDATA_CONST() { + static ConstString g_segment_name("__DATA_CONST"); + return g_segment_name; } -const ConstString & -ObjectFileMachO::GetSegmentNameOBJC() -{ - static ConstString g_segment_name_OBJC ("__OBJC"); - return g_segment_name_OBJC; +const ConstString &ObjectFileMachO::GetSegmentNameOBJC() { + static ConstString g_segment_name_OBJC("__OBJC"); + return g_segment_name_OBJC; } -const ConstString & -ObjectFileMachO::GetSegmentNameLINKEDIT() -{ - static ConstString g_section_name_LINKEDIT ("__LINKEDIT"); - return g_section_name_LINKEDIT; +const ConstString &ObjectFileMachO::GetSegmentNameLINKEDIT() { + static ConstString g_section_name_LINKEDIT("__LINKEDIT"); + return g_section_name_LINKEDIT; } -const ConstString & -ObjectFileMachO::GetSectionNameEHFrame() -{ - static ConstString g_section_name_eh_frame ("__eh_frame"); - return g_section_name_eh_frame; +const ConstString &ObjectFileMachO::GetSectionNameEHFrame() { + static ConstString g_section_name_eh_frame("__eh_frame"); + return g_section_name_eh_frame; } -bool -ObjectFileMachO::MagicBytesMatch (DataBufferSP& data_sp, - lldb::addr_t data_offset, - lldb::addr_t data_length) -{ - DataExtractor data; - data.SetData (data_sp, data_offset, data_length); - lldb::offset_t offset = 0; - uint32_t magic = data.GetU32(&offset); - return MachHeaderSizeFromMagic(magic) != 0; +bool ObjectFileMachO::MagicBytesMatch(DataBufferSP &data_sp, + lldb::addr_t data_offset, + lldb::addr_t data_length) { + DataExtractor data; + data.SetData(data_sp, data_offset, data_length); + lldb::offset_t offset = 0; + uint32_t magic = data.GetU32(&offset); + return MachHeaderSizeFromMagic(magic) != 0; } ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, + DataBufferSP &data_sp, lldb::offset_t data_offset, - const FileSpec* file, + const FileSpec *file, lldb::offset_t file_offset, - lldb::offset_t length) : - ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), - m_mach_segments(), - m_mach_sections(), - m_entry_point_address(), - m_thread_context_offsets(), - m_thread_context_offsets_valid(false), - m_reexported_dylibs (), - m_allow_assembly_emulation_unwind_plans (true) -{ - ::memset (&m_header, 0, sizeof(m_header)); - ::memset (&m_dysymtab, 0, sizeof(m_dysymtab)); + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_mach_segments(), m_mach_sections(), m_entry_point_address(), + m_thread_context_offsets(), m_thread_context_offsets_valid(false), + m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) { + ::memset(&m_header, 0, sizeof(m_header)); + ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); } -ObjectFileMachO::ObjectFileMachO (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& header_data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr) : - ObjectFile(module_sp, process_sp, header_addr, header_data_sp), - m_mach_segments(), - m_mach_sections(), - m_entry_point_address(), - m_thread_context_offsets(), - m_thread_context_offsets_valid(false), - m_reexported_dylibs (), - m_allow_assembly_emulation_unwind_plans (true) -{ - ::memset (&m_header, 0, sizeof(m_header)); - ::memset (&m_dysymtab, 0, sizeof(m_dysymtab)); +ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_mach_segments(), m_mach_sections(), m_entry_point_address(), + m_thread_context_offsets(), m_thread_context_offsets_valid(false), + m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) { + ::memset(&m_header, 0, sizeof(m_header)); + ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); } -bool -ObjectFileMachO::ParseHeader (DataExtractor &data, - lldb::offset_t *data_offset_ptr, - llvm::MachO::mach_header &header) -{ - data.SetByteOrder (endian::InlHostByteOrder()); - // Leave magic in the original byte order - header.magic = data.GetU32(data_offset_ptr); - bool can_parse = false; - bool is_64_bit = false; - switch (header.magic) - { - case MH_MAGIC: - data.SetByteOrder (endian::InlHostByteOrder()); - data.SetAddressByteSize(4); - can_parse = true; - break; - - case MH_MAGIC_64: - data.SetByteOrder (endian::InlHostByteOrder()); - data.SetAddressByteSize(8); - can_parse = true; - is_64_bit = true; - break; - - case MH_CIGAM: - data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig); - data.SetAddressByteSize(4); - can_parse = true; - break; - - case MH_CIGAM_64: - data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig); - data.SetAddressByteSize(8); - is_64_bit = true; - can_parse = true; - break; - - default: - break; - } - - if (can_parse) - { - data.GetU32(data_offset_ptr, &header.cputype, 6); - if (is_64_bit) - *data_offset_ptr += 4; - return true; - } - else - { - memset(&header, 0, sizeof(header)); - } - return false; +bool ObjectFileMachO::ParseHeader(DataExtractor &data, + lldb::offset_t *data_offset_ptr, + llvm::MachO::mach_header &header) { + data.SetByteOrder(endian::InlHostByteOrder()); + // Leave magic in the original byte order + header.magic = data.GetU32(data_offset_ptr); + bool can_parse = false; + bool is_64_bit = false; + switch (header.magic) { + case MH_MAGIC: + data.SetByteOrder(endian::InlHostByteOrder()); + data.SetAddressByteSize(4); + can_parse = true; + break; + + case MH_MAGIC_64: + data.SetByteOrder(endian::InlHostByteOrder()); + data.SetAddressByteSize(8); + can_parse = true; + is_64_bit = true; + break; + + case MH_CIGAM: + data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig + ? eByteOrderLittle + : eByteOrderBig); + data.SetAddressByteSize(4); + can_parse = true; + break; + + case MH_CIGAM_64: + data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig + ? eByteOrderLittle + : eByteOrderBig); + data.SetAddressByteSize(8); + is_64_bit = true; + can_parse = true; + break; + + default: + break; + } + + if (can_parse) { + data.GetU32(data_offset_ptr, &header.cputype, 6); + if (is_64_bit) + *data_offset_ptr += 4; + return true; + } else { + memset(&header, 0, sizeof(header)); + } + return false; } -bool -ObjectFileMachO::ParseHeader () -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - bool can_parse = false; - lldb::offset_t offset = 0; - m_data.SetByteOrder (endian::InlHostByteOrder()); - // Leave magic in the original byte order - m_header.magic = m_data.GetU32(&offset); - switch (m_header.magic) - { - case MH_MAGIC: - m_data.SetByteOrder (endian::InlHostByteOrder()); - m_data.SetAddressByteSize(4); - can_parse = true; - break; - - case MH_MAGIC_64: - m_data.SetByteOrder (endian::InlHostByteOrder()); - m_data.SetAddressByteSize(8); - can_parse = true; - break; - - case MH_CIGAM: - m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig); - m_data.SetAddressByteSize(4); - can_parse = true; - break; - - case MH_CIGAM_64: - m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig); - m_data.SetAddressByteSize(8); - can_parse = true; - break; - - default: - break; - } - - if (can_parse) - { - m_data.GetU32(&offset, &m_header.cputype, 6); +bool ObjectFileMachO::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + bool can_parse = false; + lldb::offset_t offset = 0; + m_data.SetByteOrder(endian::InlHostByteOrder()); + // Leave magic in the original byte order + m_header.magic = m_data.GetU32(&offset); + switch (m_header.magic) { + case MH_MAGIC: + m_data.SetByteOrder(endian::InlHostByteOrder()); + m_data.SetAddressByteSize(4); + can_parse = true; + break; + + case MH_MAGIC_64: + m_data.SetByteOrder(endian::InlHostByteOrder()); + m_data.SetAddressByteSize(8); + can_parse = true; + break; + + case MH_CIGAM: + m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig + ? eByteOrderLittle + : eByteOrderBig); + m_data.SetAddressByteSize(4); + can_parse = true; + break; + + case MH_CIGAM_64: + m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig + ? eByteOrderLittle + : eByteOrderBig); + m_data.SetAddressByteSize(8); + can_parse = true; + break; + + default: + break; + } - - ArchSpec mach_arch; - - if (GetArchitecture (mach_arch)) - { - // Check if the module has a required architecture - const ArchSpec &module_arch = module_sp->GetArchitecture(); - if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch)) - return false; - - if (SetModulesArchitecture (mach_arch)) - { - const size_t header_and_lc_size = m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic); - if (m_data.GetByteSize() < header_and_lc_size) - { - DataBufferSP data_sp; - ProcessSP process_sp (m_process_wp.lock()); - if (process_sp) - { - data_sp = ReadMemory (process_sp, m_memory_addr, header_and_lc_size); - } - else - { - // Read in all only the load command data from the file on disk - data_sp = m_file.ReadFileContents(m_file_offset, header_and_lc_size); - if (data_sp->GetByteSize() != header_and_lc_size) - return false; - } - if (data_sp) - m_data.SetData (data_sp); - } - } - return true; + if (can_parse) { + m_data.GetU32(&offset, &m_header.cputype, 6); + + ArchSpec mach_arch; + + if (GetArchitecture(mach_arch)) { + // Check if the module has a required architecture + const ArchSpec &module_arch = module_sp->GetArchitecture(); + if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch)) + return false; + + if (SetModulesArchitecture(mach_arch)) { + const size_t header_and_lc_size = + m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic); + if (m_data.GetByteSize() < header_and_lc_size) { + DataBufferSP data_sp; + ProcessSP process_sp(m_process_wp.lock()); + if (process_sp) { + data_sp = + ReadMemory(process_sp, m_memory_addr, header_and_lc_size); + } else { + // Read in all only the load command data from the file on disk + data_sp = + m_file.ReadFileContents(m_file_offset, header_and_lc_size); + if (data_sp->GetByteSize() != header_and_lc_size) + return false; } + if (data_sp) + m_data.SetData(data_sp); + } } - else - { - memset(&m_header, 0, sizeof(struct mach_header)); - } + return true; + } + } else { + memset(&m_header, 0, sizeof(struct mach_header)); } - return false; + } + return false; } -ByteOrder -ObjectFileMachO::GetByteOrder () const -{ - return m_data.GetByteOrder (); +ByteOrder ObjectFileMachO::GetByteOrder() const { + return m_data.GetByteOrder(); } -bool -ObjectFileMachO::IsExecutable() const -{ - return m_header.filetype == MH_EXECUTE; +bool ObjectFileMachO::IsExecutable() const { + return m_header.filetype == MH_EXECUTE; } -uint32_t -ObjectFileMachO::GetAddressByteSize () const -{ - return m_data.GetAddressByteSize (); +uint32_t ObjectFileMachO::GetAddressByteSize() const { + return m_data.GetAddressByteSize(); } -AddressClass -ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) -{ - Symtab *symtab = GetSymtab(); - if (symtab) - { - Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr); - if (symbol) - { - if (symbol->ValueIsAddress()) - { - SectionSP section_sp (symbol->GetAddressRef().GetSection()); - if (section_sp) - { - const lldb::SectionType section_type = section_sp->GetType(); - switch (section_type) - { - case eSectionTypeInvalid: - return eAddressClassUnknown; - - case eSectionTypeCode: - if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) - { - // For ARM we have a bit in the n_desc field of the symbol - // that tells us ARM/Thumb which is bit 0x0008. - if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) - return eAddressClassCodeAlternateISA; - } - return eAddressClassCode; - - case eSectionTypeContainer: - return eAddressClassUnknown; - - case eSectionTypeData: - case eSectionTypeDataCString: - case eSectionTypeDataCStringPointers: - case eSectionTypeDataSymbolAddress: - case eSectionTypeData4: - case eSectionTypeData8: - case eSectionTypeData16: - case eSectionTypeDataPointers: - case eSectionTypeZeroFill: - case eSectionTypeDataObjCMessageRefs: - case eSectionTypeDataObjCCFStrings: - case eSectionTypeGoSymtab: - return eAddressClassData; - - case eSectionTypeDebug: - case eSectionTypeDWARFDebugAbbrev: - case eSectionTypeDWARFDebugAddr: - case eSectionTypeDWARFDebugAranges: - case eSectionTypeDWARFDebugFrame: - case eSectionTypeDWARFDebugInfo: - case eSectionTypeDWARFDebugLine: - case eSectionTypeDWARFDebugLoc: - case eSectionTypeDWARFDebugMacInfo: - case eSectionTypeDWARFDebugMacro: - case eSectionTypeDWARFDebugPubNames: - case eSectionTypeDWARFDebugPubTypes: - case eSectionTypeDWARFDebugRanges: - case eSectionTypeDWARFDebugStr: - case eSectionTypeDWARFDebugStrOffsets: - case eSectionTypeDWARFAppleNames: - case eSectionTypeDWARFAppleTypes: - case eSectionTypeDWARFAppleNamespaces: - case eSectionTypeDWARFAppleObjC: - return eAddressClassDebug; - - case eSectionTypeEHFrame: - case eSectionTypeARMexidx: - case eSectionTypeARMextab: - case eSectionTypeCompactUnwind: - return eAddressClassRuntime; - - case eSectionTypeAbsoluteAddress: - case eSectionTypeELFSymbolTable: - case eSectionTypeELFDynamicSymbols: - case eSectionTypeELFRelocationEntries: - case eSectionTypeELFDynamicLinkInfo: - case eSectionTypeOther: - return eAddressClassUnknown; - } - } - } - - const SymbolType symbol_type = symbol->GetType(); - switch (symbol_type) - { - case eSymbolTypeAny: return eAddressClassUnknown; - case eSymbolTypeAbsolute: return eAddressClassUnknown; - - case eSymbolTypeCode: - case eSymbolTypeTrampoline: - case eSymbolTypeResolver: - if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) - { - // For ARM we have a bit in the n_desc field of the symbol - // that tells us ARM/Thumb which is bit 0x0008. - if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) - return eAddressClassCodeAlternateISA; - } - return eAddressClassCode; - - case eSymbolTypeData: return eAddressClassData; - case eSymbolTypeRuntime: return eAddressClassRuntime; - case eSymbolTypeException: return eAddressClassRuntime; - case eSymbolTypeSourceFile: return eAddressClassDebug; - case eSymbolTypeHeaderFile: return eAddressClassDebug; - case eSymbolTypeObjectFile: return eAddressClassDebug; - case eSymbolTypeCommonBlock: return eAddressClassDebug; - case eSymbolTypeBlock: return eAddressClassDebug; - case eSymbolTypeLocal: return eAddressClassData; - case eSymbolTypeParam: return eAddressClassData; - case eSymbolTypeVariable: return eAddressClassData; - case eSymbolTypeVariableType: return eAddressClassDebug; - case eSymbolTypeLineEntry: return eAddressClassDebug; - case eSymbolTypeLineHeader: return eAddressClassDebug; - case eSymbolTypeScopeBegin: return eAddressClassDebug; - case eSymbolTypeScopeEnd: return eAddressClassDebug; - case eSymbolTypeAdditional: return eAddressClassUnknown; - case eSymbolTypeCompiler: return eAddressClassDebug; - case eSymbolTypeInstrumentation:return eAddressClassDebug; - case eSymbolTypeUndefined: return eAddressClassUnknown; - case eSymbolTypeObjCClass: return eAddressClassRuntime; - case eSymbolTypeObjCMetaClass: return eAddressClassRuntime; - case eSymbolTypeObjCIVar: return eAddressClassRuntime; - case eSymbolTypeReExported: return eAddressClassRuntime; +AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { + Symtab *symtab = GetSymtab(); + if (symtab) { + Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr); + if (symbol) { + if (symbol->ValueIsAddress()) { + SectionSP section_sp(symbol->GetAddressRef().GetSection()); + if (section_sp) { + const lldb::SectionType section_type = section_sp->GetType(); + switch (section_type) { + case eSectionTypeInvalid: + return eAddressClassUnknown; + + case eSectionTypeCode: + if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { + // For ARM we have a bit in the n_desc field of the symbol + // that tells us ARM/Thumb which is bit 0x0008. + if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) + return eAddressClassCodeAlternateISA; } + return eAddressClassCode; + + case eSectionTypeContainer: + return eAddressClassUnknown; + + case eSectionTypeData: + case eSectionTypeDataCString: + case eSectionTypeDataCStringPointers: + case eSectionTypeDataSymbolAddress: + case eSectionTypeData4: + case eSectionTypeData8: + case eSectionTypeData16: + case eSectionTypeDataPointers: + case eSectionTypeZeroFill: + case eSectionTypeDataObjCMessageRefs: + case eSectionTypeDataObjCCFStrings: + case eSectionTypeGoSymtab: + return eAddressClassData; + + case eSectionTypeDebug: + case eSectionTypeDWARFDebugAbbrev: + case eSectionTypeDWARFDebugAddr: + case eSectionTypeDWARFDebugAranges: + case eSectionTypeDWARFDebugFrame: + case eSectionTypeDWARFDebugInfo: + case eSectionTypeDWARFDebugLine: + case eSectionTypeDWARFDebugLoc: + case eSectionTypeDWARFDebugMacInfo: + case eSectionTypeDWARFDebugMacro: + case eSectionTypeDWARFDebugPubNames: + case eSectionTypeDWARFDebugPubTypes: + case eSectionTypeDWARFDebugRanges: + case eSectionTypeDWARFDebugStr: + case eSectionTypeDWARFDebugStrOffsets: + case eSectionTypeDWARFAppleNames: + case eSectionTypeDWARFAppleTypes: + case eSectionTypeDWARFAppleNamespaces: + case eSectionTypeDWARFAppleObjC: + return eAddressClassDebug; + + case eSectionTypeEHFrame: + case eSectionTypeARMexidx: + case eSectionTypeARMextab: + case eSectionTypeCompactUnwind: + return eAddressClassRuntime; + + case eSectionTypeAbsoluteAddress: + case eSectionTypeELFSymbolTable: + case eSectionTypeELFDynamicSymbols: + case eSectionTypeELFRelocationEntries: + case eSectionTypeELFDynamicLinkInfo: + case eSectionTypeOther: + return eAddressClassUnknown; + } + } + } + + const SymbolType symbol_type = symbol->GetType(); + switch (symbol_type) { + case eSymbolTypeAny: + return eAddressClassUnknown; + case eSymbolTypeAbsolute: + return eAddressClassUnknown; + + case eSymbolTypeCode: + case eSymbolTypeTrampoline: + case eSymbolTypeResolver: + if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { + // For ARM we have a bit in the n_desc field of the symbol + // that tells us ARM/Thumb which is bit 0x0008. + if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB) + return eAddressClassCodeAlternateISA; } + return eAddressClassCode; + + case eSymbolTypeData: + return eAddressClassData; + case eSymbolTypeRuntime: + return eAddressClassRuntime; + case eSymbolTypeException: + return eAddressClassRuntime; + case eSymbolTypeSourceFile: + return eAddressClassDebug; + case eSymbolTypeHeaderFile: + return eAddressClassDebug; + case eSymbolTypeObjectFile: + return eAddressClassDebug; + case eSymbolTypeCommonBlock: + return eAddressClassDebug; + case eSymbolTypeBlock: + return eAddressClassDebug; + case eSymbolTypeLocal: + return eAddressClassData; + case eSymbolTypeParam: + return eAddressClassData; + case eSymbolTypeVariable: + return eAddressClassData; + case eSymbolTypeVariableType: + return eAddressClassDebug; + case eSymbolTypeLineEntry: + return eAddressClassDebug; + case eSymbolTypeLineHeader: + return eAddressClassDebug; + case eSymbolTypeScopeBegin: + return eAddressClassDebug; + case eSymbolTypeScopeEnd: + return eAddressClassDebug; + case eSymbolTypeAdditional: + return eAddressClassUnknown; + case eSymbolTypeCompiler: + return eAddressClassDebug; + case eSymbolTypeInstrumentation: + return eAddressClassDebug; + case eSymbolTypeUndefined: + return eAddressClassUnknown; + case eSymbolTypeObjCClass: + return eAddressClassRuntime; + case eSymbolTypeObjCMetaClass: + return eAddressClassRuntime; + case eSymbolTypeObjCIVar: + return eAddressClassRuntime; + case eSymbolTypeReExported: + return eAddressClassRuntime; + } + } + } + return eAddressClassUnknown; +} + +Symtab *ObjectFileMachO::GetSymtab() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_symtab_ap.get() == NULL) { + m_symtab_ap.reset(new Symtab(this)); + std::lock_guard<std::recursive_mutex> symtab_guard( + m_symtab_ap->GetMutex()); + ParseSymtab(); + m_symtab_ap->Finalize(); } - return eAddressClassUnknown; + } + return m_symtab_ap.get(); } -Symtab * -ObjectFileMachO::GetSymtab() -{ +bool ObjectFileMachO::IsStripped() { + if (m_dysymtab.cmd == 0) { ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - if (m_symtab_ap.get() == NULL) - { - m_symtab_ap.reset(new Symtab(this)); - std::lock_guard<std::recursive_mutex> symtab_guard(m_symtab_ap->GetMutex()); - ParseSymtab (); - m_symtab_ap->Finalize (); + if (module_sp) { + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + + load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == LC_DYSYMTAB) { + m_dysymtab.cmd = lc.cmd; + m_dysymtab.cmdsize = lc.cmdsize; + if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym, + (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) == + NULL) { + // Clear m_dysymtab if we were unable to read all items from the + // load command + ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); + } } + offset = load_cmd_offset + lc.cmdsize; + } } - return m_symtab_ap.get(); + } + if (m_dysymtab.cmd) + return m_dysymtab.nlocalsym <= 1; + return false; } -bool -ObjectFileMachO::IsStripped () -{ - if (m_dysymtab.cmd == 0) - { - ModuleSP module_sp(GetModule()); - if (module_sp) - { - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - for (uint32_t i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t load_cmd_offset = offset; - - load_command lc; - if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) - break; - if (lc.cmd == LC_DYSYMTAB) - { - m_dysymtab.cmd = lc.cmd; - m_dysymtab.cmdsize = lc.cmdsize; - if (m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) == NULL) - { - // Clear m_dysymtab if we were unable to read all items from the load command - ::memset (&m_dysymtab, 0, sizeof(m_dysymtab)); - } - } - offset = load_cmd_offset + lc.cmdsize; - } +void ObjectFileMachO::CreateSections(SectionList &unified_section_list) { + if (!m_sections_ap.get()) { + m_sections_ap.reset(new SectionList()); + + const bool is_dsym = (m_header.filetype == MH_DSYM); + lldb::user_id_t segID = 0; + lldb::user_id_t sectID = 0; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + uint32_t i; + const bool is_core = GetType() == eTypeCoreFile; + // bool dump_sections = false; + ModuleSP module_sp(GetModule()); + // First look up any LC_ENCRYPTION_INFO load commands + typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges; + EncryptedFileRanges encrypted_file_ranges; + encryption_info_command encryption_cmd; + for (i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL) + break; + + // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for + // the 3 fields we care about, so treat them the same. + if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || + encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) { + if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) { + if (encryption_cmd.cryptid != 0) { + EncryptedFileRanges::Entry entry; + entry.SetRangeBase(encryption_cmd.cryptoff); + entry.SetByteSize(encryption_cmd.cryptsize); + encrypted_file_ranges.Append(entry); + } } + } + offset = load_cmd_offset + encryption_cmd.cmdsize; } - if (m_dysymtab.cmd) - return m_dysymtab.nlocalsym <= 1; - return false; -} -void -ObjectFileMachO::CreateSections (SectionList &unified_section_list) -{ - if (!m_sections_ap.get()) - { - m_sections_ap.reset(new SectionList()); - - const bool is_dsym = (m_header.filetype == MH_DSYM); - lldb::user_id_t segID = 0; - lldb::user_id_t sectID = 0; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - uint32_t i; - const bool is_core = GetType() == eTypeCoreFile; - //bool dump_sections = false; - ModuleSP module_sp (GetModule()); - // First look up any LC_ENCRYPTION_INFO load commands - typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges; - EncryptedFileRanges encrypted_file_ranges; - encryption_info_command encryption_cmd; - for (i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t load_cmd_offset = offset; - if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL) - break; + bool section_file_addresses_changed = false; + + offset = MachHeaderSizeFromMagic(m_header.magic); + + struct segment_command_64 load_cmd; + for (i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) { + if (m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) { + bool add_section = true; + bool add_to_unified = true; + ConstString const_segname(load_cmd.segname, + std::min<size_t>(strlen(load_cmd.segname), + sizeof(load_cmd.segname))); + + SectionSP unified_section_sp( + unified_section_list.FindSectionByName(const_segname)); + if (is_dsym && unified_section_sp) { + if (const_segname == GetSegmentNameLINKEDIT()) { + // We need to keep the __LINKEDIT segment private to this object + // file only + add_to_unified = false; + } else { + // This is the dSYM file and this section has already been created + // by + // the object file, no need to create it. + add_section = false; + } + } + load_cmd.vmaddr = m_data.GetAddress(&offset); + load_cmd.vmsize = m_data.GetAddress(&offset); + load_cmd.fileoff = m_data.GetAddress(&offset); + load_cmd.filesize = m_data.GetAddress(&offset); + if (m_length != 0 && load_cmd.filesize != 0) { + if (load_cmd.fileoff > m_length) { + // We have a load command that says it extends past the end of the + // file. This is likely + // a corrupt file. We don't have any way to return an error + // condition here (this method + // was likely invoked from something like + // ObjectFile::GetSectionList()) -- all we can do + // is null out the SectionList vector and if a process has been + // set up, dump a message + // to stdout. The most common case here is core file debugging + // with a truncated file. + const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 + ? "LC_SEGMENT_64" + : "LC_SEGMENT"; + module_sp->ReportWarning( + "load command %u %s has a fileoff (0x%" PRIx64 + ") that extends beyond the end of the file (0x%" PRIx64 + "), ignoring this section", + i, lc_segment_name, load_cmd.fileoff, m_length); + + load_cmd.fileoff = 0; + load_cmd.filesize = 0; + } - // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for - // the 3 fields we care about, so treat them the same. - if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) - { - if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) - { - if (encryption_cmd.cryptid != 0) - { - EncryptedFileRanges::Entry entry; - entry.SetRangeBase(encryption_cmd.cryptoff); - entry.SetByteSize(encryption_cmd.cryptsize); - encrypted_file_ranges.Append(entry); - } + if (load_cmd.fileoff + load_cmd.filesize > m_length) { + // We have a load command that says it extends past the end of the + // file. This is likely + // a corrupt file. We don't have any way to return an error + // condition here (this method + // was likely invoked from something like + // ObjectFile::GetSectionList()) -- all we can do + // is null out the SectionList vector and if a process has been + // set up, dump a message + // to stdout. The most common case here is core file debugging + // with a truncated file. + const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 + ? "LC_SEGMENT_64" + : "LC_SEGMENT"; + GetModule()->ReportWarning( + "load command %u %s has a fileoff + filesize (0x%" PRIx64 + ") that extends beyond the end of the file (0x%" PRIx64 + "), the segment will be truncated to match", + i, lc_segment_name, load_cmd.fileoff + load_cmd.filesize, + m_length); + + // Tuncase the length + load_cmd.filesize = m_length - load_cmd.fileoff; + } + } + if (m_data.GetU32(&offset, &load_cmd.maxprot, 4)) { + const uint32_t segment_permissions = + ((load_cmd.initprot & VM_PROT_READ) ? ePermissionsReadable + : 0) | + ((load_cmd.initprot & VM_PROT_WRITE) ? ePermissionsWritable + : 0) | + ((load_cmd.initprot & VM_PROT_EXECUTE) ? ePermissionsExecutable + : 0); + + const bool segment_is_encrypted = + (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0; + + // Keep a list of mach segments around in case we need to + // get at data that isn't stored in the abstracted Sections. + m_mach_segments.push_back(load_cmd); + + // Use a segment ID of the segment index shifted left by 8 so they + // never conflict with any of the sections. + SectionSP segment_sp; + if (add_section && (const_segname || is_core)) { + segment_sp.reset(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this sections belongs + ++segID << 8, // Section ID is the 1 based segment index + // shifted right by 8 bits as not to collide + // with any of the 256 section IDs that are + // possible + const_segname, // Name of this section + eSectionTypeContainer, // This section is a container of other + // sections. + load_cmd.vmaddr, // File VM address == addresses as they are + // found in the object file + load_cmd.vmsize, // VM size in bytes of this section + load_cmd.fileoff, // Offset to the data for this section in + // the file + load_cmd.filesize, // Size in bytes of this section as found + // in the file + 0, // Segments have no alignment information + load_cmd.flags)); // Flags for this section + + segment_sp->SetIsEncrypted(segment_is_encrypted); + m_sections_ap->AddSection(segment_sp); + segment_sp->SetPermissions(segment_permissions); + if (add_to_unified) + unified_section_list.AddSection(segment_sp); + } else if (unified_section_sp) { + if (is_dsym && + unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { + // Check to see if the module was read from memory? + if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid()) { + // We have a module that is in memory and needs to have its + // file address adjusted. We need to do this because when we + // load a file from memory, its addresses will be slid + // already, + // yet the addresses in the new symbol file will still be + // unslid. + // Since everything is stored as section offset, this + // shouldn't + // cause any problems. + + // Make sure we've parsed the symbol table from the + // ObjectFile before we go around changing its Sections. + module_sp->GetObjectFile()->GetSymtab(); + // eh_frame would present the same problems but we parse that + // on + // a per-function basis as-needed so it's more difficult to + // remove its use of the Sections. Realistically, the + // environments + // where this code path will be taken will not have eh_frame + // sections. + + unified_section_sp->SetFileAddress(load_cmd.vmaddr); + + // Notify the module that the section addresses have been + // changed once + // we're done so any file-address caches can be updated. + section_file_addresses_changed = true; } + } + m_sections_ap->AddSection(unified_section_sp); } - offset = load_cmd_offset + encryption_cmd.cmdsize; - } - - bool section_file_addresses_changed = false; - offset = MachHeaderSizeFromMagic(m_header.magic); + struct section_64 sect64; + ::memset(§64, 0, sizeof(sect64)); + // Push a section into our mach sections for the section at + // index zero (NO_SECT) if we don't have any mach sections yet... + if (m_mach_sections.empty()) + m_mach_sections.push_back(sect64); + uint32_t segment_sect_idx; + const lldb::user_id_t first_segment_sectID = sectID + 1; + + const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8; + for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects; + ++segment_sect_idx) { + if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname, + sizeof(sect64.sectname)) == NULL) + break; + if (m_data.GetU8(&offset, (uint8_t *)sect64.segname, + sizeof(sect64.segname)) == NULL) + break; + sect64.addr = m_data.GetAddress(&offset); + sect64.size = m_data.GetAddress(&offset); - struct segment_command_64 load_cmd; - for (i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t load_cmd_offset = offset; - if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + if (m_data.GetU32(&offset, §64.offset, num_u32s) == NULL) break; - if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) - { - if (m_data.GetU8(&offset, (uint8_t*)load_cmd.segname, 16)) - { - bool add_section = true; - bool add_to_unified = true; - ConstString const_segname (load_cmd.segname, std::min<size_t>(strlen(load_cmd.segname), sizeof(load_cmd.segname))); - - SectionSP unified_section_sp(unified_section_list.FindSectionByName(const_segname)); - if (is_dsym && unified_section_sp) - { - if (const_segname == GetSegmentNameLINKEDIT()) - { - // We need to keep the __LINKEDIT segment private to this object file only - add_to_unified = false; - } - else - { - // This is the dSYM file and this section has already been created by - // the object file, no need to create it. - add_section = false; - } - } - load_cmd.vmaddr = m_data.GetAddress(&offset); - load_cmd.vmsize = m_data.GetAddress(&offset); - load_cmd.fileoff = m_data.GetAddress(&offset); - load_cmd.filesize = m_data.GetAddress(&offset); - if (m_length != 0 && load_cmd.filesize != 0) - { - if (load_cmd.fileoff > m_length) - { - // We have a load command that says it extends past the end of the file. This is likely - // a corrupt file. We don't have any way to return an error condition here (this method - // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do - // is null out the SectionList vector and if a process has been set up, dump a message - // to stdout. The most common case here is core file debugging with a truncated file. - const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; - module_sp->ReportWarning("load command %u %s has a fileoff (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), ignoring this section", - i, - lc_segment_name, - load_cmd.fileoff, - m_length); - - load_cmd.fileoff = 0; - load_cmd.filesize = 0; - } - - if (load_cmd.fileoff + load_cmd.filesize > m_length) - { - // We have a load command that says it extends past the end of the file. This is likely - // a corrupt file. We don't have any way to return an error condition here (this method - // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do - // is null out the SectionList vector and if a process has been set up, dump a message - // to stdout. The most common case here is core file debugging with a truncated file. - const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; - GetModule()->ReportWarning("load command %u %s has a fileoff + filesize (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), the segment will be truncated to match", - i, - lc_segment_name, - load_cmd.fileoff + load_cmd.filesize, - m_length); - - // Tuncase the length - load_cmd.filesize = m_length - load_cmd.fileoff; - } + // Keep a list of mach sections around in case we need to + // get at data that isn't stored in the abstracted Sections. + m_mach_sections.push_back(sect64); + + if (add_section) { + ConstString section_name( + sect64.sectname, std::min<size_t>(strlen(sect64.sectname), + sizeof(sect64.sectname))); + if (!const_segname) { + // We have a segment with no name so we need to conjure up + // segments that correspond to the section's segname if there + // isn't already such a section. If there is such a section, + // we resize the section so that it spans all sections. + // We also mark these sections as fake so address matches + // don't + // hit if they land in the gaps between the child sections. + const_segname.SetTrimmedCStringWithLength( + sect64.segname, sizeof(sect64.segname)); + segment_sp = + unified_section_list.FindSectionByName(const_segname); + if (segment_sp.get()) { + Section *segment = segment_sp.get(); + // Grow the section size as needed. + const lldb::addr_t sect64_min_addr = sect64.addr; + const lldb::addr_t sect64_max_addr = + sect64_min_addr + sect64.size; + const lldb::addr_t curr_seg_byte_size = + segment->GetByteSize(); + const lldb::addr_t curr_seg_min_addr = + segment->GetFileAddress(); + const lldb::addr_t curr_seg_max_addr = + curr_seg_min_addr + curr_seg_byte_size; + if (sect64_min_addr >= curr_seg_min_addr) { + const lldb::addr_t new_seg_byte_size = + sect64_max_addr - curr_seg_min_addr; + // Only grow the section size if needed + if (new_seg_byte_size > curr_seg_byte_size) + segment->SetByteSize(new_seg_byte_size); + } else { + // We need to change the base address of the segment and + // adjust the child section offsets for all existing + // children. + const lldb::addr_t slide_amount = + sect64_min_addr - curr_seg_min_addr; + segment->Slide(slide_amount, false); + segment->GetChildren().Slide(-slide_amount, false); + segment->SetByteSize(curr_seg_max_addr - sect64_min_addr); } - if (m_data.GetU32(&offset, &load_cmd.maxprot, 4)) - { - const uint32_t segment_permissions = - ((load_cmd.initprot & VM_PROT_READ) ? ePermissionsReadable : 0) | - ((load_cmd.initprot & VM_PROT_WRITE) ? ePermissionsWritable : 0) | - ((load_cmd.initprot & VM_PROT_EXECUTE) ? ePermissionsExecutable : 0); - - const bool segment_is_encrypted = (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0; - - // Keep a list of mach segments around in case we need to - // get at data that isn't stored in the abstracted Sections. - m_mach_segments.push_back (load_cmd); - - // Use a segment ID of the segment index shifted left by 8 so they - // never conflict with any of the sections. - SectionSP segment_sp; - if (add_section && (const_segname || is_core)) - { - segment_sp.reset(new Section (module_sp, // Module to which this section belongs - this, // Object file to which this sections belongs - ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible - const_segname, // Name of this section - eSectionTypeContainer, // This section is a container of other sections. - load_cmd.vmaddr, // File VM address == addresses as they are found in the object file - load_cmd.vmsize, // VM size in bytes of this section - load_cmd.fileoff, // Offset to the data for this section in the file - load_cmd.filesize, // Size in bytes of this section as found in the file - 0, // Segments have no alignment information - load_cmd.flags)); // Flags for this section - - segment_sp->SetIsEncrypted (segment_is_encrypted); - m_sections_ap->AddSection(segment_sp); - segment_sp->SetPermissions(segment_permissions); - if (add_to_unified) - unified_section_list.AddSection(segment_sp); - } - else if (unified_section_sp) - { - if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) - { - // Check to see if the module was read from memory? - if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid()) - { - // We have a module that is in memory and needs to have its - // file address adjusted. We need to do this because when we - // load a file from memory, its addresses will be slid already, - // yet the addresses in the new symbol file will still be unslid. - // Since everything is stored as section offset, this shouldn't - // cause any problems. - - // Make sure we've parsed the symbol table from the - // ObjectFile before we go around changing its Sections. - module_sp->GetObjectFile()->GetSymtab(); - // eh_frame would present the same problems but we parse that on - // a per-function basis as-needed so it's more difficult to - // remove its use of the Sections. Realistically, the environments - // where this code path will be taken will not have eh_frame sections. - - unified_section_sp->SetFileAddress(load_cmd.vmaddr); - - // Notify the module that the section addresses have been changed once - // we're done so any file-address caches can be updated. - section_file_addresses_changed = true; - } - } - m_sections_ap->AddSection(unified_section_sp); - } - - struct section_64 sect64; - ::memset (§64, 0, sizeof(sect64)); - // Push a section into our mach sections for the section at - // index zero (NO_SECT) if we don't have any mach sections yet... - if (m_mach_sections.empty()) - m_mach_sections.push_back(sect64); - uint32_t segment_sect_idx; - const lldb::user_id_t first_segment_sectID = sectID + 1; - - - const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8; - for (segment_sect_idx=0; segment_sect_idx<load_cmd.nsects; ++segment_sect_idx) - { - if (m_data.GetU8(&offset, (uint8_t*)sect64.sectname, sizeof(sect64.sectname)) == NULL) - break; - if (m_data.GetU8(&offset, (uint8_t*)sect64.segname, sizeof(sect64.segname)) == NULL) - break; - sect64.addr = m_data.GetAddress(&offset); - sect64.size = m_data.GetAddress(&offset); - - if (m_data.GetU32(&offset, §64.offset, num_u32s) == NULL) - break; - - // Keep a list of mach sections around in case we need to - // get at data that isn't stored in the abstracted Sections. - m_mach_sections.push_back (sect64); - - if (add_section) - { - ConstString section_name (sect64.sectname, std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname))); - if (!const_segname) - { - // We have a segment with no name so we need to conjure up - // segments that correspond to the section's segname if there - // isn't already such a section. If there is such a section, - // we resize the section so that it spans all sections. - // We also mark these sections as fake so address matches don't - // hit if they land in the gaps between the child sections. - const_segname.SetTrimmedCStringWithLength(sect64.segname, sizeof(sect64.segname)); - segment_sp = unified_section_list.FindSectionByName (const_segname); - if (segment_sp.get()) - { - Section *segment = segment_sp.get(); - // Grow the section size as needed. - const lldb::addr_t sect64_min_addr = sect64.addr; - const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size; - const lldb::addr_t curr_seg_byte_size = segment->GetByteSize(); - const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress(); - const lldb::addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size; - if (sect64_min_addr >= curr_seg_min_addr) - { - const lldb::addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr; - // Only grow the section size if needed - if (new_seg_byte_size > curr_seg_byte_size) - segment->SetByteSize (new_seg_byte_size); - } - else - { - // We need to change the base address of the segment and - // adjust the child section offsets for all existing children. - const lldb::addr_t slide_amount = sect64_min_addr - curr_seg_min_addr; - segment->Slide(slide_amount, false); - segment->GetChildren().Slide(-slide_amount, false); - segment->SetByteSize (curr_seg_max_addr - sect64_min_addr); - } - - // Grow the section size as needed. - if (sect64.offset) - { - const lldb::addr_t segment_min_file_offset = segment->GetFileOffset(); - const lldb::addr_t segment_max_file_offset = segment_min_file_offset + segment->GetFileSize(); - - const lldb::addr_t section_min_file_offset = sect64.offset; - const lldb::addr_t section_max_file_offset = section_min_file_offset + sect64.size; - const lldb::addr_t new_file_offset = std::min (section_min_file_offset, segment_min_file_offset); - const lldb::addr_t new_file_size = std::max (section_max_file_offset, segment_max_file_offset) - new_file_offset; - segment->SetFileOffset (new_file_offset); - segment->SetFileSize (new_file_size); - } - } - else - { - // Create a fake section for the section's named segment - segment_sp.reset(new Section (segment_sp, // Parent section - module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible - const_segname, // Name of this section - eSectionTypeContainer, // This section is a container of other sections. - sect64.addr, // File VM address == addresses as they are found in the object file - sect64.size, // VM size in bytes of this section - sect64.offset, // Offset to the data for this section in the file - sect64.offset ? sect64.size : 0, // Size in bytes of this section as found in the file - sect64.align, - load_cmd.flags)); // Flags for this section - segment_sp->SetIsFake(true); - segment_sp->SetPermissions(segment_permissions); - m_sections_ap->AddSection(segment_sp); - if (add_to_unified) - unified_section_list.AddSection(segment_sp); - segment_sp->SetIsEncrypted (segment_is_encrypted); - } - } - assert (segment_sp.get()); - lldb::SectionType sect_type = eSectionTypeOther; - - if (sect64.flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)) - sect_type = eSectionTypeCode; - else - { - uint32_t mach_sect_type = sect64.flags & SECTION_TYPE; - static ConstString g_sect_name_objc_data ("__objc_data"); - static ConstString g_sect_name_objc_msgrefs ("__objc_msgrefs"); - static ConstString g_sect_name_objc_selrefs ("__objc_selrefs"); - static ConstString g_sect_name_objc_classrefs ("__objc_classrefs"); - static ConstString g_sect_name_objc_superrefs ("__objc_superrefs"); - static ConstString g_sect_name_objc_const ("__objc_const"); - static ConstString g_sect_name_objc_classlist ("__objc_classlist"); - static ConstString g_sect_name_cfstring ("__cfstring"); - - static ConstString g_sect_name_dwarf_debug_abbrev ("__debug_abbrev"); - 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_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_apple_names ("__apple_names"); - static ConstString g_sect_name_dwarf_apple_types ("__apple_types"); - static ConstString g_sect_name_dwarf_apple_namespaces ("__apple_namespac"); - static ConstString g_sect_name_dwarf_apple_objc ("__apple_objc"); - static ConstString g_sect_name_eh_frame ("__eh_frame"); - static ConstString g_sect_name_compact_unwind ("__unwind_info"); - static ConstString g_sect_name_text ("__text"); - static ConstString g_sect_name_data ("__data"); - static ConstString g_sect_name_go_symtab ("__gosymtab"); - - if (section_name == g_sect_name_dwarf_debug_abbrev) - sect_type = eSectionTypeDWARFDebugAbbrev; - else if (section_name == g_sect_name_dwarf_debug_aranges) - sect_type = eSectionTypeDWARFDebugAranges; - else if (section_name == g_sect_name_dwarf_debug_frame) - sect_type = eSectionTypeDWARFDebugFrame; - else if (section_name == g_sect_name_dwarf_debug_info) - sect_type = eSectionTypeDWARFDebugInfo; - else if (section_name == g_sect_name_dwarf_debug_line) - sect_type = eSectionTypeDWARFDebugLine; - else if (section_name == g_sect_name_dwarf_debug_loc) - sect_type = eSectionTypeDWARFDebugLoc; - else if (section_name == g_sect_name_dwarf_debug_macinfo) - sect_type = eSectionTypeDWARFDebugMacInfo; - else if (section_name == g_sect_name_dwarf_debug_pubnames) - sect_type = eSectionTypeDWARFDebugPubNames; - else if (section_name == g_sect_name_dwarf_debug_pubtypes) - sect_type = eSectionTypeDWARFDebugPubTypes; - else if (section_name == g_sect_name_dwarf_debug_ranges) - sect_type = eSectionTypeDWARFDebugRanges; - else if (section_name == g_sect_name_dwarf_debug_str) - sect_type = eSectionTypeDWARFDebugStr; - else if (section_name == g_sect_name_dwarf_apple_names) - sect_type = eSectionTypeDWARFAppleNames; - else if (section_name == g_sect_name_dwarf_apple_types) - sect_type = eSectionTypeDWARFAppleTypes; - else if (section_name == g_sect_name_dwarf_apple_namespaces) - sect_type = eSectionTypeDWARFAppleNamespaces; - else if (section_name == g_sect_name_dwarf_apple_objc) - sect_type = eSectionTypeDWARFAppleObjC; - else if (section_name == g_sect_name_objc_selrefs) - sect_type = eSectionTypeDataCStringPointers; - else if (section_name == g_sect_name_objc_msgrefs) - sect_type = eSectionTypeDataObjCMessageRefs; - else if (section_name == g_sect_name_eh_frame) - sect_type = eSectionTypeEHFrame; - else if (section_name == g_sect_name_compact_unwind) - sect_type = eSectionTypeCompactUnwind; - else if (section_name == g_sect_name_cfstring) - sect_type = eSectionTypeDataObjCCFStrings; - else if (section_name == g_sect_name_go_symtab) - sect_type = eSectionTypeGoSymtab; - else if (section_name == g_sect_name_objc_data || - section_name == g_sect_name_objc_classrefs || - section_name == g_sect_name_objc_superrefs || - section_name == g_sect_name_objc_const || - section_name == g_sect_name_objc_classlist) - { - sect_type = eSectionTypeDataPointers; - } - - if (sect_type == eSectionTypeOther) - { - switch (mach_sect_type) - { - // TODO: categorize sections by other flags for regular sections - case S_REGULAR: - if (section_name == g_sect_name_text) - sect_type = eSectionTypeCode; - else if (section_name == g_sect_name_data) - sect_type = eSectionTypeData; - else - sect_type = eSectionTypeOther; - break; - case S_ZEROFILL: sect_type = eSectionTypeZeroFill; break; - case S_CSTRING_LITERALS: sect_type = eSectionTypeDataCString; break; // section with only literal C strings - case S_4BYTE_LITERALS: sect_type = eSectionTypeData4; break; // section with only 4 byte literals - case S_8BYTE_LITERALS: sect_type = eSectionTypeData8; break; // section with only 8 byte literals - case S_LITERAL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only pointers to literals - case S_NON_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only non-lazy symbol pointers - case S_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only lazy symbol pointers - case S_SYMBOL_STUBS: sect_type = eSectionTypeCode; break; // section with only symbol stubs, byte size of stub in the reserved2 field - case S_MOD_INIT_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for initialization - case S_MOD_TERM_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for termination - case S_COALESCED: sect_type = eSectionTypeOther; break; - case S_GB_ZEROFILL: sect_type = eSectionTypeZeroFill; break; - case S_INTERPOSING: sect_type = eSectionTypeCode; break; // section with only pairs of function pointers for interposing - case S_16BYTE_LITERALS: sect_type = eSectionTypeData16; break; // section with only 16 byte literals - case S_DTRACE_DOF: sect_type = eSectionTypeDebug; break; - case S_LAZY_DYLIB_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; - default: break; - } - } - } - - SectionSP section_sp(new Section (segment_sp, - module_sp, - this, - ++sectID, - section_name, - sect_type, - sect64.addr - segment_sp->GetFileAddress(), - sect64.size, - sect64.offset, - sect64.offset == 0 ? 0 : sect64.size, - sect64.align, - sect64.flags)); - // Set the section to be encrypted to match the segment - - bool section_is_encrypted = false; - if (!segment_is_encrypted && load_cmd.filesize != 0) - section_is_encrypted = encrypted_file_ranges.FindEntryThatContains(sect64.offset) != NULL; - - section_sp->SetIsEncrypted (segment_is_encrypted || section_is_encrypted); - section_sp->SetPermissions(segment_permissions); - segment_sp->GetChildren().AddSection(section_sp); - - if (segment_sp->IsFake()) - { - segment_sp.reset(); - const_segname.Clear(); - } - } - } - if (segment_sp && is_dsym) - { - if (first_segment_sectID <= sectID) - { - lldb::user_id_t sect_uid; - for (sect_uid = first_segment_sectID; sect_uid <= sectID; ++sect_uid) - { - SectionSP curr_section_sp(segment_sp->GetChildren().FindSectionByID (sect_uid)); - SectionSP next_section_sp; - if (sect_uid + 1 <= sectID) - next_section_sp = segment_sp->GetChildren().FindSectionByID (sect_uid+1); - - if (curr_section_sp.get()) - { - if (curr_section_sp->GetByteSize() == 0) - { - if (next_section_sp.get() != NULL) - curr_section_sp->SetByteSize ( next_section_sp->GetFileAddress() - curr_section_sp->GetFileAddress() ); - else - curr_section_sp->SetByteSize ( load_cmd.vmsize ); - } - } - } - } - } + // Grow the section size as needed. + if (sect64.offset) { + const lldb::addr_t segment_min_file_offset = + segment->GetFileOffset(); + const lldb::addr_t segment_max_file_offset = + segment_min_file_offset + segment->GetFileSize(); + + const lldb::addr_t section_min_file_offset = + sect64.offset; + const lldb::addr_t section_max_file_offset = + section_min_file_offset + sect64.size; + const lldb::addr_t new_file_offset = std::min( + section_min_file_offset, segment_min_file_offset); + const lldb::addr_t new_file_size = + std::max(section_max_file_offset, + segment_max_file_offset) - + new_file_offset; + segment->SetFileOffset(new_file_offset); + segment->SetFileSize(new_file_size); + } + } else { + // Create a fake section for the section's named segment + segment_sp.reset(new Section( + segment_sp, // Parent section + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + ++segID << 8, // Section ID is the 1 based segment index + // shifted right by 8 bits as not to + // collide with any of the 256 section IDs + // that are possible + const_segname, // Name of this section + eSectionTypeContainer, // This section is a container of + // other sections. + sect64.addr, // File VM address == addresses as they are + // found in the object file + sect64.size, // VM size in bytes of this section + sect64.offset, // Offset to the data for this section in + // the file + sect64.offset ? sect64.size : 0, // Size in bytes of + // this section as + // found in the file + sect64.align, + load_cmd.flags)); // Flags for this section + segment_sp->SetIsFake(true); + segment_sp->SetPermissions(segment_permissions); + m_sections_ap->AddSection(segment_sp); + if (add_to_unified) + unified_section_list.AddSection(segment_sp); + segment_sp->SetIsEncrypted(segment_is_encrypted); + } + } + assert(segment_sp.get()); + + lldb::SectionType sect_type = eSectionTypeOther; + + if (sect64.flags & + (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)) + sect_type = eSectionTypeCode; + else { + uint32_t mach_sect_type = sect64.flags & SECTION_TYPE; + static ConstString g_sect_name_objc_data("__objc_data"); + static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs"); + static ConstString g_sect_name_objc_selrefs("__objc_selrefs"); + static ConstString g_sect_name_objc_classrefs( + "__objc_classrefs"); + static ConstString g_sect_name_objc_superrefs( + "__objc_superrefs"); + static ConstString g_sect_name_objc_const("__objc_const"); + static ConstString g_sect_name_objc_classlist( + "__objc_classlist"); + static ConstString g_sect_name_cfstring("__cfstring"); + + static ConstString g_sect_name_dwarf_debug_abbrev( + "__debug_abbrev"); + 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_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_apple_names( + "__apple_names"); + static ConstString g_sect_name_dwarf_apple_types( + "__apple_types"); + static ConstString g_sect_name_dwarf_apple_namespaces( + "__apple_namespac"); + static ConstString g_sect_name_dwarf_apple_objc( + "__apple_objc"); + static ConstString g_sect_name_eh_frame("__eh_frame"); + static ConstString g_sect_name_compact_unwind( + "__unwind_info"); + static ConstString g_sect_name_text("__text"); + static ConstString g_sect_name_data("__data"); + static ConstString g_sect_name_go_symtab("__gosymtab"); + + if (section_name == g_sect_name_dwarf_debug_abbrev) + sect_type = eSectionTypeDWARFDebugAbbrev; + else if (section_name == g_sect_name_dwarf_debug_aranges) + sect_type = eSectionTypeDWARFDebugAranges; + else if (section_name == g_sect_name_dwarf_debug_frame) + sect_type = eSectionTypeDWARFDebugFrame; + else if (section_name == g_sect_name_dwarf_debug_info) + sect_type = eSectionTypeDWARFDebugInfo; + else if (section_name == g_sect_name_dwarf_debug_line) + sect_type = eSectionTypeDWARFDebugLine; + else if (section_name == g_sect_name_dwarf_debug_loc) + sect_type = eSectionTypeDWARFDebugLoc; + else if (section_name == g_sect_name_dwarf_debug_macinfo) + sect_type = eSectionTypeDWARFDebugMacInfo; + else if (section_name == g_sect_name_dwarf_debug_pubnames) + sect_type = eSectionTypeDWARFDebugPubNames; + else if (section_name == g_sect_name_dwarf_debug_pubtypes) + sect_type = eSectionTypeDWARFDebugPubTypes; + else if (section_name == g_sect_name_dwarf_debug_ranges) + sect_type = eSectionTypeDWARFDebugRanges; + else if (section_name == g_sect_name_dwarf_debug_str) + sect_type = eSectionTypeDWARFDebugStr; + else if (section_name == g_sect_name_dwarf_apple_names) + sect_type = eSectionTypeDWARFAppleNames; + else if (section_name == g_sect_name_dwarf_apple_types) + sect_type = eSectionTypeDWARFAppleTypes; + else if (section_name == g_sect_name_dwarf_apple_namespaces) + sect_type = eSectionTypeDWARFAppleNamespaces; + else if (section_name == g_sect_name_dwarf_apple_objc) + sect_type = eSectionTypeDWARFAppleObjC; + else if (section_name == g_sect_name_objc_selrefs) + sect_type = eSectionTypeDataCStringPointers; + else if (section_name == g_sect_name_objc_msgrefs) + sect_type = eSectionTypeDataObjCMessageRefs; + else if (section_name == g_sect_name_eh_frame) + sect_type = eSectionTypeEHFrame; + else if (section_name == g_sect_name_compact_unwind) + sect_type = eSectionTypeCompactUnwind; + else if (section_name == g_sect_name_cfstring) + sect_type = eSectionTypeDataObjCCFStrings; + else if (section_name == g_sect_name_go_symtab) + sect_type = eSectionTypeGoSymtab; + else if (section_name == g_sect_name_objc_data || + section_name == g_sect_name_objc_classrefs || + section_name == g_sect_name_objc_superrefs || + section_name == g_sect_name_objc_const || + section_name == g_sect_name_objc_classlist) { + sect_type = eSectionTypeDataPointers; + } + + if (sect_type == eSectionTypeOther) { + switch (mach_sect_type) { + // TODO: categorize sections by other flags for regular + // sections + case S_REGULAR: + if (section_name == g_sect_name_text) + sect_type = eSectionTypeCode; + else if (section_name == g_sect_name_data) + sect_type = eSectionTypeData; + else + sect_type = eSectionTypeOther; + break; + case S_ZEROFILL: + sect_type = eSectionTypeZeroFill; + break; + case S_CSTRING_LITERALS: + sect_type = eSectionTypeDataCString; + break; // section with only literal C strings + case S_4BYTE_LITERALS: + sect_type = eSectionTypeData4; + break; // section with only 4 byte literals + case S_8BYTE_LITERALS: + sect_type = eSectionTypeData8; + break; // section with only 8 byte literals + case S_LITERAL_POINTERS: + sect_type = eSectionTypeDataPointers; + break; // section with only pointers to literals + case S_NON_LAZY_SYMBOL_POINTERS: + sect_type = eSectionTypeDataPointers; + break; // section with only non-lazy symbol pointers + case S_LAZY_SYMBOL_POINTERS: + sect_type = eSectionTypeDataPointers; + break; // section with only lazy symbol pointers + case S_SYMBOL_STUBS: + sect_type = eSectionTypeCode; + break; // section with only symbol stubs, byte size of + // stub in the reserved2 field + case S_MOD_INIT_FUNC_POINTERS: + sect_type = eSectionTypeDataPointers; + break; // section with only function pointers for + // initialization + case S_MOD_TERM_FUNC_POINTERS: + sect_type = eSectionTypeDataPointers; + break; // section with only function pointers for + // termination + case S_COALESCED: + sect_type = eSectionTypeOther; + break; + case S_GB_ZEROFILL: + sect_type = eSectionTypeZeroFill; + break; + case S_INTERPOSING: + sect_type = eSectionTypeCode; + break; // section with only pairs of function pointers for + // interposing + case S_16BYTE_LITERALS: + sect_type = eSectionTypeData16; + break; // section with only 16 byte literals + case S_DTRACE_DOF: + sect_type = eSectionTypeDebug; + break; + case S_LAZY_DYLIB_SYMBOL_POINTERS: + sect_type = eSectionTypeDataPointers; + break; + default: + break; } + } } + + SectionSP section_sp(new Section( + segment_sp, module_sp, this, ++sectID, section_name, + sect_type, sect64.addr - segment_sp->GetFileAddress(), + sect64.size, sect64.offset, + sect64.offset == 0 ? 0 : sect64.size, sect64.align, + sect64.flags)); + // Set the section to be encrypted to match the segment + + bool section_is_encrypted = false; + if (!segment_is_encrypted && load_cmd.filesize != 0) + section_is_encrypted = + encrypted_file_ranges.FindEntryThatContains( + sect64.offset) != NULL; + + section_sp->SetIsEncrypted(segment_is_encrypted || + section_is_encrypted); + section_sp->SetPermissions(segment_permissions); + segment_sp->GetChildren().AddSection(section_sp); + + if (segment_sp->IsFake()) { + segment_sp.reset(); + const_segname.Clear(); + } + } } - else if (load_cmd.cmd == LC_DYSYMTAB) - { - m_dysymtab.cmd = load_cmd.cmd; - m_dysymtab.cmdsize = load_cmd.cmdsize; - m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2); + if (segment_sp && is_dsym) { + if (first_segment_sectID <= sectID) { + lldb::user_id_t sect_uid; + for (sect_uid = first_segment_sectID; sect_uid <= sectID; + ++sect_uid) { + SectionSP curr_section_sp( + segment_sp->GetChildren().FindSectionByID(sect_uid)); + SectionSP next_section_sp; + if (sect_uid + 1 <= sectID) + next_section_sp = + segment_sp->GetChildren().FindSectionByID(sect_uid + 1); + + if (curr_section_sp.get()) { + if (curr_section_sp->GetByteSize() == 0) { + if (next_section_sp.get() != NULL) + curr_section_sp->SetByteSize( + next_section_sp->GetFileAddress() - + curr_section_sp->GetFileAddress()); + else + curr_section_sp->SetByteSize(load_cmd.vmsize); + } + } + } + } } - - offset = load_cmd_offset + load_cmd.cmdsize; + } } + } else if (load_cmd.cmd == LC_DYSYMTAB) { + m_dysymtab.cmd = load_cmd.cmd; + m_dysymtab.cmdsize = load_cmd.cmdsize; + m_data.GetU32(&offset, &m_dysymtab.ilocalsym, + (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2); + } + + offset = load_cmd_offset + load_cmd.cmdsize; + } - - if (section_file_addresses_changed && module_sp.get()) - { - module_sp->SectionFileAddressesChanged(); - } + if (section_file_addresses_changed && module_sp.get()) { + module_sp->SectionFileAddressesChanged(); } + } } -class MachSymtabSectionInfo -{ +class MachSymtabSectionInfo { public: - MachSymtabSectionInfo (SectionList *section_list) : - m_section_list (section_list), - m_section_infos() - { - // Get the number of sections down to a depth of 1 to include - // all segments and their sections, but no other sections that - // may be added for debug map or - m_section_infos.resize(section_list->GetNumSections(1)); - } - - SectionSP - GetSection (uint8_t n_sect, addr_t file_addr) - { - if (n_sect == 0) - return SectionSP(); - if (n_sect < m_section_infos.size()) - { - if (!m_section_infos[n_sect].section_sp) - { - SectionSP section_sp (m_section_list->FindSectionByID (n_sect)); - m_section_infos[n_sect].section_sp = section_sp; - if (section_sp) - { - m_section_infos[n_sect].vm_range.SetBaseAddress (section_sp->GetFileAddress()); - m_section_infos[n_sect].vm_range.SetByteSize (section_sp->GetByteSize()); - } - else - { - Host::SystemLog (Host::eSystemLogError, "error: unable to find section for section %u\n", n_sect); - } - } - if (m_section_infos[n_sect].vm_range.Contains(file_addr)) - { - // Symbol is in section. - return m_section_infos[n_sect].section_sp; - } - else if (m_section_infos[n_sect].vm_range.GetByteSize () == 0 && - m_section_infos[n_sect].vm_range.GetBaseAddress() == file_addr) - { - // Symbol is in section with zero size, but has the same start - // address as the section. This can happen with linker symbols - // (symbols that start with the letter 'l' or 'L'. - return m_section_infos[n_sect].section_sp; - } + MachSymtabSectionInfo(SectionList *section_list) + : m_section_list(section_list), m_section_infos() { + // Get the number of sections down to a depth of 1 to include + // all segments and their sections, but no other sections that + // may be added for debug map or + m_section_infos.resize(section_list->GetNumSections(1)); + } + + SectionSP GetSection(uint8_t n_sect, addr_t file_addr) { + if (n_sect == 0) + return SectionSP(); + if (n_sect < m_section_infos.size()) { + if (!m_section_infos[n_sect].section_sp) { + SectionSP section_sp(m_section_list->FindSectionByID(n_sect)); + m_section_infos[n_sect].section_sp = section_sp; + if (section_sp) { + m_section_infos[n_sect].vm_range.SetBaseAddress( + section_sp->GetFileAddress()); + m_section_infos[n_sect].vm_range.SetByteSize( + section_sp->GetByteSize()); + } else { + Host::SystemLog(Host::eSystemLogError, + "error: unable to find section for section %u\n", + n_sect); } - return m_section_list->FindSectionContainingFileAddress(file_addr); + } + if (m_section_infos[n_sect].vm_range.Contains(file_addr)) { + // Symbol is in section. + return m_section_infos[n_sect].section_sp; + } else if (m_section_infos[n_sect].vm_range.GetByteSize() == 0 && + m_section_infos[n_sect].vm_range.GetBaseAddress() == + file_addr) { + // Symbol is in section with zero size, but has the same start + // address as the section. This can happen with linker symbols + // (symbols that start with the letter 'l' or 'L'. + return m_section_infos[n_sect].section_sp; + } } + return m_section_list->FindSectionContainingFileAddress(file_addr); + } protected: - struct SectionInfo - { - SectionInfo () : - vm_range(), - section_sp () - { - } - - VMRange vm_range; - SectionSP section_sp; - }; - SectionList *m_section_list; - std::vector<SectionInfo> m_section_infos; + struct SectionInfo { + SectionInfo() : vm_range(), section_sp() {} + + VMRange vm_range; + SectionSP section_sp; + }; + SectionList *m_section_list; + std::vector<SectionInfo> m_section_infos; }; -struct TrieEntry -{ - TrieEntry () : - name(), - address(LLDB_INVALID_ADDRESS), - flags (0), - other(0), - import_name() - { - } - - void - Clear () - { - name.Clear(); - address = LLDB_INVALID_ADDRESS; - flags = 0; - other = 0; - import_name.Clear(); - } - - void - Dump () const - { - printf ("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"", - static_cast<unsigned long long>(address), - static_cast<unsigned long long>(flags), - static_cast<unsigned long long>(other), name.GetCString()); - if (import_name) - printf (" -> \"%s\"\n", import_name.GetCString()); - else - printf ("\n"); - } - ConstString name; - uint64_t address; - uint64_t flags; - uint64_t other; - ConstString import_name; +struct TrieEntry { + TrieEntry() + : name(), address(LLDB_INVALID_ADDRESS), flags(0), other(0), + import_name() {} + + void Clear() { + name.Clear(); + address = LLDB_INVALID_ADDRESS; + flags = 0; + other = 0; + import_name.Clear(); + } + + void Dump() const { + printf("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"", + static_cast<unsigned long long>(address), + static_cast<unsigned long long>(flags), + static_cast<unsigned long long>(other), name.GetCString()); + if (import_name) + printf(" -> \"%s\"\n", import_name.GetCString()); + else + printf("\n"); + } + ConstString name; + uint64_t address; + uint64_t flags; + uint64_t other; + ConstString import_name; }; -struct TrieEntryWithOffset -{ - lldb::offset_t nodeOffset; - TrieEntry entry; +struct TrieEntryWithOffset { + lldb::offset_t nodeOffset; + TrieEntry entry; - TrieEntryWithOffset (lldb::offset_t offset) : - nodeOffset (offset), - entry() - { - } + TrieEntryWithOffset(lldb::offset_t offset) : nodeOffset(offset), entry() {} - void - Dump (uint32_t idx) const - { - printf ("[%3u] 0x%16.16llx: ", idx, - static_cast<unsigned long long>(nodeOffset)); - entry.Dump(); - } + void Dump(uint32_t idx) const { + printf("[%3u] 0x%16.16llx: ", idx, + static_cast<unsigned long long>(nodeOffset)); + entry.Dump(); + } - bool - operator<(const TrieEntryWithOffset& other) const - { - return ( nodeOffset < other.nodeOffset ); - } + bool operator<(const TrieEntryWithOffset &other) const { + return (nodeOffset < other.nodeOffset); + } }; -static bool -ParseTrieEntries (DataExtractor &data, - lldb::offset_t offset, - const bool is_arm, - std::vector<llvm::StringRef> &nameSlices, - std::set<lldb::addr_t> &resolver_addresses, - std::vector<TrieEntryWithOffset>& output) -{ - if (!data.ValidOffset(offset)) - return true; - - const uint64_t terminalSize = data.GetULEB128(&offset); - lldb::offset_t children_offset = offset + terminalSize; - if ( terminalSize != 0 ) { - TrieEntryWithOffset e (offset); - e.entry.flags = data.GetULEB128(&offset); - const char *import_name = NULL; - if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) { - e.entry.address = 0; - e.entry.other = data.GetULEB128(&offset); // dylib ordinal - import_name = data.GetCStr(&offset); - } - else { - e.entry.address = data.GetULEB128(&offset); - if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) - { - e.entry.other = data.GetULEB128(&offset); - uint64_t resolver_addr = e.entry.other; - if (is_arm) - resolver_addr &= THUMB_ADDRESS_BIT_MASK; - resolver_addresses.insert(resolver_addr); - } - else - e.entry.other = 0; - } - // Only add symbols that are reexport symbols with a valid import name - if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name && import_name[0]) - { - std::string name; - if (!nameSlices.empty()) - { - for (auto name_slice: nameSlices) - name.append(name_slice.data(), name_slice.size()); - } - if (name.size() > 1) - { - // Skip the leading '_' - e.entry.name.SetCStringWithLength(name.c_str() + 1,name.size() - 1); - } - if (import_name) - { - // Skip the leading '_' - e.entry.import_name.SetCString(import_name+1); - } - output.push_back(e); - } - } - - const uint8_t childrenCount = data.GetU8(&children_offset); - for (uint8_t i=0; i < childrenCount; ++i) { - const char *cstr = data.GetCStr(&children_offset); - if (cstr) - nameSlices.push_back(llvm::StringRef(cstr)); - else - return false; // Corrupt data - lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset); - if (childNodeOffset) - { - if (!ParseTrieEntries(data, - childNodeOffset, - is_arm, - nameSlices, - resolver_addresses, - output)) - { - return false; - } - } - nameSlices.pop_back(); - } +static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset, + const bool is_arm, + std::vector<llvm::StringRef> &nameSlices, + std::set<lldb::addr_t> &resolver_addresses, + std::vector<TrieEntryWithOffset> &output) { + if (!data.ValidOffset(offset)) return true; + + const uint64_t terminalSize = data.GetULEB128(&offset); + lldb::offset_t children_offset = offset + terminalSize; + if (terminalSize != 0) { + TrieEntryWithOffset e(offset); + e.entry.flags = data.GetULEB128(&offset); + const char *import_name = NULL; + if (e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { + e.entry.address = 0; + e.entry.other = data.GetULEB128(&offset); // dylib ordinal + import_name = data.GetCStr(&offset); + } else { + e.entry.address = data.GetULEB128(&offset); + if (e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { + e.entry.other = data.GetULEB128(&offset); + uint64_t resolver_addr = e.entry.other; + if (is_arm) + resolver_addr &= THUMB_ADDRESS_BIT_MASK; + resolver_addresses.insert(resolver_addr); + } else + e.entry.other = 0; + } + // Only add symbols that are reexport symbols with a valid import name + if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name && + import_name[0]) { + std::string name; + if (!nameSlices.empty()) { + for (auto name_slice : nameSlices) + name.append(name_slice.data(), name_slice.size()); + } + if (name.size() > 1) { + // Skip the leading '_' + e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1); + } + if (import_name) { + // Skip the leading '_' + e.entry.import_name.SetCString(import_name + 1); + } + output.push_back(e); + } + } + + const uint8_t childrenCount = data.GetU8(&children_offset); + for (uint8_t i = 0; i < childrenCount; ++i) { + const char *cstr = data.GetCStr(&children_offset); + if (cstr) + nameSlices.push_back(llvm::StringRef(cstr)); + else + return false; // Corrupt data + lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset); + if (childNodeOffset) { + if (!ParseTrieEntries(data, childNodeOffset, is_arm, nameSlices, + resolver_addresses, output)) { + return false; + } + } + nameSlices.pop_back(); + } + return true; } // Read the UUID out of a dyld_shared_cache file on-disk. -UUID -ObjectFileMachO::GetSharedCacheUUID (FileSpec dyld_shared_cache, const ByteOrder byte_order, const uint32_t addr_byte_size) -{ - UUID dsc_uuid; - DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1)); - if (dsc_data_sp) - { - DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size); - - char version_str[7]; - lldb::offset_t offset = 0; - memcpy (version_str, dsc_header_data.GetData (&offset, 6), 6); - version_str[6] = '\0'; - if (strcmp (version_str, "dyld_v") == 0) - { - offset = offsetof (struct lldb_copy_dyld_cache_header_v1, uuid); - uint8_t uuid_bytes[sizeof (uuid_t)]; - memcpy (uuid_bytes, dsc_header_data.GetData (&offset, sizeof (uuid_t)), sizeof (uuid_t)); - dsc_uuid.SetBytes (uuid_bytes); - } +UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache, + const ByteOrder byte_order, + const uint32_t addr_byte_size) { + UUID dsc_uuid; + DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal( + 0, sizeof(struct lldb_copy_dyld_cache_header_v1)); + if (dsc_data_sp) { + DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size); + + char version_str[7]; + lldb::offset_t offset = 0; + memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6); + version_str[6] = '\0'; + if (strcmp(version_str, "dyld_v") == 0) { + offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid); + uint8_t uuid_bytes[sizeof(uuid_t)]; + memcpy(uuid_bytes, dsc_header_data.GetData(&offset, sizeof(uuid_t)), + sizeof(uuid_t)); + dsc_uuid.SetBytes(uuid_bytes); } - return dsc_uuid; + } + return dsc_uuid; } -size_t -ObjectFileMachO::ParseSymtab () -{ - Timer scoped_timer(LLVM_PRETTY_FUNCTION, - "ObjectFileMachO::ParseSymtab () module = %s", - m_file.GetFilename().AsCString("")); - ModuleSP module_sp (GetModule()); - if (!module_sp) - return 0; - - struct symtab_command symtab_load_command = { 0, 0, 0, 0, 0, 0 }; - struct linkedit_data_command function_starts_load_command = { 0, 0, 0, 0 }; - struct dyld_info_command dyld_info = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts; - FunctionStarts function_starts; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - uint32_t i; - FileSpecList dylib_files; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); - static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_"); - - for (i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t cmd_offset = offset; - // Read in the load command and load command size - struct load_command lc; - if (m_data.GetU32(&offset, &lc, 2) == NULL) - break; - // Watch for the symbol table load command - switch (lc.cmd) - { - case LC_SYMTAB: - symtab_load_command.cmd = lc.cmd; - symtab_load_command.cmdsize = lc.cmdsize; - // Read in the rest of the symtab load command - if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) == 0) // fill in symoff, nsyms, stroff, strsize fields - return 0; - if (symtab_load_command.symoff == 0) - { - if (log) - module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0"); - return 0; - } - - if (symtab_load_command.stroff == 0) - { - if (log) - module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0"); - return 0; - } - - if (symtab_load_command.nsyms == 0) - { - if (log) - module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0"); - return 0; - } - - if (symtab_load_command.strsize == 0) - { - if (log) - module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0"); - return 0; - } - break; - - case LC_DYLD_INFO: - case LC_DYLD_INFO_ONLY: - if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) - { - dyld_info.cmd = lc.cmd; - dyld_info.cmdsize = lc.cmdsize; - } - else - { - memset (&dyld_info, 0, sizeof(dyld_info)); - } - break; +size_t ObjectFileMachO::ParseSymtab() { + Timer scoped_timer(LLVM_PRETTY_FUNCTION, + "ObjectFileMachO::ParseSymtab () module = %s", + m_file.GetFilename().AsCString("")); + ModuleSP module_sp(GetModule()); + if (!module_sp) + return 0; - case LC_LOAD_DYLIB: - case LC_LOAD_WEAK_DYLIB: - case LC_REEXPORT_DYLIB: - case LC_LOADFVMLIB: - case LC_LOAD_UPWARD_DYLIB: - { - uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); - const char *path = m_data.PeekCStr(name_offset); - if (path) - { - FileSpec file_spec(path, false); - // Strip the path if there is @rpath, @executable, etc so we just use the basename - if (path[0] == '@') - file_spec.GetDirectory().Clear(); - - if (lc.cmd == LC_REEXPORT_DYLIB) - { - m_reexported_dylibs.AppendIfUnique(file_spec); - } + struct symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0}; + struct linkedit_data_command function_starts_load_command = {0, 0, 0, 0}; + struct dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts; + FunctionStarts function_starts; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + uint32_t i; + FileSpecList dylib_files; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS)); + static const llvm::StringRef g_objc_v2_prefix_class("_OBJC_CLASS_$_"); + static const llvm::StringRef g_objc_v2_prefix_metaclass("_OBJC_METACLASS_$_"); + static const llvm::StringRef g_objc_v2_prefix_ivar("_OBJC_IVAR_$_"); + + for (i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + // Read in the load command and load command size + struct load_command lc; + if (m_data.GetU32(&offset, &lc, 2) == NULL) + break; + // Watch for the symbol table load command + switch (lc.cmd) { + case LC_SYMTAB: + symtab_load_command.cmd = lc.cmd; + symtab_load_command.cmdsize = lc.cmdsize; + // Read in the rest of the symtab load command + if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) == + 0) // fill in symoff, nsyms, stroff, strsize fields + return 0; + if (symtab_load_command.symoff == 0) { + if (log) + module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0"); + return 0; + } - dylib_files.Append(file_spec); - } - } - break; + if (symtab_load_command.stroff == 0) { + if (log) + module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0"); + return 0; + } - case LC_FUNCTION_STARTS: - function_starts_load_command.cmd = lc.cmd; - function_starts_load_command.cmdsize = lc.cmdsize; - if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) == NULL) // fill in symoff, nsyms, stroff, strsize fields - memset (&function_starts_load_command, 0, sizeof(function_starts_load_command)); - break; + if (symtab_load_command.nsyms == 0) { + if (log) + module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0"); + return 0; + } - default: - break; + if (symtab_load_command.strsize == 0) { + if (log) + module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0"); + return 0; + } + break; + + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: + if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) { + dyld_info.cmd = lc.cmd; + dyld_info.cmdsize = lc.cmdsize; + } else { + memset(&dyld_info, 0, sizeof(dyld_info)); + } + break; + + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + case LC_REEXPORT_DYLIB: + case LC_LOADFVMLIB: + case LC_LOAD_UPWARD_DYLIB: { + uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); + const char *path = m_data.PeekCStr(name_offset); + if (path) { + FileSpec file_spec(path, false); + // Strip the path if there is @rpath, @executable, etc so we just use + // the basename + if (path[0] == '@') + file_spec.GetDirectory().Clear(); + + if (lc.cmd == LC_REEXPORT_DYLIB) { + m_reexported_dylibs.AppendIfUnique(file_spec); } - offset = cmd_offset + lc.cmdsize; - } - - if (symtab_load_command.cmd) - { - Symtab *symtab = m_symtab_ap.get(); - SectionList *section_list = GetSectionList(); - if (section_list == NULL) - return 0; - - const uint32_t addr_byte_size = m_data.GetAddressByteSize(); - const ByteOrder byte_order = m_data.GetByteOrder(); - bool bit_width_32 = addr_byte_size == 4; - const size_t nlist_byte_size = bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64); - - DataExtractor nlist_data (NULL, 0, byte_order, addr_byte_size); - DataExtractor strtab_data (NULL, 0, byte_order, addr_byte_size); - DataExtractor function_starts_data (NULL, 0, byte_order, addr_byte_size); - DataExtractor indirect_symbol_index_data (NULL, 0, byte_order, addr_byte_size); - DataExtractor dyld_trie_data (NULL, 0, byte_order, addr_byte_size); - - const addr_t nlist_data_byte_size = symtab_load_command.nsyms * nlist_byte_size; - const addr_t strtab_data_byte_size = symtab_load_command.strsize; - addr_t strtab_addr = LLDB_INVALID_ADDRESS; - - ProcessSP process_sp (m_process_wp.lock()); - Process *process = process_sp.get(); - - uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete; - - if (process && m_header.filetype != llvm::MachO::MH_OBJECT) - { - Target &target = process->GetTarget(); - - memory_module_load_level = target.GetMemoryModuleLoadLevel(); - - SectionSP linkedit_section_sp(section_list->FindSectionByName(GetSegmentNameLINKEDIT())); - // Reading mach file from memory in a process or core file... - - if (linkedit_section_sp) - { - addr_t linkedit_load_addr = linkedit_section_sp->GetLoadBaseAddress(&target); - if (linkedit_load_addr == LLDB_INVALID_ADDRESS) - { - // We might be trying to access the symbol table before the __LINKEDIT's load - // address has been set in the target. We can't fail to read the symbol table, - // so calculate the right address manually - linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage(m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get()); - } - const addr_t linkedit_file_offset = linkedit_section_sp->GetFileOffset(); - const addr_t symoff_addr = linkedit_load_addr + symtab_load_command.symoff - linkedit_file_offset; - strtab_addr = linkedit_load_addr + symtab_load_command.stroff - linkedit_file_offset; - - bool data_was_read = false; - -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - if (m_header.flags & 0x80000000u && process->GetAddressByteSize() == sizeof (void*)) - { - // This mach-o memory file is in the dyld shared cache. If this - // program is not remote and this is iOS, then this process will - // share the same shared cache as the process we are debugging and - // we can read the entire __LINKEDIT from the address space in this - // process. This is a needed optimization that is used for local iOS - // debugging only since all shared libraries in the shared cache do - // not have corresponding files that exist in the file system of the - // device. They have been combined into a single file. This means we - // always have to load these files from memory. All of the symbol and - // string tables from all of the __LINKEDIT sections from the shared - // libraries in the shared cache have been merged into a single large - // symbol and string table. Reading all of this symbol and string table - // data across can slow down debug launch times, so we optimize this by - // reading the memory for the __LINKEDIT section from this process. - - UUID lldb_shared_cache(GetLLDBSharedCacheUUID()); - UUID process_shared_cache(GetProcessSharedCacheUUID(process)); - bool use_lldb_cache = true; - if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && lldb_shared_cache != process_shared_cache) - { - use_lldb_cache = false; - ModuleSP module_sp (GetModule()); - if (module_sp) - module_sp->ReportWarning ("shared cache in process does not match lldb's own shared cache, startup will be slow."); - - } - - PlatformSP platform_sp (target.GetPlatform()); - if (platform_sp && platform_sp->IsHost() && use_lldb_cache) - { - data_was_read = true; - nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, eByteOrderLittle); - strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, eByteOrderLittle); - if (function_starts_load_command.cmd) - { - const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset; - function_starts_data.SetData ((void *)func_start_addr, function_starts_load_command.datasize, eByteOrderLittle); - } - } - } -#endif + dylib_files.Append(file_spec); + } + } break; + + case LC_FUNCTION_STARTS: + function_starts_load_command.cmd = lc.cmd; + function_starts_load_command.cmdsize = lc.cmdsize; + if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) == + NULL) // fill in symoff, nsyms, stroff, strsize fields + memset(&function_starts_load_command, 0, + sizeof(function_starts_load_command)); + break; + + default: + break; + } + offset = cmd_offset + lc.cmdsize; + } - if (!data_was_read) - { - // Always load dyld - the dynamic linker - from memory if we didn't find a binary anywhere else. - // lldb will not register dylib/framework/bundle loads/unloads if we don't have the dyld symbols, - // we force dyld to load from memory despite the user's target.memory-module-load-level setting. - if (memory_module_load_level == eMemoryModuleLoadLevelComplete || m_header.filetype == llvm::MachO::MH_DYLINKER) - { - DataBufferSP nlist_data_sp (ReadMemory (process_sp, symoff_addr, nlist_data_byte_size)); - if (nlist_data_sp) - nlist_data.SetData (nlist_data_sp, 0, nlist_data_sp->GetByteSize()); - // Load strings individually from memory when loading from memory since shared cache - // string tables contain strings for all symbols from all shared cached libraries - //DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, strtab_data_byte_size)); - //if (strtab_data_sp) - // strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize()); - if (m_dysymtab.nindirectsyms != 0) - { - const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab.indirectsymoff - linkedit_file_offset; - DataBufferSP indirect_syms_data_sp (ReadMemory (process_sp, indirect_syms_addr, m_dysymtab.nindirectsyms * 4)); - if (indirect_syms_data_sp) - indirect_symbol_index_data.SetData (indirect_syms_data_sp, 0, indirect_syms_data_sp->GetByteSize()); - } - } - else if (memory_module_load_level >= eMemoryModuleLoadLevelPartial) - { - if (function_starts_load_command.cmd) - { - const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset; - DataBufferSP func_start_data_sp (ReadMemory (process_sp, func_start_addr, function_starts_load_command.datasize)); - if (func_start_data_sp) - function_starts_data.SetData (func_start_data_sp, 0, func_start_data_sp->GetByteSize()); - } - } - } - } + if (symtab_load_command.cmd) { + Symtab *symtab = m_symtab_ap.get(); + SectionList *section_list = GetSectionList(); + if (section_list == NULL) + return 0; + + const uint32_t addr_byte_size = m_data.GetAddressByteSize(); + const ByteOrder byte_order = m_data.GetByteOrder(); + bool bit_width_32 = addr_byte_size == 4; + const size_t nlist_byte_size = + bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64); + + DataExtractor nlist_data(NULL, 0, byte_order, addr_byte_size); + DataExtractor strtab_data(NULL, 0, byte_order, addr_byte_size); + DataExtractor function_starts_data(NULL, 0, byte_order, addr_byte_size); + DataExtractor indirect_symbol_index_data(NULL, 0, byte_order, + addr_byte_size); + DataExtractor dyld_trie_data(NULL, 0, byte_order, addr_byte_size); + + const addr_t nlist_data_byte_size = + symtab_load_command.nsyms * nlist_byte_size; + const addr_t strtab_data_byte_size = symtab_load_command.strsize; + addr_t strtab_addr = LLDB_INVALID_ADDRESS; + + ProcessSP process_sp(m_process_wp.lock()); + Process *process = process_sp.get(); + + uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete; + + if (process && m_header.filetype != llvm::MachO::MH_OBJECT) { + Target &target = process->GetTarget(); + + memory_module_load_level = target.GetMemoryModuleLoadLevel(); + + SectionSP linkedit_section_sp( + section_list->FindSectionByName(GetSegmentNameLINKEDIT())); + // Reading mach file from memory in a process or core file... + + if (linkedit_section_sp) { + addr_t linkedit_load_addr = + linkedit_section_sp->GetLoadBaseAddress(&target); + if (linkedit_load_addr == LLDB_INVALID_ADDRESS) { + // We might be trying to access the symbol table before the + // __LINKEDIT's load + // address has been set in the target. We can't fail to read the + // symbol table, + // so calculate the right address manually + linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage( + m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get()); } - else - { - nlist_data.SetData (m_data, - symtab_load_command.symoff, - nlist_data_byte_size); - strtab_data.SetData (m_data, - symtab_load_command.stroff, - strtab_data_byte_size); - - if (dyld_info.export_size > 0) - { - dyld_trie_data.SetData (m_data, - dyld_info.export_off, - dyld_info.export_size); - } - if (m_dysymtab.nindirectsyms != 0) - { - indirect_symbol_index_data.SetData (m_data, - m_dysymtab.indirectsymoff, - m_dysymtab.nindirectsyms * 4); - } - if (function_starts_load_command.cmd) - { - function_starts_data.SetData (m_data, - function_starts_load_command.dataoff, - function_starts_load_command.datasize); + const addr_t linkedit_file_offset = + linkedit_section_sp->GetFileOffset(); + const addr_t symoff_addr = linkedit_load_addr + + symtab_load_command.symoff - + linkedit_file_offset; + strtab_addr = linkedit_load_addr + symtab_load_command.stroff - + linkedit_file_offset; + + bool data_was_read = false; + +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) + if (m_header.flags & 0x80000000u && + process->GetAddressByteSize() == sizeof(void *)) { + // This mach-o memory file is in the dyld shared cache. If this + // program is not remote and this is iOS, then this process will + // share the same shared cache as the process we are debugging and + // we can read the entire __LINKEDIT from the address space in this + // process. This is a needed optimization that is used for local iOS + // debugging only since all shared libraries in the shared cache do + // not have corresponding files that exist in the file system of the + // device. They have been combined into a single file. This means we + // always have to load these files from memory. All of the symbol and + // string tables from all of the __LINKEDIT sections from the shared + // libraries in the shared cache have been merged into a single large + // symbol and string table. Reading all of this symbol and string + // table + // data across can slow down debug launch times, so we optimize this + // by + // reading the memory for the __LINKEDIT section from this process. + + UUID lldb_shared_cache(GetLLDBSharedCacheUUID()); + UUID process_shared_cache(GetProcessSharedCacheUUID(process)); + bool use_lldb_cache = true; + if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && + lldb_shared_cache != process_shared_cache) { + use_lldb_cache = false; + ModuleSP module_sp(GetModule()); + if (module_sp) + module_sp->ReportWarning("shared cache in process does not match " + "lldb's own shared cache, startup will " + "be slow."); + } + + PlatformSP platform_sp(target.GetPlatform()); + if (platform_sp && platform_sp->IsHost() && use_lldb_cache) { + data_was_read = true; + nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, + eByteOrderLittle); + strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, + eByteOrderLittle); + if (function_starts_load_command.cmd) { + const addr_t func_start_addr = + linkedit_load_addr + function_starts_load_command.dataoff - + linkedit_file_offset; + function_starts_data.SetData( + (void *)func_start_addr, + function_starts_load_command.datasize, eByteOrderLittle); } + } } +#endif - if (nlist_data.GetByteSize() == 0 && memory_module_load_level == eMemoryModuleLoadLevelComplete) - { - if (log) - module_sp->LogMessage(log, "failed to read nlist data"); - return 0; - } - - const bool have_strtab_data = strtab_data.GetByteSize() > 0; - if (!have_strtab_data) - { - if (process) - { - if (strtab_addr == LLDB_INVALID_ADDRESS) - { - if (log) - module_sp->LogMessage(log, "failed to locate the strtab in memory"); - return 0; - } + if (!data_was_read) { + // Always load dyld - the dynamic linker - from memory if we didn't + // find a binary anywhere else. + // lldb will not register dylib/framework/bundle loads/unloads if we + // don't have the dyld symbols, + // we force dyld to load from memory despite the user's + // target.memory-module-load-level setting. + if (memory_module_load_level == eMemoryModuleLoadLevelComplete || + m_header.filetype == llvm::MachO::MH_DYLINKER) { + DataBufferSP nlist_data_sp( + ReadMemory(process_sp, symoff_addr, nlist_data_byte_size)); + if (nlist_data_sp) + nlist_data.SetData(nlist_data_sp, 0, + nlist_data_sp->GetByteSize()); + // Load strings individually from memory when loading from memory + // since shared cache + // string tables contain strings for all symbols from all shared + // cached libraries + // DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, + // strtab_data_byte_size)); + // if (strtab_data_sp) + // strtab_data.SetData (strtab_data_sp, 0, + // strtab_data_sp->GetByteSize()); + if (m_dysymtab.nindirectsyms != 0) { + const addr_t indirect_syms_addr = linkedit_load_addr + + m_dysymtab.indirectsymoff - + linkedit_file_offset; + DataBufferSP indirect_syms_data_sp( + ReadMemory(process_sp, indirect_syms_addr, + m_dysymtab.nindirectsyms * 4)); + if (indirect_syms_data_sp) + indirect_symbol_index_data.SetData( + indirect_syms_data_sp, 0, + indirect_syms_data_sp->GetByteSize()); } - else - { - if (log) - module_sp->LogMessage(log, "failed to read strtab data"); - return 0; + } else if (memory_module_load_level >= + eMemoryModuleLoadLevelPartial) { + if (function_starts_load_command.cmd) { + const addr_t func_start_addr = + linkedit_load_addr + function_starts_load_command.dataoff - + linkedit_file_offset; + DataBufferSP func_start_data_sp( + ReadMemory(process_sp, func_start_addr, + function_starts_load_command.datasize)); + if (func_start_data_sp) + function_starts_data.SetData(func_start_data_sp, 0, + func_start_data_sp->GetByteSize()); } + } } + } + } else { + nlist_data.SetData(m_data, symtab_load_command.symoff, + nlist_data_byte_size); + strtab_data.SetData(m_data, symtab_load_command.stroff, + strtab_data_byte_size); + + if (dyld_info.export_size > 0) { + dyld_trie_data.SetData(m_data, dyld_info.export_off, + dyld_info.export_size); + } + + if (m_dysymtab.nindirectsyms != 0) { + indirect_symbol_index_data.SetData(m_data, m_dysymtab.indirectsymoff, + m_dysymtab.nindirectsyms * 4); + } + if (function_starts_load_command.cmd) { + function_starts_data.SetData(m_data, + function_starts_load_command.dataoff, + function_starts_load_command.datasize); + } + } - const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT(); - const ConstString &g_segment_name_DATA = GetSegmentNameDATA(); - const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY(); - const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST(); - const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC(); - const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame(); - SectionSP text_section_sp(section_list->FindSectionByName(g_segment_name_TEXT)); - SectionSP data_section_sp(section_list->FindSectionByName(g_segment_name_DATA)); - SectionSP data_dirty_section_sp(section_list->FindSectionByName(g_segment_name_DATA_DIRTY)); - SectionSP data_const_section_sp(section_list->FindSectionByName(g_segment_name_DATA_CONST)); - SectionSP objc_section_sp(section_list->FindSectionByName(g_segment_name_OBJC)); - SectionSP eh_frame_section_sp; - if (text_section_sp.get()) - eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName (g_section_name_eh_frame); - else - eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame); - - const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM); - - // lldb works best if it knows the start address of all functions in a module. - // Linker symbols or debug info are normally the best source of information for start addr / size but - // they may be stripped in a released binary. - // Two additional sources of information exist in Mach-O binaries: - // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each function's start address in the - // binary, relative to the text section. - // eh_frame - the eh_frame FDEs have the start addr & size of each function - // LC_FUNCTION_STARTS is the fastest source to read in, and is present on all modern binaries. - // Binaries built to run on older releases may need to use eh_frame information. - - if (text_section_sp && function_starts_data.GetByteSize()) - { - FunctionStarts::Entry function_start_entry; - function_start_entry.data = false; - lldb::offset_t function_start_offset = 0; - function_start_entry.addr = text_section_sp->GetFileAddress(); - uint64_t delta; - while ((delta = function_starts_data.GetULEB128(&function_start_offset)) > 0) - { - // Now append the current entry - function_start_entry.addr += delta; - function_starts.Append(function_start_entry); - } - } - else - { - // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the load command claiming an eh_frame - // but it doesn't actually have the eh_frame content. And if we have a dSYM, we don't need to do any - // of this fill-in-the-missing-symbols works anyway - the debug info should give us all the functions in - // the module. - if (text_section_sp.get() && eh_frame_section_sp.get() && m_type != eTypeDebugInfo) - { - DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, eRegisterKindEHFrame, true); - DWARFCallFrameInfo::FunctionAddressAndSizeVector functions; - eh_frame.GetFunctionAddressAndSizeVector (functions); - addr_t text_base_addr = text_section_sp->GetFileAddress(); - size_t count = functions.GetSize(); - for (size_t i = 0; i < count; ++i) - { - const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = functions.GetEntryAtIndex (i); - if (func) - { - FunctionStarts::Entry function_start_entry; - function_start_entry.addr = func->base - text_base_addr; - function_starts.Append(function_start_entry); - } - } - } - } + if (nlist_data.GetByteSize() == 0 && + memory_module_load_level == eMemoryModuleLoadLevelComplete) { + if (log) + module_sp->LogMessage(log, "failed to read nlist data"); + return 0; + } - const size_t function_starts_count = function_starts.GetSize(); - - // For user process binaries (executables, dylibs, frameworks, bundles), if we don't have - // LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume the binary - // has been stripped. Don't allow assembly language instruction emulation because we don't - // know proper function start boundaries. - // - // For all other types of binaries (kernels, stand-alone bare board binaries, kexts), they - // may not have LC_FUNCTION_STARTS / eh_frame sections - we should not make any assumptions - // about them based on that. - if (function_starts_count == 0 && CalculateStrata() == eStrataUser) - { - m_allow_assembly_emulation_unwind_plans = false; - Log *unwind_or_symbol_log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND)); - - if (unwind_or_symbol_log) - module_sp->LogMessage(unwind_or_symbol_log, "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds"); + const bool have_strtab_data = strtab_data.GetByteSize() > 0; + if (!have_strtab_data) { + if (process) { + if (strtab_addr == LLDB_INVALID_ADDRESS) { + if (log) + module_sp->LogMessage(log, "failed to locate the strtab in memory"); + return 0; } + } else { + if (log) + module_sp->LogMessage(log, "failed to read strtab data"); + return 0; + } + } - const user_id_t TEXT_eh_frame_sectID = - eh_frame_section_sp.get() ? eh_frame_section_sp->GetID() - : static_cast<user_id_t>(NO_SECT); - - lldb::offset_t nlist_data_offset = 0; - - uint32_t N_SO_index = UINT32_MAX; - - MachSymtabSectionInfo section_info (section_list); - std::vector<uint32_t> N_FUN_indexes; - std::vector<uint32_t> N_NSYM_indexes; - std::vector<uint32_t> N_INCL_indexes; - std::vector<uint32_t> N_BRAC_indexes; - std::vector<uint32_t> N_COMM_indexes; - typedef std::multimap <uint64_t, uint32_t> ValueToSymbolIndexMap; - typedef std::map <uint32_t, uint32_t> NListIndexToSymbolIndexMap; - typedef std::map <const char *, uint32_t> ConstNameToSymbolIndexMap; - ValueToSymbolIndexMap N_FUN_addr_to_sym_idx; - ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx; - ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx; - // Any symbols that get merged into another will get an entry - // in this map so we know - NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx; - uint32_t nlist_idx = 0; - Symbol *symbol_ptr = NULL; - - uint32_t sym_idx = 0; - Symbol *sym = NULL; - size_t num_syms = 0; - std::string memory_symbol_name; - uint32_t unmapped_local_symbols_found = 0; - - std::vector<TrieEntryWithOffset> trie_entries; - std::set<lldb::addr_t> resolver_addresses; - - if (dyld_trie_data.GetByteSize() > 0) - { - std::vector<llvm::StringRef> nameSlices; - ParseTrieEntries (dyld_trie_data, - 0, - is_arm, - nameSlices, - resolver_addresses, - trie_entries); - - ConstString text_segment_name ("__TEXT"); - SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name); - if (text_segment_sp) - { - const lldb::addr_t text_segment_file_addr = text_segment_sp->GetFileAddress(); - if (text_segment_file_addr != LLDB_INVALID_ADDRESS) - { - for (auto &e : trie_entries) - e.entry.address += text_segment_file_addr; - } - } + const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT(); + const ConstString &g_segment_name_DATA = GetSegmentNameDATA(); + const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY(); + const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST(); + const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC(); + const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame(); + SectionSP text_section_sp( + section_list->FindSectionByName(g_segment_name_TEXT)); + SectionSP data_section_sp( + section_list->FindSectionByName(g_segment_name_DATA)); + SectionSP data_dirty_section_sp( + section_list->FindSectionByName(g_segment_name_DATA_DIRTY)); + SectionSP data_const_section_sp( + section_list->FindSectionByName(g_segment_name_DATA_CONST)); + SectionSP objc_section_sp( + section_list->FindSectionByName(g_segment_name_OBJC)); + SectionSP eh_frame_section_sp; + if (text_section_sp.get()) + eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName( + g_section_name_eh_frame); + else + eh_frame_section_sp = + section_list->FindSectionByName(g_section_name_eh_frame); + + const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM); + + // lldb works best if it knows the start address of all functions in a + // module. + // Linker symbols or debug info are normally the best source of information + // for start addr / size but + // they may be stripped in a released binary. + // Two additional sources of information exist in Mach-O binaries: + // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each + // function's start address in the + // binary, relative to the text section. + // eh_frame - the eh_frame FDEs have the start addr & size of + // each function + // LC_FUNCTION_STARTS is the fastest source to read in, and is present on + // all modern binaries. + // Binaries built to run on older releases may need to use eh_frame + // information. + + if (text_section_sp && function_starts_data.GetByteSize()) { + FunctionStarts::Entry function_start_entry; + function_start_entry.data = false; + lldb::offset_t function_start_offset = 0; + function_start_entry.addr = text_section_sp->GetFileAddress(); + uint64_t delta; + while ((delta = function_starts_data.GetULEB128(&function_start_offset)) > + 0) { + // Now append the current entry + function_start_entry.addr += delta; + function_starts.Append(function_start_entry); + } + } else { + // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the + // load command claiming an eh_frame + // but it doesn't actually have the eh_frame content. And if we have a + // dSYM, we don't need to do any + // of this fill-in-the-missing-symbols works anyway - the debug info + // should give us all the functions in + // the module. + if (text_section_sp.get() && eh_frame_section_sp.get() && + m_type != eTypeDebugInfo) { + DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, + eRegisterKindEHFrame, true); + DWARFCallFrameInfo::FunctionAddressAndSizeVector functions; + eh_frame.GetFunctionAddressAndSizeVector(functions); + addr_t text_base_addr = text_section_sp->GetFileAddress(); + size_t count = functions.GetSize(); + for (size_t i = 0; i < count; ++i) { + const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = + functions.GetEntryAtIndex(i); + if (func) { + FunctionStarts::Entry function_start_entry; + function_start_entry.addr = func->base - text_base_addr; + function_starts.Append(function_start_entry); + } } + } + } - typedef std::set<ConstString> IndirectSymbols; - IndirectSymbols indirect_symbol_names; - -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - - // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been optimized by moving LOCAL - // symbols out of the memory mapped portion of the DSC. The symbol information has all been retained, - // but it isn't available in the normal nlist data. However, there *are* duplicate entries of *some* - // LOCAL symbols in the normal nlist data. To handle this situation correctly, we must first attempt - // to parse any DSC unmapped symbol information. If we find any, we set a flag that tells the normal - // nlist parser to ignore all LOCAL symbols. - - if (m_header.flags & 0x80000000u) - { - // Before we can start mapping the DSC, we need to make certain the target process is actually - // using the cache we can find. - - // Next we need to determine the correct path for the dyld shared cache. - - ArchSpec header_arch; - GetArchitecture(header_arch); - char dsc_path[PATH_MAX]; - char dsc_path_development[PATH_MAX]; - - snprintf(dsc_path, sizeof(dsc_path), "%s%s%s", - "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */ - "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ - header_arch.GetArchitectureName()); - - snprintf(dsc_path_development, sizeof(dsc_path), "%s%s%s%s", - "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */ - "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ - header_arch.GetArchitectureName(), - ".development"); - - FileSpec dsc_nondevelopment_filespec(dsc_path, false); - FileSpec dsc_development_filespec(dsc_path_development, false); - FileSpec dsc_filespec; - - UUID dsc_uuid; - UUID process_shared_cache_uuid; - - if (process) - { - process_shared_cache_uuid = GetProcessSharedCacheUUID(process); - } - - // First see if we can find an exact match for the inferior process shared cache UUID in - // the development or non-development shared caches on disk. - if (process_shared_cache_uuid.IsValid()) - { - if (dsc_development_filespec.Exists()) - { - UUID dsc_development_uuid = GetSharedCacheUUID (dsc_development_filespec, byte_order, addr_byte_size); - if (dsc_development_uuid.IsValid() && dsc_development_uuid == process_shared_cache_uuid) - { - dsc_filespec = dsc_development_filespec; - dsc_uuid = dsc_development_uuid; - } - } - if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists()) - { - UUID dsc_nondevelopment_uuid = GetSharedCacheUUID (dsc_nondevelopment_filespec, byte_order, addr_byte_size); - if (dsc_nondevelopment_uuid.IsValid() && dsc_nondevelopment_uuid == process_shared_cache_uuid) - { - dsc_filespec = dsc_nondevelopment_filespec; - dsc_uuid = dsc_nondevelopment_uuid; - } - } - } - - // Failing a UUID match, prefer the development dyld_shared cache if both are present. - if (!dsc_filespec.Exists()) - { - if (dsc_development_filespec.Exists()) - { - dsc_filespec = dsc_development_filespec; - } - else - { - dsc_filespec = dsc_nondevelopment_filespec; - } - } - - /* The dyld_cache_header has a pointer to the dyld_cache_local_symbols_info structure (localSymbolsOffset). - The dyld_cache_local_symbols_info structure gives us three things: - 1. The start and count of the nlist records in the dyld_shared_cache file - 2. The start and size of the strings for these nlist records - 3. The start and count of dyld_cache_local_symbols_entry entries - - There is one dyld_cache_local_symbols_entry per dylib/framework in the dyld shared cache. - The "dylibOffset" field is the Mach-O header of this dylib/framework in the dyld shared cache. - The dyld_cache_local_symbols_entry also lists the start of this dylib/framework's nlist records - and the count of how many nlist records there are for this dylib/framework. - */ - - // Process the dyld shared cache header to find the unmapped symbols - - DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1)); - if (!dsc_uuid.IsValid()) - { - dsc_uuid = GetSharedCacheUUID (dsc_filespec, byte_order, addr_byte_size); - } - if (dsc_data_sp) - { - DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size); - - bool uuid_match = true; - if (dsc_uuid.IsValid() && process) - { - if (process_shared_cache_uuid.IsValid() && dsc_uuid != process_shared_cache_uuid) - { - // The on-disk dyld_shared_cache file is not the same as the one in this - // process' memory, don't use it. - uuid_match = false; - ModuleSP module_sp (GetModule()); - if (module_sp) - module_sp->ReportWarning ("process shared cache does not match on-disk dyld_shared_cache file, some symbol names will be missing."); - } - } - - offset = offsetof (struct lldb_copy_dyld_cache_header_v1, mappingOffset); - - uint32_t mappingOffset = dsc_header_data.GetU32(&offset); - - // If the mappingOffset points to a location inside the header, we've - // opened an old dyld shared cache, and should not proceed further. - if (uuid_match && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) - { - - DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info)); - DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, byte_order, addr_byte_size); - offset = 0; - - // The File addresses (from the in-memory Mach-O load commands) for the shared libraries - // in the shared library cache need to be adjusted by an offset to match up with the - // dylibOffset identifying field in the dyld_cache_local_symbol_entry's. This offset is - // recorded in mapping_offset_value. - const uint64_t mapping_offset_value = dsc_mapping_info_data.GetU64(&offset); - - offset = offsetof (struct lldb_copy_dyld_cache_header_v1, localSymbolsOffset); - uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset); - uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset); + const size_t function_starts_count = function_starts.GetSize(); - if (localSymbolsOffset && localSymbolsSize) - { - // Map the local symbols - if (DataBufferSP dsc_local_symbols_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(localSymbolsOffset, localSymbolsSize)) - { - DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, byte_order, addr_byte_size); - - offset = 0; - - typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap; - typedef std::map<uint32_t, ConstString> SymbolIndexToName; - UndefinedNameToDescMap undefined_name_to_desc; - SymbolIndexToName reexport_shlib_needs_fixup; - - - // Read the local_symbols_infos struct in one shot - struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info; - dsc_local_symbols_data.GetU32(&offset, &local_symbols_info.nlistOffset, 6); - - SectionSP text_section_sp(section_list->FindSectionByName(GetSegmentNameTEXT())); - - uint32_t header_file_offset = (text_section_sp->GetFileAddress() - mapping_offset_value); - - offset = local_symbols_info.entriesOffset; - for (uint32_t entry_index = 0; entry_index < local_symbols_info.entriesCount; entry_index++) - { - struct lldb_copy_dyld_cache_local_symbols_entry local_symbols_entry; - local_symbols_entry.dylibOffset = dsc_local_symbols_data.GetU32(&offset); - local_symbols_entry.nlistStartIndex = dsc_local_symbols_data.GetU32(&offset); - local_symbols_entry.nlistCount = dsc_local_symbols_data.GetU32(&offset); - - if (header_file_offset == local_symbols_entry.dylibOffset) - { - unmapped_local_symbols_found = local_symbols_entry.nlistCount; - - // The normal nlist code cannot correctly size the Symbols array, we need to allocate it here. - sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms + unmapped_local_symbols_found - m_dysymtab.nlocalsym); - num_syms = symtab->GetNumSymbols(); - - nlist_data_offset = local_symbols_info.nlistOffset + (nlist_byte_size * local_symbols_entry.nlistStartIndex); - uint32_t string_table_offset = local_symbols_info.stringsOffset; - - for (uint32_t nlist_index = 0; nlist_index < local_symbols_entry.nlistCount; nlist_index++) - { - ///////////////////////////// - { - struct nlist_64 nlist; - if (!dsc_local_symbols_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size)) - break; - - nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked(&nlist_data_offset); - nlist.n_type = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset); - nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset); - nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked (&nlist_data_offset); - nlist.n_value = dsc_local_symbols_data.GetAddress_unchecked (&nlist_data_offset); - - SymbolType type = eSymbolTypeInvalid; - const char *symbol_name = dsc_local_symbols_data.PeekCStr(string_table_offset + nlist.n_strx); - - if (symbol_name == NULL) - { - // No symbol should be NULL, even the symbols with no - // string values should have an offset zero which points - // to an empty C-string - Host::SystemLog (Host::eSystemLogError, - "error: DSC unmapped local symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n", - entry_index, - nlist.n_strx, - module_sp->GetFileSpec().GetPath().c_str()); - continue; - } - if (symbol_name[0] == '\0') - symbol_name = NULL; - - const char *symbol_name_non_abi_mangled = NULL; - - SectionSP symbol_section; - uint32_t symbol_byte_size = 0; - bool add_nlist = true; - bool is_debug = ((nlist.n_type & N_STAB) != 0); - bool demangled_is_synthesized = false; - bool is_gsym = false; - bool set_value = true; - - assert (sym_idx < num_syms); - - sym[sym_idx].SetDebug (is_debug); - - if (is_debug) - { - switch (nlist.n_type) - { - case N_GSYM: - // global symbol: name,,NO_SECT,type,0 - // Sometimes the N_GSYM value contains the address. - - // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They - // have the same address, but we want to ensure that we always find only the real symbol, - // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass - // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated - // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the - // same address. - - is_gsym = true; - sym[sym_idx].SetExternal(true); - - if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') - { - llvm::StringRef symbol_name_ref(symbol_name); - if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); - type = eSymbolTypeObjCMetaClass; - demangled_is_synthesized = true; - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); - type = eSymbolTypeObjCIVar; - demangled_is_synthesized = true; - } - } - else - { - if (nlist.n_value != 0) - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeData; - } - break; - - case N_FNAME: - // procedure name (f77 kludge): name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_FUN: - // procedure: name,,n_sect,linenumber,address - if (symbol_name) - { - type = eSymbolTypeCode; - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - - N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx)); - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - N_FUN_indexes.push_back(sym_idx); - } - else - { - type = eSymbolTypeCompiler; - - if ( !N_FUN_indexes.empty() ) - { - // Copy the size of the function into the original STAB entry so we don't have - // to hunt for it later - symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value); - N_FUN_indexes.pop_back(); - // We don't really need the end function STAB as it contains the size which - // we already placed with the original symbol, so don't add it if we want a - // minimal symbol table - add_nlist = false; - } - } - break; - - case N_STSYM: - // static symbol: name,,n_sect,type,address - N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx)); - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - if (symbol_name && symbol_name[0]) - { - type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData); - } - break; - - case N_LCSYM: - // .lcomm symbol: name,,n_sect,type,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeCommonBlock; - break; - - case N_BNSYM: - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - // Skip these if we want minimal symbol tables - add_nlist = false; - break; - - case N_ENSYM: - // Set the size of the N_BNSYM to the terminating index of this N_ENSYM - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - // Skip these if we want minimal symbol tables - add_nlist = false; - break; - - case N_OPT: - // emitted with gcc2_compiled and in gcc source - type = eSymbolTypeCompiler; - break; - - case N_RSYM: - // register sym: name,,NO_SECT,type,register - type = eSymbolTypeVariable; - break; - - case N_SLINE: - // src line: 0,,n_sect,linenumber,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeLineEntry; - break; - - case N_SSYM: - // structure elt: name,,NO_SECT,type,struct_offset - type = eSymbolTypeVariableType; - break; - - case N_SO: - // source file name - type = eSymbolTypeSourceFile; - if (symbol_name == NULL) - { - add_nlist = false; - if (N_SO_index != UINT32_MAX) - { - // Set the size of the N_SO to the terminating index of this N_SO - // so that we can always skip the entire N_SO if we need to navigate - // more quickly at the source level when parsing STABS - symbol_ptr = symtab->SymbolAtIndex(N_SO_index); - symbol_ptr->SetByteSize(sym_idx); - symbol_ptr->SetSizeIsSibling(true); - } - N_NSYM_indexes.clear(); - N_INCL_indexes.clear(); - N_BRAC_indexes.clear(); - N_COMM_indexes.clear(); - N_FUN_indexes.clear(); - N_SO_index = UINT32_MAX; - } - else - { - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - const bool N_SO_has_full_path = symbol_name[0] == '/'; - if (N_SO_has_full_path) - { - if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) - { - // We have two consecutive N_SO entries where the first contains a directory - // and the second contains a full path. - sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false); - m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; - add_nlist = false; - } - else - { - // This is the first entry in a N_SO that contains a directory or - // a full path to the source file - N_SO_index = sym_idx; - } - } - else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) - { - // This is usually the second N_SO entry that contains just the filename, - // so here we combine it with the first one if we are minimizing the symbol table - const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName(lldb::eLanguageTypeUnknown).AsCString(); - if (so_path && so_path[0]) - { - std::string full_so_path (so_path); - const size_t double_slash_pos = full_so_path.find("//"); - if (double_slash_pos != std::string::npos) - { - // The linker has been generating bad N_SO entries with doubled up paths - // in the format "%s%s" where the first string in the DW_AT_comp_dir, - // and the second is the directory for the source file so you end up with - // a path that looks like "/tmp/src//tmp/src/" - FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) - { - so_dir.SetFile(&full_so_path[double_slash_pos + 1], false); - if (so_dir.Exists()) - { - // Trim off the incorrect path - full_so_path.erase(0, double_slash_pos + 1); - } - } - } - if (*full_so_path.rbegin() != '/') - full_so_path += '/'; - full_so_path += symbol_name; - sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false); - add_nlist = false; - m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; - } - } - else - { - // This could be a relative path to a N_SO - N_SO_index = sym_idx; - } - } - break; - - case N_OSO: - // object file name: name,,0,0,st_mtime - type = eSymbolTypeObjectFile; - break; - - case N_LSYM: - // local sym: name,,NO_SECT,type,offset - type = eSymbolTypeLocal; - break; - - //---------------------------------------------------------------------- - // INCL scopes - //---------------------------------------------------------------------- - case N_BINCL: - // include file beginning: name,,NO_SECT,0,sum - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - N_INCL_indexes.push_back(sym_idx); - type = eSymbolTypeScopeBegin; - break; - - case N_EINCL: - // include file end: name,,NO_SECT,0,0 - // Set the size of the N_BINCL to the terminating index of this N_EINCL - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - if ( !N_INCL_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); - symbol_ptr->SetByteSize(sym_idx + 1); - symbol_ptr->SetSizeIsSibling(true); - N_INCL_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_SOL: - // #included file name: name,,n_sect,0,address - type = eSymbolTypeHeaderFile; - - // We currently don't use the header files on darwin - add_nlist = false; - break; - - case N_PARAMS: - // compiler parameters: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_VERSION: - // compiler version: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_OLEVEL: - // compiler -O level: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_PSYM: - // parameter: name,,NO_SECT,type,offset - type = eSymbolTypeVariable; - break; - - case N_ENTRY: - // alternate entry: name,,n_sect,linenumber,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeLineEntry; - break; - - //---------------------------------------------------------------------- - // Left and Right Braces - //---------------------------------------------------------------------- - case N_LBRAC: - // left bracket: 0,,NO_SECT,nesting level,address - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - N_BRAC_indexes.push_back(sym_idx); - type = eSymbolTypeScopeBegin; - break; - - case N_RBRAC: - // right bracket: 0,,NO_SECT,nesting level,address - // Set the size of the N_LBRAC to the terminating index of this N_RBRAC - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - if ( !N_BRAC_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back()); - symbol_ptr->SetByteSize(sym_idx + 1); - symbol_ptr->SetSizeIsSibling(true); - N_BRAC_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_EXCL: - // deleted include file: name,,NO_SECT,0,sum - type = eSymbolTypeHeaderFile; - break; - - //---------------------------------------------------------------------- - // COMM scopes - //---------------------------------------------------------------------- - case N_BCOMM: - // begin common: name,,NO_SECT,0,0 - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - type = eSymbolTypeScopeBegin; - N_COMM_indexes.push_back(sym_idx); - break; - - case N_ECOML: - // end common (local name): 0,,n_sect,0,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - // Fall through - - case N_ECOMM: - // end common: name,,n_sect,0,0 - // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - if ( !N_COMM_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); - symbol_ptr->SetByteSize(sym_idx + 1); - symbol_ptr->SetSizeIsSibling(true); - N_COMM_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_LENG: - // second stab entry with length information - type = eSymbolTypeAdditional; - break; - - default: break; - } - } - else - { - //uint8_t n_pext = N_PEXT & nlist.n_type; - uint8_t n_type = N_TYPE & nlist.n_type; - sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); - - switch (n_type) - { - case N_INDR: - { - const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value); - if (reexport_name_cstr && reexport_name_cstr[0]) - { - type = eSymbolTypeReExported; - ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0)); - sym[sym_idx].SetReExportedSymbolName(reexport_name); - set_value = false; - reexport_shlib_needs_fixup[sym_idx] = reexport_name; - indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0))); - } - else - type = eSymbolTypeUndefined; - } - break; - - case N_UNDF: - if (symbol_name && symbol_name[0]) - { - ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)); - undefined_name_to_desc[undefined_name] = nlist.n_desc; - } - // Fall through - case N_PBUD: - type = eSymbolTypeUndefined; - break; - - case N_ABS: - type = eSymbolTypeAbsolute; - break; - - case N_SECT: - { - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - - if (symbol_section == NULL) - { - // TODO: warn about this? - add_nlist = false; - break; - } - - if (TEXT_eh_frame_sectID == nlist.n_sect) - { - type = eSymbolTypeException; - } - else - { - uint32_t section_type = symbol_section->Get() & SECTION_TYPE; - - switch (section_type) - { - case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings - case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals - case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals - case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals - case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers - case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers - case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field - case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization - case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination - case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing - case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals - case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break; - case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; - default: - switch (symbol_section->GetType()) - { - case lldb::eSectionTypeCode: - type = eSymbolTypeCode; - break; - case eSectionTypeData: - case eSectionTypeDataCString: // Inlined C string data - case eSectionTypeDataCStringPointers: // Pointers to C string data - case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table - case eSectionTypeData4: - case eSectionTypeData8: - case eSectionTypeData16: - type = eSymbolTypeData; - break; - default: - break; - } - break; - } - - if (type == eSymbolTypeInvalid) - { - const char *symbol_sect_name = symbol_section->GetName().AsCString(); - if (symbol_section->IsDescendant (text_section_sp.get())) - { - if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | - S_ATTR_SELF_MODIFYING_CODE | - S_ATTR_SOME_INSTRUCTIONS)) - type = eSymbolTypeData; - else - type = eSymbolTypeCode; - } - else if (symbol_section->IsDescendant(data_section_sp.get()) || - symbol_section->IsDescendant(data_dirty_section_sp.get()) || - symbol_section->IsDescendant(data_const_section_sp.get())) - { - if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name) - { - type = eSymbolTypeRuntime; - - if (symbol_name) - { - llvm::StringRef symbol_name_ref(symbol_name); - if (symbol_name_ref.startswith("_OBJC_")) - { - static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_"); - if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); - type = eSymbolTypeObjCMetaClass; - demangled_is_synthesized = true; - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); - type = eSymbolTypeObjCIVar; - demangled_is_synthesized = true; - } - } - } - } - else if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name) - { - type = eSymbolTypeException; - } - else - { - type = eSymbolTypeData; - } - } - else if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name) - { - type = eSymbolTypeTrampoline; - } - else if (symbol_section->IsDescendant(objc_section_sp.get())) - { - type = eSymbolTypeRuntime; - if (symbol_name && symbol_name[0] == '.') - { - llvm::StringRef symbol_name_ref(symbol_name); - static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_"); - if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name; - symbol_name = symbol_name + g_objc_v1_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - } - } - } - } - } - } - break; - } - } - - if (add_nlist) - { - uint64_t symbol_value = nlist.n_value; - if (symbol_name_non_abi_mangled) - { - sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled)); - sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name)); - } - else - { - bool symbol_name_is_mangled = false; - - if (symbol_name && symbol_name[0] == '_') - { - symbol_name_is_mangled = symbol_name[1] == '_'; - symbol_name++; // Skip the leading underscore - } - - if (symbol_name) - { - ConstString const_symbol_name(symbol_name); - sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled); - if (is_gsym && is_debug) - { - const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString(); - if (gsym_name) - N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; - } - } - } - if (symbol_section) - { - const addr_t section_file_addr = symbol_section->GetFileAddress(); - if (symbol_byte_size == 0 && function_starts_count > 0) - { - addr_t symbol_lookup_file_addr = nlist.n_value; - // Do an exact address match for non-ARM addresses, else get the closest since - // the symbol might be a thumb symbol which has an address with bit zero set - FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm); - if (is_arm && func_start_entry) - { - // Verify that the function start address is the symbol address (ARM) - // or the symbol address + 1 (thumb) - if (func_start_entry->addr != symbol_lookup_file_addr && - func_start_entry->addr != (symbol_lookup_file_addr + 1)) - { - // Not the right entry, NULL it out... - func_start_entry = NULL; - } - } - if (func_start_entry) - { - func_start_entry->data = true; - - addr_t symbol_file_addr = func_start_entry->addr; - uint32_t symbol_flags = 0; - if (is_arm) - { - if (symbol_file_addr & 1) - symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB; - symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - } - - const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry); - const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize(); - if (next_func_start_entry) - { - addr_t next_symbol_file_addr = next_func_start_entry->addr; - // Be sure the clear the Thumb address bit when we calculate the size - // from the current and next address - if (is_arm) - next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr); - } - else - { - symbol_byte_size = section_end_file_addr - symbol_file_addr; - } - } - } - symbol_value -= section_file_addr; - } - - if (is_debug == false) - { - if (type == eSymbolTypeCode) - { - // See if we can find a N_FUN entry for any code symbols. - // If we do find a match, and the name matches, then we - // can merge the two into just the function symbol to avoid - // duplicate entries in the symbol table - std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; - range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value); - if (range.first != range.second) - { - bool found_it = false; - for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos) - { - if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) - { - m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; - // We just need the flags from the linker symbol, so put these flags - // into the N_FUN flags to avoid duplicate symbols in the symbol table - sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); - sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); - if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end()) - sym[pos->second].SetType (eSymbolTypeResolver); - sym[sym_idx].Clear(); - found_it = true; - break; - } - } - if (found_it) - continue; - } - else - { - if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end()) - type = eSymbolTypeResolver; - } - } - else if (type == eSymbolTypeData || - type == eSymbolTypeObjCClass || - type == eSymbolTypeObjCMetaClass || - type == eSymbolTypeObjCIVar ) - { - // See if we can find a N_STSYM entry for any data symbols. - // If we do find a match, and the name matches, then we - // can merge the two into just the Static symbol to avoid - // duplicate entries in the symbol table - std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; - range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value); - if (range.first != range.second) - { - bool found_it = false; - for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos) - { - if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) - { - m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; - // We just need the flags from the linker symbol, so put these flags - // into the N_STSYM flags to avoid duplicate symbols in the symbol table - sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); - sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); - sym[sym_idx].Clear(); - found_it = true; - break; - } - } - if (found_it) - continue; - } - else - { - const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString(); - if (gsym_name) - { - // Combine N_GSYM stab entries with the non stab symbol - ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name); - if (pos != N_GSYM_name_to_sym_idx.end()) - { - const uint32_t GSYM_sym_idx = pos->second; - m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx; - // Copy the address, because often the N_GSYM address has an invalid address of zero - // when the global is a common symbol - sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section); - sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value); - // We just need the flags from the linker symbol, so put these flags - // into the N_GSYM flags to avoid duplicate symbols in the symbol table - sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc); - sym[sym_idx].Clear(); - continue; - } - } - } - } - } - - sym[sym_idx].SetID (nlist_idx); - sym[sym_idx].SetType (type); - if (set_value) - { - sym[sym_idx].GetAddressRef().SetSection (symbol_section); - sym[sym_idx].GetAddressRef().SetOffset (symbol_value); - } - sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc); - - if (symbol_byte_size > 0) - sym[sym_idx].SetByteSize(symbol_byte_size); - - if (demangled_is_synthesized) - sym[sym_idx].SetDemangledNameIsSynthesized(true); - ++sym_idx; - } - else - { - sym[sym_idx].Clear(); - } - - } - ///////////////////////////// - } - break; // No more entries to consider - } - } + // For user process binaries (executables, dylibs, frameworks, bundles), if + // we don't have + // LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume + // the binary + // has been stripped. Don't allow assembly language instruction emulation + // because we don't + // know proper function start boundaries. + // + // For all other types of binaries (kernels, stand-alone bare board + // binaries, kexts), they + // may not have LC_FUNCTION_STARTS / eh_frame sections - we should not make + // any assumptions + // about them based on that. + if (function_starts_count == 0 && CalculateStrata() == eStrataUser) { + m_allow_assembly_emulation_unwind_plans = false; + Log *unwind_or_symbol_log(lldb_private::GetLogIfAnyCategoriesSet( + LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND)); + + if (unwind_or_symbol_log) + module_sp->LogMessage( + unwind_or_symbol_log, + "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds"); + } - for (const auto &pos :reexport_shlib_needs_fixup) - { - const auto undef_pos = undefined_name_to_desc.find(pos.second); - if (undef_pos != undefined_name_to_desc.end()) - { - const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); - if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize()) - sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1)); - } - } - } - } - } - } + const user_id_t TEXT_eh_frame_sectID = + eh_frame_section_sp.get() ? eh_frame_section_sp->GetID() + : static_cast<user_id_t>(NO_SECT); + + lldb::offset_t nlist_data_offset = 0; + + uint32_t N_SO_index = UINT32_MAX; + + MachSymtabSectionInfo section_info(section_list); + std::vector<uint32_t> N_FUN_indexes; + std::vector<uint32_t> N_NSYM_indexes; + std::vector<uint32_t> N_INCL_indexes; + std::vector<uint32_t> N_BRAC_indexes; + std::vector<uint32_t> N_COMM_indexes; + typedef std::multimap<uint64_t, uint32_t> ValueToSymbolIndexMap; + typedef std::map<uint32_t, uint32_t> NListIndexToSymbolIndexMap; + typedef std::map<const char *, uint32_t> ConstNameToSymbolIndexMap; + ValueToSymbolIndexMap N_FUN_addr_to_sym_idx; + ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx; + ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx; + // Any symbols that get merged into another will get an entry + // in this map so we know + NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx; + uint32_t nlist_idx = 0; + Symbol *symbol_ptr = NULL; + + uint32_t sym_idx = 0; + Symbol *sym = NULL; + size_t num_syms = 0; + std::string memory_symbol_name; + uint32_t unmapped_local_symbols_found = 0; + + std::vector<TrieEntryWithOffset> trie_entries; + std::set<lldb::addr_t> resolver_addresses; + + if (dyld_trie_data.GetByteSize() > 0) { + std::vector<llvm::StringRef> nameSlices; + ParseTrieEntries(dyld_trie_data, 0, is_arm, nameSlices, + resolver_addresses, trie_entries); + + ConstString text_segment_name("__TEXT"); + SectionSP text_segment_sp = + GetSectionList()->FindSectionByName(text_segment_name); + if (text_segment_sp) { + const lldb::addr_t text_segment_file_addr = + text_segment_sp->GetFileAddress(); + if (text_segment_file_addr != LLDB_INVALID_ADDRESS) { + for (auto &e : trie_entries) + e.entry.address += text_segment_file_addr; } + } + } - // Must reset this in case it was mutated above! - nlist_data_offset = 0; -#endif - - if (nlist_data.GetByteSize() > 0) - { - - // If the sym array was not created while parsing the DSC unmapped - // symbols, create it now. - if (sym == NULL) - { - sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms); - num_syms = symtab->GetNumSymbols(); - } - - if (unmapped_local_symbols_found) - { - assert(m_dysymtab.ilocalsym == 0); - nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size); - nlist_idx = m_dysymtab.nlocalsym; - } - else - { - nlist_idx = 0; - } - - typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap; - typedef std::map<uint32_t, ConstString> SymbolIndexToName; - UndefinedNameToDescMap undefined_name_to_desc; - SymbolIndexToName reexport_shlib_needs_fixup; - for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx) - { - struct nlist_64 nlist; - if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size)) - break; - - nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset); - nlist.n_type = nlist_data.GetU8_unchecked (&nlist_data_offset); - nlist.n_sect = nlist_data.GetU8_unchecked (&nlist_data_offset); - nlist.n_desc = nlist_data.GetU16_unchecked (&nlist_data_offset); - nlist.n_value = nlist_data.GetAddress_unchecked (&nlist_data_offset); - - SymbolType type = eSymbolTypeInvalid; - const char *symbol_name = NULL; - - if (have_strtab_data) - { - symbol_name = strtab_data.PeekCStr(nlist.n_strx); + typedef std::set<ConstString> IndirectSymbols; + IndirectSymbols indirect_symbol_names; + +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) + + // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been + // optimized by moving LOCAL + // symbols out of the memory mapped portion of the DSC. The symbol + // information has all been retained, + // but it isn't available in the normal nlist data. However, there *are* + // duplicate entries of *some* + // LOCAL symbols in the normal nlist data. To handle this situation + // correctly, we must first attempt + // to parse any DSC unmapped symbol information. If we find any, we set a + // flag that tells the normal + // nlist parser to ignore all LOCAL symbols. + + if (m_header.flags & 0x80000000u) { + // Before we can start mapping the DSC, we need to make certain the target + // process is actually + // using the cache we can find. + + // Next we need to determine the correct path for the dyld shared cache. + + ArchSpec header_arch; + GetArchitecture(header_arch); + char dsc_path[PATH_MAX]; + char dsc_path_development[PATH_MAX]; + + snprintf( + dsc_path, sizeof(dsc_path), "%s%s%s", + "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR + */ + "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ + header_arch.GetArchitectureName()); + + snprintf( + dsc_path_development, sizeof(dsc_path), "%s%s%s%s", + "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR + */ + "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ + header_arch.GetArchitectureName(), + ".development"); + + FileSpec dsc_nondevelopment_filespec(dsc_path, false); + FileSpec dsc_development_filespec(dsc_path_development, false); + FileSpec dsc_filespec; + + UUID dsc_uuid; + UUID process_shared_cache_uuid; + + if (process) { + process_shared_cache_uuid = GetProcessSharedCacheUUID(process); + } + + // First see if we can find an exact match for the inferior process shared + // cache UUID in + // the development or non-development shared caches on disk. + if (process_shared_cache_uuid.IsValid()) { + if (dsc_development_filespec.Exists()) { + UUID dsc_development_uuid = GetSharedCacheUUID( + dsc_development_filespec, byte_order, addr_byte_size); + if (dsc_development_uuid.IsValid() && + dsc_development_uuid == process_shared_cache_uuid) { + dsc_filespec = dsc_development_filespec; + dsc_uuid = dsc_development_uuid; + } + } + if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists()) { + UUID dsc_nondevelopment_uuid = GetSharedCacheUUID( + dsc_nondevelopment_filespec, byte_order, addr_byte_size); + if (dsc_nondevelopment_uuid.IsValid() && + dsc_nondevelopment_uuid == process_shared_cache_uuid) { + dsc_filespec = dsc_nondevelopment_filespec; + dsc_uuid = dsc_nondevelopment_uuid; + } + } + } + + // Failing a UUID match, prefer the development dyld_shared cache if both + // are present. + if (!dsc_filespec.Exists()) { + if (dsc_development_filespec.Exists()) { + dsc_filespec = dsc_development_filespec; + } else { + dsc_filespec = dsc_nondevelopment_filespec; + } + } + + /* The dyld_cache_header has a pointer to the + dyld_cache_local_symbols_info structure (localSymbolsOffset). + The dyld_cache_local_symbols_info structure gives us three things: + 1. The start and count of the nlist records in the dyld_shared_cache + file + 2. The start and size of the strings for these nlist records + 3. The start and count of dyld_cache_local_symbols_entry entries + + There is one dyld_cache_local_symbols_entry per dylib/framework in the + dyld shared cache. + The "dylibOffset" field is the Mach-O header of this dylib/framework in + the dyld shared cache. + The dyld_cache_local_symbols_entry also lists the start of this + dylib/framework's nlist records + and the count of how many nlist records there are for this + dylib/framework. + */ + + // Process the dyld shared cache header to find the unmapped symbols + + DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal( + 0, sizeof(struct lldb_copy_dyld_cache_header_v1)); + if (!dsc_uuid.IsValid()) { + dsc_uuid = GetSharedCacheUUID(dsc_filespec, byte_order, addr_byte_size); + } + if (dsc_data_sp) { + DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size); + + bool uuid_match = true; + if (dsc_uuid.IsValid() && process) { + if (process_shared_cache_uuid.IsValid() && + dsc_uuid != process_shared_cache_uuid) { + // The on-disk dyld_shared_cache file is not the same as the one in + // this + // process' memory, don't use it. + uuid_match = false; + ModuleSP module_sp(GetModule()); + if (module_sp) + module_sp->ReportWarning("process shared cache does not match " + "on-disk dyld_shared_cache file, some " + "symbol names will be missing."); + } + } - if (symbol_name == NULL) + offset = offsetof(struct lldb_copy_dyld_cache_header_v1, mappingOffset); + + uint32_t mappingOffset = dsc_header_data.GetU32(&offset); + + // If the mappingOffset points to a location inside the header, we've + // opened an old dyld shared cache, and should not proceed further. + if (uuid_match && + mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) { + + DataBufferSP dsc_mapping_info_data_sp = + dsc_filespec.MemoryMapFileContentsIfLocal( + mappingOffset, + sizeof(struct lldb_copy_dyld_cache_mapping_info)); + DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, + byte_order, addr_byte_size); + offset = 0; + + // The File addresses (from the in-memory Mach-O load commands) for + // the shared libraries + // in the shared library cache need to be adjusted by an offset to + // match up with the + // dylibOffset identifying field in the + // dyld_cache_local_symbol_entry's. This offset is + // recorded in mapping_offset_value. + const uint64_t mapping_offset_value = + dsc_mapping_info_data.GetU64(&offset); + + offset = offsetof(struct lldb_copy_dyld_cache_header_v1, + localSymbolsOffset); + uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset); + uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset); + + if (localSymbolsOffset && localSymbolsSize) { + // Map the local symbols + if (DataBufferSP dsc_local_symbols_data_sp = + dsc_filespec.MemoryMapFileContentsIfLocal( + localSymbolsOffset, localSymbolsSize)) { + DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, + byte_order, addr_byte_size); + + offset = 0; + + typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap; + typedef std::map<uint32_t, ConstString> SymbolIndexToName; + UndefinedNameToDescMap undefined_name_to_desc; + SymbolIndexToName reexport_shlib_needs_fixup; + + // Read the local_symbols_infos struct in one shot + struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info; + dsc_local_symbols_data.GetU32(&offset, + &local_symbols_info.nlistOffset, 6); + + SectionSP text_section_sp( + section_list->FindSectionByName(GetSegmentNameTEXT())); + + uint32_t header_file_offset = + (text_section_sp->GetFileAddress() - mapping_offset_value); + + offset = local_symbols_info.entriesOffset; + for (uint32_t entry_index = 0; + entry_index < local_symbols_info.entriesCount; + entry_index++) { + struct lldb_copy_dyld_cache_local_symbols_entry + local_symbols_entry; + local_symbols_entry.dylibOffset = + dsc_local_symbols_data.GetU32(&offset); + local_symbols_entry.nlistStartIndex = + dsc_local_symbols_data.GetU32(&offset); + local_symbols_entry.nlistCount = + dsc_local_symbols_data.GetU32(&offset); + + if (header_file_offset == local_symbols_entry.dylibOffset) { + unmapped_local_symbols_found = local_symbols_entry.nlistCount; + + // The normal nlist code cannot correctly size the Symbols + // array, we need to allocate it here. + sym = symtab->Resize( + symtab_load_command.nsyms + m_dysymtab.nindirectsyms + + unmapped_local_symbols_found - m_dysymtab.nlocalsym); + num_syms = symtab->GetNumSymbols(); + + nlist_data_offset = + local_symbols_info.nlistOffset + + (nlist_byte_size * local_symbols_entry.nlistStartIndex); + uint32_t string_table_offset = + local_symbols_info.stringsOffset; + + for (uint32_t nlist_index = 0; + nlist_index < local_symbols_entry.nlistCount; + nlist_index++) { + ///////////////////////////// { + struct nlist_64 nlist; + if (!dsc_local_symbols_data.ValidOffsetForDataOfSize( + nlist_data_offset, nlist_byte_size)) + break; + + nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked( + &nlist_data_offset); + nlist.n_type = dsc_local_symbols_data.GetU8_unchecked( + &nlist_data_offset); + nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked( + &nlist_data_offset); + nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked( + &nlist_data_offset); + nlist.n_value = + dsc_local_symbols_data.GetAddress_unchecked( + &nlist_data_offset); + + SymbolType type = eSymbolTypeInvalid; + const char *symbol_name = dsc_local_symbols_data.PeekCStr( + string_table_offset + nlist.n_strx); + + if (symbol_name == NULL) { // No symbol should be NULL, even the symbols with no // string values should have an offset zero which points // to an empty C-string - Host::SystemLog (Host::eSystemLogError, - "error: symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n", - nlist_idx, - nlist.n_strx, - module_sp->GetFileSpec().GetPath().c_str()); + Host::SystemLog( + Host::eSystemLogError, + "error: DSC unmapped local symbol[%u] has invalid " + "string table offset 0x%x in %s, ignoring symbol\n", + entry_index, nlist.n_strx, + module_sp->GetFileSpec().GetPath().c_str()); continue; - } - if (symbol_name[0] == '\0') + } + if (symbol_name[0] == '\0') symbol_name = NULL; - } - else - { - const addr_t str_addr = strtab_addr + nlist.n_strx; - Error str_error; - if (process->ReadCStringFromMemory(str_addr, memory_symbol_name, str_error)) - symbol_name = memory_symbol_name.c_str(); - } - const char *symbol_name_non_abi_mangled = NULL; - - SectionSP symbol_section; - lldb::addr_t symbol_byte_size = 0; - bool add_nlist = true; - bool is_gsym = false; - bool is_debug = ((nlist.n_type & N_STAB) != 0); - bool demangled_is_synthesized = false; - bool set_value = true; - assert (sym_idx < num_syms); - - sym[sym_idx].SetDebug (is_debug); - - if (is_debug) - { - switch (nlist.n_type) - { - case N_GSYM: - // global symbol: name,,NO_SECT,type,0 - // Sometimes the N_GSYM value contains the address. - - // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They - // have the same address, but we want to ensure that we always find only the real symbol, - // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass - // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated - // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the - // same address. - is_gsym = true; - sym[sym_idx].SetExternal(true); - - if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') - { + + const char *symbol_name_non_abi_mangled = NULL; + + SectionSP symbol_section; + uint32_t symbol_byte_size = 0; + bool add_nlist = true; + bool is_debug = ((nlist.n_type & N_STAB) != 0); + bool demangled_is_synthesized = false; + bool is_gsym = false; + bool set_value = true; + + assert(sym_idx < num_syms); + + sym[sym_idx].SetDebug(is_debug); + + if (is_debug) { + switch (nlist.n_type) { + case N_GSYM: + // global symbol: name,,NO_SECT,type,0 + // Sometimes the N_GSYM value contains the address. + + // FIXME: In the .o files, we have a GSYM and a debug + // symbol for all the ObjC data. They + // have the same address, but we want to ensure that + // we always find only the real symbol, + // 'cause we don't currently correctly attribute the + // GSYM one to the ObjCClass/Ivar/MetaClass + // symbol type. This is a temporary hack to make sure + // the ObjectiveC symbols get treated + // correctly. To do this right, we should coalesce + // all the GSYM & global symbols that have the + // same address. + + is_gsym = true; + sym[sym_idx].SetExternal(true); + + if (symbol_name && symbol_name[0] == '_' && + symbol_name[1] == 'O') { llvm::StringRef symbol_name_ref(symbol_name); - if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); - type = eSymbolTypeObjCMetaClass; - demangled_is_synthesized = true; + if (symbol_name_ref.startswith( + g_objc_v2_prefix_class)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = + symbol_name + g_objc_v2_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; + + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_metaclass)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = symbol_name + + g_objc_v2_prefix_metaclass.size(); + type = eSymbolTypeObjCMetaClass; + demangled_is_synthesized = true; + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_ivar)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = + symbol_name + g_objc_v2_prefix_ivar.size(); + type = eSymbolTypeObjCIVar; + demangled_is_synthesized = true; } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); - type = eSymbolTypeObjCIVar; - demangled_is_synthesized = true; - } - } - else - { + } else { if (nlist.n_value != 0) - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); type = eSymbolTypeData; - } - break; + } + break; - case N_FNAME: - // procedure name (f77 kludge): name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; + case N_FNAME: + // procedure name (f77 kludge): name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; - case N_FUN: - // procedure: name,,n_sect,linenumber,address - if (symbol_name) - { + case N_FUN: + // procedure: name,,n_sect,linenumber,address + if (symbol_name) { type = eSymbolTypeCode; - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - - N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx)); - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + + N_FUN_addr_to_sym_idx.insert( + std::make_pair(nlist.n_value, sym_idx)); + // We use the current number of symbols in the + // symbol table in lieu of + // using nlist_idx in case we ever start trimming + // entries out N_FUN_indexes.push_back(sym_idx); - } - else - { + } else { type = eSymbolTypeCompiler; - if ( !N_FUN_indexes.empty() ) - { - // Copy the size of the function into the original STAB entry so we don't have - // to hunt for it later - symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value); - N_FUN_indexes.pop_back(); - // We don't really need the end function STAB as it contains the size which - // we already placed with the original symbol, so don't add it if we want a - // minimal symbol table - add_nlist = false; + if (!N_FUN_indexes.empty()) { + // Copy the size of the function into the original + // STAB entry so we don't have + // to hunt for it later + symtab->SymbolAtIndex(N_FUN_indexes.back()) + ->SetByteSize(nlist.n_value); + N_FUN_indexes.pop_back(); + // We don't really need the end function STAB as + // it contains the size which + // we already placed with the original symbol, so + // don't add it if we want a + // minimal symbol table + add_nlist = false; } - } - break; - - case N_STSYM: - // static symbol: name,,n_sect,type,address - N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx)); - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - if (symbol_name && symbol_name[0]) - { - type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData); - } - break; - - case N_LCSYM: - // .lcomm symbol: name,,n_sect,type,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeCommonBlock; - break; - - case N_BNSYM: - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - // Skip these if we want minimal symbol tables - add_nlist = false; - break; - - case N_ENSYM: - // Set the size of the N_BNSYM to the terminating index of this N_ENSYM - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - // Skip these if we want minimal symbol tables - add_nlist = false; - break; - - - case N_OPT: - // emitted with gcc2_compiled and in gcc source - type = eSymbolTypeCompiler; - break; - - case N_RSYM: - // register sym: name,,NO_SECT,type,register - type = eSymbolTypeVariable; - break; - - case N_SLINE: - // src line: 0,,n_sect,linenumber,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeLineEntry; - break; - - case N_SSYM: - // structure elt: name,,NO_SECT,type,struct_offset - type = eSymbolTypeVariableType; - break; - - case N_SO: - // source file name - type = eSymbolTypeSourceFile; - if (symbol_name == NULL) - { + } + break; + + case N_STSYM: + // static symbol: name,,n_sect,type,address + N_STSYM_addr_to_sym_idx.insert( + std::make_pair(nlist.n_value, sym_idx)); + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + if (symbol_name && symbol_name[0]) { + type = ObjectFile::GetSymbolTypeFromName( + symbol_name + 1, eSymbolTypeData); + } + break; + + case N_LCSYM: + // .lcomm symbol: name,,n_sect,type,address + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + type = eSymbolTypeCommonBlock; + break; + + case N_BNSYM: + // We use the current number of symbols in the symbol + // table in lieu of + // using nlist_idx in case we ever start trimming + // entries out + // Skip these if we want minimal symbol tables + add_nlist = false; + break; + + case N_ENSYM: + // Set the size of the N_BNSYM to the terminating + // index of this N_ENSYM + // so that we can always skip the entire symbol if we + // need to navigate + // more quickly at the source level when parsing STABS + // Skip these if we want minimal symbol tables + add_nlist = false; + break; + + case N_OPT: + // emitted with gcc2_compiled and in gcc source + type = eSymbolTypeCompiler; + break; + + case N_RSYM: + // register sym: name,,NO_SECT,type,register + type = eSymbolTypeVariable; + break; + + case N_SLINE: + // src line: 0,,n_sect,linenumber,address + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + type = eSymbolTypeLineEntry; + break; + + case N_SSYM: + // structure elt: name,,NO_SECT,type,struct_offset + type = eSymbolTypeVariableType; + break; + + case N_SO: + // source file name + type = eSymbolTypeSourceFile; + if (symbol_name == NULL) { add_nlist = false; - if (N_SO_index != UINT32_MAX) - { - // Set the size of the N_SO to the terminating index of this N_SO - // so that we can always skip the entire N_SO if we need to navigate - // more quickly at the source level when parsing STABS - symbol_ptr = symtab->SymbolAtIndex(N_SO_index); - symbol_ptr->SetByteSize(sym_idx); - symbol_ptr->SetSizeIsSibling(true); + if (N_SO_index != UINT32_MAX) { + // Set the size of the N_SO to the terminating + // index of this N_SO + // so that we can always skip the entire N_SO if + // we need to navigate + // more quickly at the source level when parsing + // STABS + symbol_ptr = symtab->SymbolAtIndex(N_SO_index); + symbol_ptr->SetByteSize(sym_idx); + symbol_ptr->SetSizeIsSibling(true); } N_NSYM_indexes.clear(); N_INCL_indexes.clear(); @@ -3939,2174 +3031,3060 @@ ObjectFileMachO::ParseSymtab () N_COMM_indexes.clear(); N_FUN_indexes.clear(); N_SO_index = UINT32_MAX; - } - else - { - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - const bool N_SO_has_full_path = symbol_name[0] == '/'; - if (N_SO_has_full_path) - { - if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) - { - // We have two consecutive N_SO entries where the first contains a directory - // and the second contains a full path. - sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false); - m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; - add_nlist = false; - } - else - { - // This is the first entry in a N_SO that contains a directory or - // a full path to the source file - N_SO_index = sym_idx; - } - } - else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) - { - // This is usually the second N_SO entry that contains just the filename, - // so here we combine it with the first one if we are minimizing the symbol table - const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName(lldb::eLanguageTypeUnknown).AsCString(); - if (so_path && so_path[0]) - { - std::string full_so_path (so_path); - const size_t double_slash_pos = full_so_path.find("//"); - if (double_slash_pos != std::string::npos) - { - // The linker has been generating bad N_SO entries with doubled up paths - // in the format "%s%s" where the first string in the DW_AT_comp_dir, - // and the second is the directory for the source file so you end up with - // a path that looks like "/tmp/src//tmp/src/" - FileSpec so_dir(so_path, false); - if (!so_dir.Exists()) - { - so_dir.SetFile(&full_so_path[double_slash_pos + 1], false); - if (so_dir.Exists()) - { - // Trim off the incorrect path - full_so_path.erase(0, double_slash_pos + 1); - } - } + } else { + // We use the current number of symbols in the + // symbol table in lieu of + // using nlist_idx in case we ever start trimming + // entries out + const bool N_SO_has_full_path = + symbol_name[0] == '/'; + if (N_SO_has_full_path) { + if ((N_SO_index == sym_idx - 1) && + ((sym_idx - 1) < num_syms)) { + // We have two consecutive N_SO entries where + // the first contains a directory + // and the second contains a full path. + sym[sym_idx - 1].GetMangled().SetValue( + ConstString(symbol_name), false); + m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; + add_nlist = false; + } else { + // This is the first entry in a N_SO that + // contains a directory or + // a full path to the source file + N_SO_index = sym_idx; + } + } else if ((N_SO_index == sym_idx - 1) && + ((sym_idx - 1) < num_syms)) { + // This is usually the second N_SO entry that + // contains just the filename, + // so here we combine it with the first one if we + // are minimizing the symbol table + const char *so_path = + sym[sym_idx - 1] + .GetMangled() + .GetDemangledName( + lldb::eLanguageTypeUnknown) + .AsCString(); + if (so_path && so_path[0]) { + std::string full_so_path(so_path); + const size_t double_slash_pos = + full_so_path.find("//"); + if (double_slash_pos != std::string::npos) { + // The linker has been generating bad N_SO + // entries with doubled up paths + // in the format "%s%s" where the first string + // in the DW_AT_comp_dir, + // and the second is the directory for the + // source file so you end up with + // a path that looks like "/tmp/src//tmp/src/" + FileSpec so_dir(so_path, false); + if (!so_dir.Exists()) { + so_dir.SetFile( + &full_so_path[double_slash_pos + 1], + false); + if (so_dir.Exists()) { + // Trim off the incorrect path + full_so_path.erase(0, + double_slash_pos + 1); } - if (*full_so_path.rbegin() != '/') - full_so_path += '/'; - full_so_path += symbol_name; - sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false); - add_nlist = false; - m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; + } } + if (*full_so_path.rbegin() != '/') + full_so_path += '/'; + full_so_path += symbol_name; + sym[sym_idx - 1].GetMangled().SetValue( + ConstString(full_so_path.c_str()), false); + add_nlist = false; + m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; + } + } else { + // This could be a relative path to a N_SO + N_SO_index = sym_idx; } - else - { - // This could be a relative path to a N_SO - N_SO_index = sym_idx; - } - } - break; - - case N_OSO: - // object file name: name,,0,0,st_mtime - type = eSymbolTypeObjectFile; - break; - - case N_LSYM: - // local sym: name,,NO_SECT,type,offset - type = eSymbolTypeLocal; - break; - - //---------------------------------------------------------------------- - // INCL scopes - //---------------------------------------------------------------------- - case N_BINCL: - // include file beginning: name,,NO_SECT,0,sum - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - N_INCL_indexes.push_back(sym_idx); - type = eSymbolTypeScopeBegin; - break; - - case N_EINCL: - // include file end: name,,NO_SECT,0,0 - // Set the size of the N_BINCL to the terminating index of this N_EINCL - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - if ( !N_INCL_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); + } + break; + + case N_OSO: + // object file name: name,,0,0,st_mtime + type = eSymbolTypeObjectFile; + break; + + case N_LSYM: + // local sym: name,,NO_SECT,type,offset + type = eSymbolTypeLocal; + break; + + //---------------------------------------------------------------------- + // INCL scopes + //---------------------------------------------------------------------- + case N_BINCL: + // include file beginning: name,,NO_SECT,0,sum + // We use the current number of symbols in the symbol + // table in lieu of + // using nlist_idx in case we ever start trimming + // entries out + N_INCL_indexes.push_back(sym_idx); + type = eSymbolTypeScopeBegin; + break; + + case N_EINCL: + // include file end: name,,NO_SECT,0,0 + // Set the size of the N_BINCL to the terminating + // index of this N_EINCL + // so that we can always skip the entire symbol if we + // need to navigate + // more quickly at the source level when parsing STABS + if (!N_INCL_indexes.empty()) { + symbol_ptr = + symtab->SymbolAtIndex(N_INCL_indexes.back()); symbol_ptr->SetByteSize(sym_idx + 1); symbol_ptr->SetSizeIsSibling(true); N_INCL_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_SOL: - // #included file name: name,,n_sect,0,address - type = eSymbolTypeHeaderFile; - - // We currently don't use the header files on darwin - add_nlist = false; - break; - - case N_PARAMS: - // compiler parameters: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_VERSION: - // compiler version: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_OLEVEL: - // compiler -O level: name,,NO_SECT,0,0 - type = eSymbolTypeCompiler; - break; - - case N_PSYM: - // parameter: name,,NO_SECT,type,offset - type = eSymbolTypeVariable; - break; - - case N_ENTRY: - // alternate entry: name,,n_sect,linenumber,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - type = eSymbolTypeLineEntry; - break; - - //---------------------------------------------------------------------- - // Left and Right Braces - //---------------------------------------------------------------------- - case N_LBRAC: - // left bracket: 0,,NO_SECT,nesting level,address - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - N_BRAC_indexes.push_back(sym_idx); - type = eSymbolTypeScopeBegin; - break; - - case N_RBRAC: - // right bracket: 0,,NO_SECT,nesting level,address - // Set the size of the N_LBRAC to the terminating index of this N_RBRAC - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - if ( !N_BRAC_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back()); + } + type = eSymbolTypeScopeEnd; + break; + + case N_SOL: + // #included file name: name,,n_sect,0,address + type = eSymbolTypeHeaderFile; + + // We currently don't use the header files on darwin + add_nlist = false; + break; + + case N_PARAMS: + // compiler parameters: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; + + case N_VERSION: + // compiler version: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; + + case N_OLEVEL: + // compiler -O level: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; + + case N_PSYM: + // parameter: name,,NO_SECT,type,offset + type = eSymbolTypeVariable; + break; + + case N_ENTRY: + // alternate entry: name,,n_sect,linenumber,address + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + type = eSymbolTypeLineEntry; + break; + + //---------------------------------------------------------------------- + // Left and Right Braces + //---------------------------------------------------------------------- + case N_LBRAC: + // left bracket: 0,,NO_SECT,nesting level,address + // We use the current number of symbols in the symbol + // table in lieu of + // using nlist_idx in case we ever start trimming + // entries out + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + N_BRAC_indexes.push_back(sym_idx); + type = eSymbolTypeScopeBegin; + break; + + case N_RBRAC: + // right bracket: 0,,NO_SECT,nesting level,address + // Set the size of the N_LBRAC to the terminating + // index of this N_RBRAC + // so that we can always skip the entire symbol if we + // need to navigate + // more quickly at the source level when parsing STABS + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + if (!N_BRAC_indexes.empty()) { + symbol_ptr = + symtab->SymbolAtIndex(N_BRAC_indexes.back()); symbol_ptr->SetByteSize(sym_idx + 1); symbol_ptr->SetSizeIsSibling(true); N_BRAC_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_EXCL: - // deleted include file: name,,NO_SECT,0,sum - type = eSymbolTypeHeaderFile; - break; - - //---------------------------------------------------------------------- - // COMM scopes - //---------------------------------------------------------------------- - case N_BCOMM: - // begin common: name,,NO_SECT,0,0 - // We use the current number of symbols in the symbol table in lieu of - // using nlist_idx in case we ever start trimming entries out - type = eSymbolTypeScopeBegin; - N_COMM_indexes.push_back(sym_idx); - break; - - case N_ECOML: - // end common (local name): 0,,n_sect,0,address - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - LLVM_FALLTHROUGH; - - case N_ECOMM: - // end common: name,,n_sect,0,0 - // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML - // so that we can always skip the entire symbol if we need to navigate - // more quickly at the source level when parsing STABS - if ( !N_COMM_indexes.empty() ) - { - symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); + } + type = eSymbolTypeScopeEnd; + break; + + case N_EXCL: + // deleted include file: name,,NO_SECT,0,sum + type = eSymbolTypeHeaderFile; + break; + + //---------------------------------------------------------------------- + // COMM scopes + //---------------------------------------------------------------------- + case N_BCOMM: + // begin common: name,,NO_SECT,0,0 + // We use the current number of symbols in the symbol + // table in lieu of + // using nlist_idx in case we ever start trimming + // entries out + type = eSymbolTypeScopeBegin; + N_COMM_indexes.push_back(sym_idx); + break; + + case N_ECOML: + // end common (local name): 0,,n_sect,0,address + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + // Fall through + + case N_ECOMM: + // end common: name,,n_sect,0,0 + // Set the size of the N_BCOMM to the terminating + // index of this N_ECOMM/N_ECOML + // so that we can always skip the entire symbol if we + // need to navigate + // more quickly at the source level when parsing STABS + if (!N_COMM_indexes.empty()) { + symbol_ptr = + symtab->SymbolAtIndex(N_COMM_indexes.back()); symbol_ptr->SetByteSize(sym_idx + 1); symbol_ptr->SetSizeIsSibling(true); N_COMM_indexes.pop_back(); - } - type = eSymbolTypeScopeEnd; - break; - - case N_LENG: - // second stab entry with length information - type = eSymbolTypeAdditional; - break; - - default: break; - } - } - else - { - //uint8_t n_pext = N_PEXT & nlist.n_type; - uint8_t n_type = N_TYPE & nlist.n_type; - sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); + } + type = eSymbolTypeScopeEnd; + break; - switch (n_type) - { - case N_INDR: - { - const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value); - if (reexport_name_cstr && reexport_name_cstr[0]) - { - type = eSymbolTypeReExported; - ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0)); - sym[sym_idx].SetReExportedSymbolName(reexport_name); - set_value = false; - reexport_shlib_needs_fixup[sym_idx] = reexport_name; - indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0))); - } - else - type = eSymbolTypeUndefined; - } - break; + case N_LENG: + // second stab entry with length information + type = eSymbolTypeAdditional; + break; - case N_UNDF: - if (symbol_name && symbol_name[0]) - { - ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)); - undefined_name_to_desc[undefined_name] = nlist.n_desc; + default: + break; } - LLVM_FALLTHROUGH; - - case N_PBUD: - type = eSymbolTypeUndefined; - break; - - case N_ABS: - type = eSymbolTypeAbsolute; - break; - - case N_SECT: - { - symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value); - - if (!symbol_section) - { - // TODO: warn about this? - add_nlist = false; + } else { + // uint8_t n_pext = N_PEXT & nlist.n_type; + uint8_t n_type = N_TYPE & nlist.n_type; + sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); + + switch (n_type) { + case N_INDR: { + const char *reexport_name_cstr = + strtab_data.PeekCStr(nlist.n_value); + if (reexport_name_cstr && reexport_name_cstr[0]) { + type = eSymbolTypeReExported; + ConstString reexport_name( + reexport_name_cstr + + ((reexport_name_cstr[0] == '_') ? 1 : 0)); + sym[sym_idx].SetReExportedSymbolName(reexport_name); + set_value = false; + reexport_shlib_needs_fixup[sym_idx] = reexport_name; + indirect_symbol_names.insert( + ConstString(symbol_name + + ((symbol_name[0] == '_') ? 1 : 0))); + } else + type = eSymbolTypeUndefined; + } break; + + case N_UNDF: + if (symbol_name && symbol_name[0]) { + ConstString undefined_name( + symbol_name + + ((symbol_name[0] == '_') ? 1 : 0)); + undefined_name_to_desc[undefined_name] = + nlist.n_desc; + } + // Fall through + case N_PBUD: + type = eSymbolTypeUndefined; + break; + + case N_ABS: + type = eSymbolTypeAbsolute; + break; + + case N_SECT: { + symbol_section = section_info.GetSection( + nlist.n_sect, nlist.n_value); + + if (symbol_section == NULL) { + // TODO: warn about this? + add_nlist = false; + break; + } + + if (TEXT_eh_frame_sectID == nlist.n_sect) { + type = eSymbolTypeException; + } else { + uint32_t section_type = + symbol_section->Get() & SECTION_TYPE; + + switch (section_type) { + case S_CSTRING_LITERALS: + type = eSymbolTypeData; + break; // section with only literal C strings + case S_4BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 4 byte literals + case S_8BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 8 byte literals + case S_LITERAL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only pointers to literals + case S_NON_LAZY_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only non-lazy symbol + // pointers + case S_LAZY_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only lazy symbol pointers + case S_SYMBOL_STUBS: + type = eSymbolTypeTrampoline; + break; // section with only symbol stubs, byte + // size of stub in the reserved2 field + case S_MOD_INIT_FUNC_POINTERS: + type = eSymbolTypeCode; + break; // section with only function pointers for + // initialization + case S_MOD_TERM_FUNC_POINTERS: + type = eSymbolTypeCode; + break; // section with only function pointers for + // termination + case S_INTERPOSING: + type = eSymbolTypeTrampoline; + break; // section with only pairs of function + // pointers for interposing + case S_16BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 16 byte literals + case S_DTRACE_DOF: + type = eSymbolTypeInstrumentation; + break; + case S_LAZY_DYLIB_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; + default: + switch (symbol_section->GetType()) { + case lldb::eSectionTypeCode: + type = eSymbolTypeCode; break; + case eSectionTypeData: + case eSectionTypeDataCString: // Inlined C string + // data + case eSectionTypeDataCStringPointers: // Pointers + // to C + // string + // data + case eSectionTypeDataSymbolAddress: // Address of + // a symbol in + // the symbol + // table + case eSectionTypeData4: + case eSectionTypeData8: + case eSectionTypeData16: + type = eSymbolTypeData; + break; + default: + break; + } + break; } - if (TEXT_eh_frame_sectID == nlist.n_sect) - { - type = eSymbolTypeException; - } - else - { - uint32_t section_type = symbol_section->Get() & SECTION_TYPE; - - switch (section_type) - { - case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings - case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals - case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals - case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals - case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers - case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers - case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field - case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization - case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination - case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing - case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals - case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break; - case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; - default: - switch (symbol_section->GetType()) - { - case lldb::eSectionTypeCode: - type = eSymbolTypeCode; - break; - case eSectionTypeData: - case eSectionTypeDataCString: // Inlined C string data - case eSectionTypeDataCStringPointers: // Pointers to C string data - case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table - case eSectionTypeData4: - case eSectionTypeData8: - case eSectionTypeData16: - type = eSymbolTypeData; - break; - default: - break; + if (type == eSymbolTypeInvalid) { + const char *symbol_sect_name = + symbol_section->GetName().AsCString(); + if (symbol_section->IsDescendant( + text_section_sp.get())) { + if (symbol_section->IsClear( + S_ATTR_PURE_INSTRUCTIONS | + S_ATTR_SELF_MODIFYING_CODE | + S_ATTR_SOME_INSTRUCTIONS)) + type = eSymbolTypeData; + else + type = eSymbolTypeCode; + } else if (symbol_section->IsDescendant( + data_section_sp.get()) || + symbol_section->IsDescendant( + data_dirty_section_sp.get()) || + symbol_section->IsDescendant( + data_const_section_sp.get())) { + if (symbol_sect_name && + ::strstr(symbol_sect_name, "__objc") == + symbol_sect_name) { + type = eSymbolTypeRuntime; + + if (symbol_name) { + llvm::StringRef symbol_name_ref( + symbol_name); + if (symbol_name_ref.startswith("_OBJC_")) { + static const llvm::StringRef + g_objc_v2_prefix_class( + "_OBJC_CLASS_$_"); + static const llvm::StringRef + g_objc_v2_prefix_metaclass( + "_OBJC_METACLASS_$_"); + static const llvm::StringRef + g_objc_v2_prefix_ivar( + "_OBJC_IVAR_$_"); + if (symbol_name_ref.startswith( + g_objc_v2_prefix_class)) { + symbol_name_non_abi_mangled = + symbol_name + 1; + symbol_name = + symbol_name + + g_objc_v2_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; + } else if ( + symbol_name_ref.startswith( + g_objc_v2_prefix_metaclass)) { + symbol_name_non_abi_mangled = + symbol_name + 1; + symbol_name = + symbol_name + + g_objc_v2_prefix_metaclass.size(); + type = eSymbolTypeObjCMetaClass; + demangled_is_synthesized = true; + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_ivar)) { + symbol_name_non_abi_mangled = + symbol_name + 1; + symbol_name = + symbol_name + + g_objc_v2_prefix_ivar.size(); + type = eSymbolTypeObjCIVar; + demangled_is_synthesized = true; + } } - break; + } + } else if (symbol_sect_name && + ::strstr(symbol_sect_name, + "__gcc_except_tab") == + symbol_sect_name) { + type = eSymbolTypeException; + } else { + type = eSymbolTypeData; } - - if (type == eSymbolTypeInvalid) - { - const char *symbol_sect_name = symbol_section->GetName().AsCString(); - if (symbol_section->IsDescendant (text_section_sp.get())) - { - if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | - S_ATTR_SELF_MODIFYING_CODE | - S_ATTR_SOME_INSTRUCTIONS)) - type = eSymbolTypeData; - else - type = eSymbolTypeCode; - } - else - if (symbol_section->IsDescendant(data_section_sp.get()) || - symbol_section->IsDescendant(data_dirty_section_sp.get()) || - symbol_section->IsDescendant(data_const_section_sp.get())) - { - if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name) - { - type = eSymbolTypeRuntime; - - if (symbol_name) - { - llvm::StringRef symbol_name_ref(symbol_name); - if (symbol_name_ref.startswith("_OBJC_")) - { - static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_"); - static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_"); - if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); - type = eSymbolTypeObjCMetaClass; - demangled_is_synthesized = true; - } - else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) - { - symbol_name_non_abi_mangled = symbol_name + 1; - symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); - type = eSymbolTypeObjCIVar; - demangled_is_synthesized = true; - } - } - } - } - else - if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name) - { - type = eSymbolTypeException; - } - else - { - type = eSymbolTypeData; - } - } - else - if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name) - { - type = eSymbolTypeTrampoline; - } - else - if (symbol_section->IsDescendant(objc_section_sp.get())) - { - type = eSymbolTypeRuntime; - if (symbol_name && symbol_name[0] == '.') - { - llvm::StringRef symbol_name_ref(symbol_name); - static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_"); - if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) - { - symbol_name_non_abi_mangled = symbol_name; - symbol_name = symbol_name + g_objc_v1_prefix_class.size(); - type = eSymbolTypeObjCClass; - demangled_is_synthesized = true; - } - } - } + } else if (symbol_sect_name && + ::strstr(symbol_sect_name, + "__IMPORT") == + symbol_sect_name) { + type = eSymbolTypeTrampoline; + } else if (symbol_section->IsDescendant( + objc_section_sp.get())) { + type = eSymbolTypeRuntime; + if (symbol_name && symbol_name[0] == '.') { + llvm::StringRef symbol_name_ref(symbol_name); + static const llvm::StringRef + g_objc_v1_prefix_class( + ".objc_class_name_"); + if (symbol_name_ref.startswith( + g_objc_v1_prefix_class)) { + symbol_name_non_abi_mangled = symbol_name; + symbol_name = symbol_name + + g_objc_v1_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; + } } + } } + } + } break; } - break; - } - } - - if (add_nlist) - { - uint64_t symbol_value = nlist.n_value; - - if (symbol_name_non_abi_mangled) - { - sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled)); - sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name)); - } - else - { - bool symbol_name_is_mangled = false; - - if (symbol_name && symbol_name[0] == '_') - { + } + + if (add_nlist) { + uint64_t symbol_value = nlist.n_value; + if (symbol_name_non_abi_mangled) { + sym[sym_idx].GetMangled().SetMangledName( + ConstString(symbol_name_non_abi_mangled)); + sym[sym_idx].GetMangled().SetDemangledName( + ConstString(symbol_name)); + } else { + bool symbol_name_is_mangled = false; + + if (symbol_name && symbol_name[0] == '_') { symbol_name_is_mangled = symbol_name[1] == '_'; - symbol_name++; // Skip the leading underscore - } + symbol_name++; // Skip the leading underscore + } - if (symbol_name) - { + if (symbol_name) { ConstString const_symbol_name(symbol_name); - sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled); + sym[sym_idx].GetMangled().SetValue( + const_symbol_name, symbol_name_is_mangled); + if (is_gsym && is_debug) { + const char *gsym_name = + sym[sym_idx] + .GetMangled() + .GetName(lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) + .GetCString(); + if (gsym_name) + N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; + } + } } - } - - if (is_gsym) - { - const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString(); - if (gsym_name) - N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; - } - - if (symbol_section) - { - const addr_t section_file_addr = symbol_section->GetFileAddress(); - if (symbol_byte_size == 0 && function_starts_count > 0) - { + if (symbol_section) { + const addr_t section_file_addr = + symbol_section->GetFileAddress(); + if (symbol_byte_size == 0 && + function_starts_count > 0) { addr_t symbol_lookup_file_addr = nlist.n_value; - // Do an exact address match for non-ARM addresses, else get the closest since - // the symbol might be a thumb symbol which has an address with bit zero set - FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm); - if (is_arm && func_start_entry) - { - // Verify that the function start address is the symbol address (ARM) - // or the symbol address + 1 (thumb) - if (func_start_entry->addr != symbol_lookup_file_addr && - func_start_entry->addr != (symbol_lookup_file_addr + 1)) - { - // Not the right entry, NULL it out... - func_start_entry = NULL; - } + // Do an exact address match for non-ARM addresses, + // else get the closest since + // the symbol might be a thumb symbol which has an + // address with bit zero set + FunctionStarts::Entry *func_start_entry = + function_starts.FindEntry( + symbol_lookup_file_addr, !is_arm); + if (is_arm && func_start_entry) { + // Verify that the function start address is the + // symbol address (ARM) + // or the symbol address + 1 (thumb) + if (func_start_entry->addr != + symbol_lookup_file_addr && + func_start_entry->addr != + (symbol_lookup_file_addr + 1)) { + // Not the right entry, NULL it out... + func_start_entry = NULL; + } } - if (func_start_entry) - { - func_start_entry->data = true; - - addr_t symbol_file_addr = func_start_entry->addr; + if (func_start_entry) { + func_start_entry->data = true; + + addr_t symbol_file_addr = func_start_entry->addr; + uint32_t symbol_flags = 0; + if (is_arm) { + if (symbol_file_addr & 1) + symbol_flags = + MACHO_NLIST_ARM_SYMBOL_IS_THUMB; + symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; + } + + const FunctionStarts::Entry + *next_func_start_entry = + function_starts.FindNextEntry( + func_start_entry); + const addr_t section_end_file_addr = + section_file_addr + + symbol_section->GetByteSize(); + if (next_func_start_entry) { + addr_t next_symbol_file_addr = + next_func_start_entry->addr; + // Be sure the clear the Thumb address bit when + // we calculate the size + // from the current and next address if (is_arm) - symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - - const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry); - const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize(); - if (next_func_start_entry) - { - addr_t next_symbol_file_addr = next_func_start_entry->addr; - // Be sure the clear the Thumb address bit when we calculate the size - // from the current and next address - if (is_arm) - next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr); - } - else - { - symbol_byte_size = section_end_file_addr - symbol_file_addr; - } + next_symbol_file_addr &= + THUMB_ADDRESS_BIT_MASK; + symbol_byte_size = std::min<lldb::addr_t>( + next_symbol_file_addr - symbol_file_addr, + section_end_file_addr - symbol_file_addr); + } else { + symbol_byte_size = + section_end_file_addr - symbol_file_addr; + } } + } + symbol_value -= section_file_addr; } - symbol_value -= section_file_addr; - } - if (is_debug == false) - { - if (type == eSymbolTypeCode) - { - // See if we can find a N_FUN entry for any code symbols. - // If we do find a match, and the name matches, then we - // can merge the two into just the function symbol to avoid + if (is_debug == false) { + if (type == eSymbolTypeCode) { + // See if we can find a N_FUN entry for any code + // symbols. + // If we do find a match, and the name matches, then + // we + // can merge the two into just the function symbol + // to avoid // duplicate entries in the symbol table - std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; - range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value); - if (range.first != range.second) - { - bool found_it = false; - for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos) - { - if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) - { - m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; - // We just need the flags from the linker symbol, so put these flags - // into the N_FUN flags to avoid duplicate symbols in the symbol table - sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); - sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); - if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end()) - sym[pos->second].SetType (eSymbolTypeResolver); - sym[sym_idx].Clear(); - found_it = true; - break; - } + std::pair<ValueToSymbolIndexMap::const_iterator, + ValueToSymbolIndexMap::const_iterator> + range; + range = N_FUN_addr_to_sym_idx.equal_range( + nlist.n_value); + if (range.first != range.second) { + bool found_it = false; + for (ValueToSymbolIndexMap::const_iterator pos = + range.first; + pos != range.second; ++pos) { + if (sym[sym_idx].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) == + sym[pos->second].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled)) { + m_nlist_idx_to_sym_idx[nlist_idx] = + pos->second; + // We just need the flags from the linker + // symbol, so put these flags + // into the N_FUN flags to avoid duplicate + // symbols in the symbol table + sym[pos->second].SetExternal( + sym[sym_idx].IsExternal()); + sym[pos->second].SetFlags(nlist.n_type << 16 | + nlist.n_desc); + if (resolver_addresses.find(nlist.n_value) != + resolver_addresses.end()) + sym[pos->second].SetType( + eSymbolTypeResolver); + sym[sym_idx].Clear(); + found_it = true; + break; } - if (found_it) - continue; - } - else - { - if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end()) - type = eSymbolTypeResolver; + } + if (found_it) + continue; + } else { + if (resolver_addresses.find(nlist.n_value) != + resolver_addresses.end()) + type = eSymbolTypeResolver; } - } - else if (type == eSymbolTypeData || - type == eSymbolTypeObjCClass || - type == eSymbolTypeObjCMetaClass || - type == eSymbolTypeObjCIVar ) - { - // See if we can find a N_STSYM entry for any data symbols. - // If we do find a match, and the name matches, then we - // can merge the two into just the Static symbol to avoid + } else if (type == eSymbolTypeData || + type == eSymbolTypeObjCClass || + type == eSymbolTypeObjCMetaClass || + type == eSymbolTypeObjCIVar) { + // See if we can find a N_STSYM entry for any data + // symbols. + // If we do find a match, and the name matches, then + // we + // can merge the two into just the Static symbol to + // avoid // duplicate entries in the symbol table - std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range; - range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value); - if (range.first != range.second) - { - bool found_it = false; - for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos) - { - if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) - { - m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; - // We just need the flags from the linker symbol, so put these flags - // into the N_STSYM flags to avoid duplicate symbols in the symbol table - sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); - sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); - sym[sym_idx].Clear(); - found_it = true; - break; - } + std::pair<ValueToSymbolIndexMap::const_iterator, + ValueToSymbolIndexMap::const_iterator> + range; + range = N_STSYM_addr_to_sym_idx.equal_range( + nlist.n_value); + if (range.first != range.second) { + bool found_it = false; + for (ValueToSymbolIndexMap::const_iterator pos = + range.first; + pos != range.second; ++pos) { + if (sym[sym_idx].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) == + sym[pos->second].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled)) { + m_nlist_idx_to_sym_idx[nlist_idx] = + pos->second; + // We just need the flags from the linker + // symbol, so put these flags + // into the N_STSYM flags to avoid duplicate + // symbols in the symbol table + sym[pos->second].SetExternal( + sym[sym_idx].IsExternal()); + sym[pos->second].SetFlags(nlist.n_type << 16 | + nlist.n_desc); + sym[sym_idx].Clear(); + found_it = true; + break; } - if (found_it) - continue; - } - else - { - // Combine N_GSYM stab entries with the non stab symbol - const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString(); - if (gsym_name) - { - ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name); - if (pos != N_GSYM_name_to_sym_idx.end()) - { - const uint32_t GSYM_sym_idx = pos->second; - m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx; - // Copy the address, because often the N_GSYM address has an invalid address of zero - // when the global is a common symbol - sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section); - sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value); - // We just need the flags from the linker symbol, so put these flags - // into the N_GSYM flags to avoid duplicate symbols in the symbol table - sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc); - sym[sym_idx].Clear(); - continue; - } + } + if (found_it) + continue; + } else { + const char *gsym_name = + sym[sym_idx] + .GetMangled() + .GetName(lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) + .GetCString(); + if (gsym_name) { + // Combine N_GSYM stab entries with the non stab + // symbol + ConstNameToSymbolIndexMap::const_iterator pos = + N_GSYM_name_to_sym_idx.find(gsym_name); + if (pos != N_GSYM_name_to_sym_idx.end()) { + const uint32_t GSYM_sym_idx = pos->second; + m_nlist_idx_to_sym_idx[nlist_idx] = + GSYM_sym_idx; + // Copy the address, because often the N_GSYM + // address has an invalid address of zero + // when the global is a common symbol + sym[GSYM_sym_idx].GetAddressRef().SetSection( + symbol_section); + sym[GSYM_sym_idx].GetAddressRef().SetOffset( + symbol_value); + // We just need the flags from the linker + // symbol, so put these flags + // into the N_GSYM flags to avoid duplicate + // symbols in the symbol table + sym[GSYM_sym_idx].SetFlags( + nlist.n_type << 16 | nlist.n_desc); + sym[sym_idx].Clear(); + continue; } + } } + } } - } - sym[sym_idx].SetID (nlist_idx); - sym[sym_idx].SetType (type); - if (set_value) - { - sym[sym_idx].GetAddressRef().SetSection (symbol_section); - sym[sym_idx].GetAddressRef().SetOffset (symbol_value); - } - sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc); - - if (symbol_byte_size > 0) - sym[sym_idx].SetByteSize(symbol_byte_size); + sym[sym_idx].SetID(nlist_idx); + sym[sym_idx].SetType(type); + if (set_value) { + sym[sym_idx].GetAddressRef().SetSection( + symbol_section); + sym[sym_idx].GetAddressRef().SetOffset(symbol_value); + } + sym[sym_idx].SetFlags(nlist.n_type << 16 | + nlist.n_desc); - if (demangled_is_synthesized) - sym[sym_idx].SetDemangledNameIsSynthesized(true); + if (symbol_byte_size > 0) + sym[sym_idx].SetByteSize(symbol_byte_size); - ++sym_idx; - } - else - { - sym[sym_idx].Clear(); + if (demangled_is_synthesized) + sym[sym_idx].SetDemangledNameIsSynthesized(true); + ++sym_idx; + } else { + sym[sym_idx].Clear(); + } + } + ///////////////////////////// + } + break; // No more entries to consider } - } + } - for (const auto &pos :reexport_shlib_needs_fixup) - { + for (const auto &pos : reexport_shlib_needs_fixup) { const auto undef_pos = undefined_name_to_desc.find(pos.second); - if (undef_pos != undefined_name_to_desc.end()) - { - const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); - if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize()) - sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1)); + if (undef_pos != undefined_name_to_desc.end()) { + const uint8_t dylib_ordinal = + llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); + if (dylib_ordinal > 0 && + dylib_ordinal < dylib_files.GetSize()) + sym[pos.first].SetReExportedSymbolSharedLibrary( + dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1)); } + } } + } } + } + } - uint32_t synthetic_sym_id = symtab_load_command.nsyms; + // Must reset this in case it was mutated above! + nlist_data_offset = 0; +#endif - if (function_starts_count > 0) - { - uint32_t num_synthetic_function_symbols = 0; - for (i=0; i<function_starts_count; ++i) - { - if (function_starts.GetEntryRef (i).data == false) - ++num_synthetic_function_symbols; + if (nlist_data.GetByteSize() > 0) { + + // If the sym array was not created while parsing the DSC unmapped + // symbols, create it now. + if (sym == NULL) { + sym = symtab->Resize(symtab_load_command.nsyms + + m_dysymtab.nindirectsyms); + num_syms = symtab->GetNumSymbols(); + } + + if (unmapped_local_symbols_found) { + assert(m_dysymtab.ilocalsym == 0); + nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size); + nlist_idx = m_dysymtab.nlocalsym; + } else { + nlist_idx = 0; + } + + typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap; + typedef std::map<uint32_t, ConstString> SymbolIndexToName; + UndefinedNameToDescMap undefined_name_to_desc; + SymbolIndexToName reexport_shlib_needs_fixup; + for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx) { + struct nlist_64 nlist; + if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset, + nlist_byte_size)) + break; + + nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset); + nlist.n_type = nlist_data.GetU8_unchecked(&nlist_data_offset); + nlist.n_sect = nlist_data.GetU8_unchecked(&nlist_data_offset); + nlist.n_desc = nlist_data.GetU16_unchecked(&nlist_data_offset); + nlist.n_value = nlist_data.GetAddress_unchecked(&nlist_data_offset); + + SymbolType type = eSymbolTypeInvalid; + const char *symbol_name = NULL; + + if (have_strtab_data) { + symbol_name = strtab_data.PeekCStr(nlist.n_strx); + + if (symbol_name == NULL) { + // No symbol should be NULL, even the symbols with no + // string values should have an offset zero which points + // to an empty C-string + Host::SystemLog(Host::eSystemLogError, + "error: symbol[%u] has invalid string table offset " + "0x%x in %s, ignoring symbol\n", + nlist_idx, nlist.n_strx, + module_sp->GetFileSpec().GetPath().c_str()); + continue; + } + if (symbol_name[0] == '\0') + symbol_name = NULL; + } else { + const addr_t str_addr = strtab_addr + nlist.n_strx; + Error str_error; + if (process->ReadCStringFromMemory(str_addr, memory_symbol_name, + str_error)) + symbol_name = memory_symbol_name.c_str(); + } + const char *symbol_name_non_abi_mangled = NULL; + + SectionSP symbol_section; + lldb::addr_t symbol_byte_size = 0; + bool add_nlist = true; + bool is_gsym = false; + bool is_debug = ((nlist.n_type & N_STAB) != 0); + bool demangled_is_synthesized = false; + bool set_value = true; + assert(sym_idx < num_syms); + + sym[sym_idx].SetDebug(is_debug); + + if (is_debug) { + switch (nlist.n_type) { + case N_GSYM: + // global symbol: name,,NO_SECT,type,0 + // Sometimes the N_GSYM value contains the address. + + // FIXME: In the .o files, we have a GSYM and a debug symbol for all + // the ObjC data. They + // have the same address, but we want to ensure that we always find + // only the real symbol, + // 'cause we don't currently correctly attribute the GSYM one to the + // ObjCClass/Ivar/MetaClass + // symbol type. This is a temporary hack to make sure the + // ObjectiveC symbols get treated + // correctly. To do this right, we should coalesce all the GSYM & + // global symbols that have the + // same address. + is_gsym = true; + sym[sym_idx].SetExternal(true); + + if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') { + llvm::StringRef symbol_name_ref(symbol_name); + if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = symbol_name + g_objc_v2_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; + + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_metaclass)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); + type = eSymbolTypeObjCMetaClass; + demangled_is_synthesized = true; + } else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); + type = eSymbolTypeObjCIVar; + demangled_is_synthesized = true; + } + } else { + if (nlist.n_value != 0) + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + type = eSymbolTypeData; } + break; - if (num_synthetic_function_symbols > 0) - { - if (num_syms < sym_idx + num_synthetic_function_symbols) - { - num_syms = sym_idx + num_synthetic_function_symbols; - sym = symtab->Resize (num_syms); - } - for (i=0; i<function_starts_count; ++i) - { - const FunctionStarts::Entry *func_start_entry = function_starts.GetEntryAtIndex (i); - if (func_start_entry->data == false) - { - addr_t symbol_file_addr = func_start_entry->addr; - uint32_t symbol_flags = 0; - if (is_arm) - { - if (symbol_file_addr & 1) - symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB; - symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - } - Address symbol_addr; - if (module_sp->ResolveFileAddress (symbol_file_addr, symbol_addr)) - { - SectionSP symbol_section (symbol_addr.GetSection()); - uint32_t symbol_byte_size = 0; - if (symbol_section) - { - const addr_t section_file_addr = symbol_section->GetFileAddress(); - const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry); - const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize(); - if (next_func_start_entry) - { - addr_t next_symbol_file_addr = next_func_start_entry->addr; - if (is_arm) - next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; - symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr); - } - else - { - symbol_byte_size = section_end_file_addr - symbol_file_addr; - } - sym[sym_idx].SetID (synthetic_sym_id++); - sym[sym_idx].GetMangled().SetDemangledName(GetNextSyntheticSymbolName()); - sym[sym_idx].SetType (eSymbolTypeCode); - sym[sym_idx].SetIsSynthetic (true); - sym[sym_idx].GetAddressRef() = symbol_addr; - if (symbol_flags) - sym[sym_idx].SetFlags (symbol_flags); - if (symbol_byte_size) - sym[sym_idx].SetByteSize (symbol_byte_size); - ++sym_idx; - } - } - } - } + case N_FNAME: + // procedure name (f77 kludge): name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; + + case N_FUN: + // procedure: name,,n_sect,linenumber,address + if (symbol_name) { + type = eSymbolTypeCode; + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + + N_FUN_addr_to_sym_idx.insert( + std::make_pair(nlist.n_value, sym_idx)); + // We use the current number of symbols in the symbol table in + // lieu of + // using nlist_idx in case we ever start trimming entries out + N_FUN_indexes.push_back(sym_idx); + } else { + type = eSymbolTypeCompiler; + + if (!N_FUN_indexes.empty()) { + // Copy the size of the function into the original STAB entry so + // we don't have + // to hunt for it later + symtab->SymbolAtIndex(N_FUN_indexes.back()) + ->SetByteSize(nlist.n_value); + N_FUN_indexes.pop_back(); + // We don't really need the end function STAB as it contains the + // size which + // we already placed with the original symbol, so don't add it + // if we want a + // minimal symbol table + add_nlist = false; + } } - } + break; - // Trim our symbols down to just what we ended up with after - // removing any symbols. - if (sym_idx < num_syms) - { - num_syms = sym_idx; - sym = symtab->Resize (num_syms); - } + case N_STSYM: + // static symbol: name,,n_sect,type,address + N_STSYM_addr_to_sym_idx.insert( + std::make_pair(nlist.n_value, sym_idx)); + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + if (symbol_name && symbol_name[0]) { + type = ObjectFile::GetSymbolTypeFromName(symbol_name + 1, + eSymbolTypeData); + } + break; - // Now synthesize indirect symbols - if (m_dysymtab.nindirectsyms != 0) - { - if (indirect_symbol_index_data.GetByteSize()) - { - NListIndexToSymbolIndexMap::const_iterator end_index_pos = m_nlist_idx_to_sym_idx.end(); + case N_LCSYM: + // .lcomm symbol: name,,n_sect,type,address + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + type = eSymbolTypeCommonBlock; + break; - for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); ++sect_idx) - { - if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == S_SYMBOL_STUBS) - { - uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2; - if (symbol_stub_byte_size == 0) - continue; - - const uint32_t num_symbol_stubs = m_mach_sections[sect_idx].size / symbol_stub_byte_size; - - if (num_symbol_stubs == 0) - continue; - - const uint32_t symbol_stub_index_offset = m_mach_sections[sect_idx].reserved1; - for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx) - { - const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx; - const lldb::addr_t symbol_stub_addr = m_mach_sections[sect_idx].addr + (stub_idx * symbol_stub_byte_size); - lldb::offset_t symbol_stub_offset = symbol_stub_index * 4; - if (indirect_symbol_index_data.ValidOffsetForDataOfSize(symbol_stub_offset, 4)) - { - const uint32_t stub_sym_id = indirect_symbol_index_data.GetU32 (&symbol_stub_offset); - if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL)) - continue; - - NListIndexToSymbolIndexMap::const_iterator index_pos = m_nlist_idx_to_sym_idx.find (stub_sym_id); - Symbol *stub_symbol = NULL; - if (index_pos != end_index_pos) - { - // We have a remapping from the original nlist index to - // a current symbol index, so just look this up by index - stub_symbol = symtab->SymbolAtIndex (index_pos->second); - } - else - { - // We need to lookup a symbol using the original nlist - // symbol index since this index is coming from the - // S_SYMBOL_STUBS - stub_symbol = symtab->FindSymbolByID (stub_sym_id); - } + case N_BNSYM: + // We use the current number of symbols in the symbol table in lieu + // of + // using nlist_idx in case we ever start trimming entries out + // Skip these if we want minimal symbol tables + add_nlist = false; + break; - if (stub_symbol) - { - Address so_addr(symbol_stub_addr, section_list); - - if (stub_symbol->GetType() == eSymbolTypeUndefined) - { - // Change the external symbol into a trampoline that makes sense - // These symbols were N_UNDF N_EXT, and are useless to us, so we - // can re-use them so we don't have to make up a synthetic symbol - // for no good reason. - if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end()) - stub_symbol->SetType (eSymbolTypeTrampoline); - else - stub_symbol->SetType (eSymbolTypeResolver); - stub_symbol->SetExternal (false); - stub_symbol->GetAddressRef() = so_addr; - stub_symbol->SetByteSize (symbol_stub_byte_size); - } - else - { - // Make a synthetic symbol to describe the trampoline stub - Mangled stub_symbol_mangled_name(stub_symbol->GetMangled()); - if (sym_idx >= num_syms) - { - sym = symtab->Resize (++num_syms); - stub_symbol = NULL; // this pointer no longer valid - } - sym[sym_idx].SetID (synthetic_sym_id++); - sym[sym_idx].GetMangled() = stub_symbol_mangled_name; - if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end()) - sym[sym_idx].SetType (eSymbolTypeTrampoline); - else - sym[sym_idx].SetType (eSymbolTypeResolver); - sym[sym_idx].SetIsSynthetic (true); - sym[sym_idx].GetAddressRef() = so_addr; - sym[sym_idx].SetByteSize (symbol_stub_byte_size); - ++sym_idx; - } - } - else - { - if (log) - log->Warning ("symbol stub referencing symbol table symbol %u that isn't in our minimal symbol table, fix this!!!", stub_sym_id); - } - } - } - } - } - } - } + case N_ENSYM: + // Set the size of the N_BNSYM to the terminating index of this + // N_ENSYM + // so that we can always skip the entire symbol if we need to + // navigate + // more quickly at the source level when parsing STABS + // Skip these if we want minimal symbol tables + add_nlist = false; + break; - if (!trie_entries.empty()) - { - for (const auto &e : trie_entries) - { - if (e.entry.import_name) - { - // Only add indirect symbols from the Trie entries if we - // didn't have a N_INDR nlist entry for this already - if (indirect_symbol_names.find(e.entry.name) == indirect_symbol_names.end()) - { - // Make a synthetic symbol to describe re-exported symbol. - if (sym_idx >= num_syms) - sym = symtab->Resize (++num_syms); - sym[sym_idx].SetID (synthetic_sym_id++); - sym[sym_idx].GetMangled() = Mangled(e.entry.name); - sym[sym_idx].SetType (eSymbolTypeReExported); - sym[sym_idx].SetIsSynthetic (true); - sym[sym_idx].SetReExportedSymbolName(e.entry.import_name); - if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) - { - sym[sym_idx].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(e.entry.other-1)); - } - ++sym_idx; + case N_OPT: + // emitted with gcc2_compiled and in gcc source + type = eSymbolTypeCompiler; + break; + + case N_RSYM: + // register sym: name,,NO_SECT,type,register + type = eSymbolTypeVariable; + break; + + case N_SLINE: + // src line: 0,,n_sect,linenumber,address + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + type = eSymbolTypeLineEntry; + break; + + case N_SSYM: + // structure elt: name,,NO_SECT,type,struct_offset + type = eSymbolTypeVariableType; + break; + + case N_SO: + // source file name + type = eSymbolTypeSourceFile; + if (symbol_name == NULL) { + add_nlist = false; + if (N_SO_index != UINT32_MAX) { + // Set the size of the N_SO to the terminating index of this + // N_SO + // so that we can always skip the entire N_SO if we need to + // navigate + // more quickly at the source level when parsing STABS + symbol_ptr = symtab->SymbolAtIndex(N_SO_index); + symbol_ptr->SetByteSize(sym_idx); + symbol_ptr->SetSizeIsSibling(true); + } + N_NSYM_indexes.clear(); + N_INCL_indexes.clear(); + N_BRAC_indexes.clear(); + N_COMM_indexes.clear(); + N_FUN_indexes.clear(); + N_SO_index = UINT32_MAX; + } else { + // We use the current number of symbols in the symbol table in + // lieu of + // using nlist_idx in case we ever start trimming entries out + const bool N_SO_has_full_path = symbol_name[0] == '/'; + if (N_SO_has_full_path) { + if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { + // We have two consecutive N_SO entries where the first + // contains a directory + // and the second contains a full path. + sym[sym_idx - 1].GetMangled().SetValue( + ConstString(symbol_name), false); + m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; + add_nlist = false; + } else { + // This is the first entry in a N_SO that contains a directory + // or + // a full path to the source file + N_SO_index = sym_idx; + } + } else if ((N_SO_index == sym_idx - 1) && + ((sym_idx - 1) < num_syms)) { + // This is usually the second N_SO entry that contains just the + // filename, + // so here we combine it with the first one if we are minimizing + // the symbol table + const char *so_path = + sym[sym_idx - 1] + .GetMangled() + .GetDemangledName(lldb::eLanguageTypeUnknown) + .AsCString(); + if (so_path && so_path[0]) { + std::string full_so_path(so_path); + const size_t double_slash_pos = full_so_path.find("//"); + if (double_slash_pos != std::string::npos) { + // The linker has been generating bad N_SO entries with + // doubled up paths + // in the format "%s%s" where the first string in the + // DW_AT_comp_dir, + // and the second is the directory for the source file so + // you end up with + // a path that looks like "/tmp/src//tmp/src/" + FileSpec so_dir(so_path, false); + if (!so_dir.Exists()) { + so_dir.SetFile(&full_so_path[double_slash_pos + 1], + false); + if (so_dir.Exists()) { + // Trim off the incorrect path + full_so_path.erase(0, double_slash_pos + 1); + } } + } + if (*full_so_path.rbegin() != '/') + full_so_path += '/'; + full_so_path += symbol_name; + sym[sym_idx - 1].GetMangled().SetValue( + ConstString(full_so_path.c_str()), false); + add_nlist = false; + m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; } + } else { + // This could be a relative path to a N_SO + N_SO_index = sym_idx; + } } - } - -// StreamFile s(stdout, false); -// s.Printf ("Symbol table before CalculateSymbolSizes():\n"); -// symtab->Dump(&s, NULL, eSortOrderNone); - // Set symbol byte sizes correctly since mach-o nlist entries don't have sizes - symtab->CalculateSymbolSizes(); + break; -// s.Printf ("Symbol table after CalculateSymbolSizes():\n"); -// symtab->Dump(&s, NULL, eSortOrderNone); + case N_OSO: + // object file name: name,,0,0,st_mtime + type = eSymbolTypeObjectFile; + break; - return symtab->GetNumSymbols(); - } - return 0; -} + case N_LSYM: + // local sym: name,,NO_SECT,type,offset + type = eSymbolTypeLocal; + break; -void -ObjectFileMachO::Dump (Stream *s) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - s->Printf("%p: ", static_cast<void*>(this)); - s->Indent(); - if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64) - s->PutCString("ObjectFileMachO64"); - else - s->PutCString("ObjectFileMachO32"); + //---------------------------------------------------------------------- + // INCL scopes + //---------------------------------------------------------------------- + case N_BINCL: + // include file beginning: name,,NO_SECT,0,sum + // We use the current number of symbols in the symbol table in lieu + // of + // using nlist_idx in case we ever start trimming entries out + N_INCL_indexes.push_back(sym_idx); + type = eSymbolTypeScopeBegin; + break; - ArchSpec header_arch; - GetArchitecture(header_arch); + case N_EINCL: + // include file end: name,,NO_SECT,0,0 + // Set the size of the N_BINCL to the terminating index of this + // N_EINCL + // so that we can always skip the entire symbol if we need to + // navigate + // more quickly at the source level when parsing STABS + if (!N_INCL_indexes.empty()) { + symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); + symbol_ptr->SetByteSize(sym_idx + 1); + symbol_ptr->SetSizeIsSibling(true); + N_INCL_indexes.pop_back(); + } + type = eSymbolTypeScopeEnd; + break; - *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; + case N_SOL: + // #included file name: name,,n_sect,0,address + type = eSymbolTypeHeaderFile; - SectionList *sections = GetSectionList(); - if (sections) - sections->Dump(s, NULL, true, UINT32_MAX); + // We currently don't use the header files on darwin + add_nlist = false; + break; - if (m_symtab_ap.get()) - m_symtab_ap->Dump(s, NULL, eSortOrderNone); - } -} + case N_PARAMS: + // compiler parameters: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; -bool -ObjectFileMachO::GetUUID (const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - lldb_private::UUID& uuid) -{ - uint32_t i; - struct uuid_command load_cmd; + case N_VERSION: + // compiler version: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; + break; - lldb::offset_t offset = lc_offset; - for (i=0; i<header.ncmds; ++i) - { - const lldb::offset_t cmd_offset = offset; - if (data.GetU32(&offset, &load_cmd, 2) == NULL) + case N_OLEVEL: + // compiler -O level: name,,NO_SECT,0,0 + type = eSymbolTypeCompiler; break; - - if (load_cmd.cmd == LC_UUID) - { - const uint8_t *uuid_bytes = data.PeekData(offset, 16); - - if (uuid_bytes) - { - // OpenCL on Mac OS X uses the same UUID for each of its object files. - // We pretend these object files have no UUID to prevent crashing. - - const uint8_t opencl_uuid[] = { 0x8c, 0x8e, 0xb3, 0x9b, - 0x3b, 0xa8, - 0x4b, 0x16, - 0xb6, 0xa4, - 0x27, 0x63, 0xbb, 0x14, 0xf0, 0x0d }; - - if (!memcmp(uuid_bytes, opencl_uuid, 16)) - return false; - - uuid.SetBytes (uuid_bytes); - return true; - } - return false; - } - offset = cmd_offset + load_cmd.cmdsize; - } - return false; -} -bool -ObjectFileMachO::GetArchitecture (const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - ArchSpec &arch) -{ - arch.SetArchitecture (eArchTypeMachO, header.cputype, header.cpusubtype); - - if (arch.IsValid()) - { - llvm::Triple &triple = arch.GetTriple(); - - // Set OS to an unspecified unknown or a "*" so it can match any OS - triple.setOS(llvm::Triple::UnknownOS); - triple.setOSName(llvm::StringRef()); - - if (header.filetype == MH_PRELOAD) - { - if (header.cputype == CPU_TYPE_ARM) - { - // If this is a 32-bit arm binary, and it's a standalone binary, - // force the Vendor to Apple so we don't accidentally pick up - // the generic armv7 ABI at runtime. Apple's armv7 ABI always uses - // r7 for the frame pointer register; most other armv7 ABIs use a - // combination of r7 and r11. - triple.setVendor(llvm::Triple::Apple); - } - else - { - // Set vendor to an unspecified unknown or a "*" so it can match any vendor - // This is required for correct behavior of EFI debugging on x86_64 - triple.setVendor(llvm::Triple::UnknownVendor); - triple.setVendorName(llvm::StringRef()); + case N_PSYM: + // parameter: name,,NO_SECT,type,offset + type = eSymbolTypeVariable; + break; + + case N_ENTRY: + // alternate entry: name,,n_sect,linenumber,address + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + type = eSymbolTypeLineEntry; + break; + + //---------------------------------------------------------------------- + // Left and Right Braces + //---------------------------------------------------------------------- + case N_LBRAC: + // left bracket: 0,,NO_SECT,nesting level,address + // We use the current number of symbols in the symbol table in lieu + // of + // using nlist_idx in case we ever start trimming entries out + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + N_BRAC_indexes.push_back(sym_idx); + type = eSymbolTypeScopeBegin; + break; + + case N_RBRAC: + // right bracket: 0,,NO_SECT,nesting level,address + // Set the size of the N_LBRAC to the terminating index of this + // N_RBRAC + // so that we can always skip the entire symbol if we need to + // navigate + // more quickly at the source level when parsing STABS + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + if (!N_BRAC_indexes.empty()) { + symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back()); + symbol_ptr->SetByteSize(sym_idx + 1); + symbol_ptr->SetSizeIsSibling(true); + N_BRAC_indexes.pop_back(); } - return true; - } - else - { - struct load_command load_cmd; + type = eSymbolTypeScopeEnd; + break; - lldb::offset_t offset = lc_offset; - for (uint32_t i=0; i<header.ncmds; ++i) - { - const lldb::offset_t cmd_offset = offset; - if (data.GetU32(&offset, &load_cmd, 2) == NULL) - break; - - switch (load_cmd.cmd) - { - case llvm::MachO::LC_VERSION_MIN_IPHONEOS: - triple.setOS (llvm::Triple::IOS); - return true; - - case llvm::MachO::LC_VERSION_MIN_MACOSX: - triple.setOS (llvm::Triple::MacOSX); - return true; - - case llvm::MachO::LC_VERSION_MIN_TVOS: - triple.setOS (llvm::Triple::TvOS); - return true; - - case llvm::MachO::LC_VERSION_MIN_WATCHOS: - triple.setOS (llvm::Triple::WatchOS); - return true; + case N_EXCL: + // deleted include file: name,,NO_SECT,0,sum + type = eSymbolTypeHeaderFile; + break; - default: - break; - } + //---------------------------------------------------------------------- + // COMM scopes + //---------------------------------------------------------------------- + case N_BCOMM: + // begin common: name,,NO_SECT,0,0 + // We use the current number of symbols in the symbol table in lieu + // of + // using nlist_idx in case we ever start trimming entries out + type = eSymbolTypeScopeBegin; + N_COMM_indexes.push_back(sym_idx); + break; - offset = cmd_offset + load_cmd.cmdsize; + case N_ECOML: + // end common (local name): 0,,n_sect,0,address + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + LLVM_FALLTHROUGH; + + case N_ECOMM: + // end common: name,,n_sect,0,0 + // Set the size of the N_BCOMM to the terminating index of this + // N_ECOMM/N_ECOML + // so that we can always skip the entire symbol if we need to + // navigate + // more quickly at the source level when parsing STABS + if (!N_COMM_indexes.empty()) { + symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); + symbol_ptr->SetByteSize(sym_idx + 1); + symbol_ptr->SetSizeIsSibling(true); + N_COMM_indexes.pop_back(); } - - if (header.filetype != MH_KEXT_BUNDLE) - { - // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT - // so lets not say our Vendor is Apple, leave it as an unspecified unknown - triple.setVendor(llvm::Triple::UnknownVendor); - triple.setVendorName(llvm::StringRef()); + type = eSymbolTypeScopeEnd; + break; + + case N_LENG: + // second stab entry with length information + type = eSymbolTypeAdditional; + break; + + default: + break; + } + } else { + // uint8_t n_pext = N_PEXT & nlist.n_type; + uint8_t n_type = N_TYPE & nlist.n_type; + sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); + + switch (n_type) { + case N_INDR: { + const char *reexport_name_cstr = + strtab_data.PeekCStr(nlist.n_value); + if (reexport_name_cstr && reexport_name_cstr[0]) { + type = eSymbolTypeReExported; + ConstString reexport_name( + reexport_name_cstr + + ((reexport_name_cstr[0] == '_') ? 1 : 0)); + sym[sym_idx].SetReExportedSymbolName(reexport_name); + set_value = false; + reexport_shlib_needs_fixup[sym_idx] = reexport_name; + indirect_symbol_names.insert( + ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0))); + } else + type = eSymbolTypeUndefined; + } break; + + case N_UNDF: + if (symbol_name && symbol_name[0]) { + ConstString undefined_name(symbol_name + + ((symbol_name[0] == '_') ? 1 : 0)); + undefined_name_to_desc[undefined_name] = nlist.n_desc; } - } - } - return arch.IsValid(); -} + LLVM_FALLTHROUGH; -bool -ObjectFileMachO::GetUUID (lldb_private::UUID* uuid) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - return GetUUID (m_header, m_data, offset, *uuid); - } - return false; -} + case N_PBUD: + type = eSymbolTypeUndefined; + break; -uint32_t -ObjectFileMachO::GetDependentModules (FileSpecList& files) -{ - uint32_t count = 0; - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - struct load_command load_cmd; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - std::vector<std::string> rpath_paths; - std::vector<std::string> rpath_relative_paths; - const bool resolve_path = false; // Don't resolve the dependent file paths since they may not reside on this system - uint32_t i; - for (i=0; i<m_header.ncmds; ++i) - { - const uint32_t cmd_offset = offset; - if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) - break; + case N_ABS: + type = eSymbolTypeAbsolute; + break; - switch (load_cmd.cmd) - { - case LC_RPATH: - case LC_LOAD_DYLIB: - case LC_LOAD_WEAK_DYLIB: - case LC_REEXPORT_DYLIB: - case LC_LOAD_DYLINKER: - case LC_LOADFVMLIB: - case LC_LOAD_UPWARD_DYLIB: - { - uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); - const char *path = m_data.PeekCStr(name_offset); - if (path) - { - if (load_cmd.cmd == LC_RPATH) - rpath_paths.push_back(path); - else - { - if (path[0] == '@') - { - if (strncmp(path, "@rpath", strlen("@rpath")) == 0) - rpath_relative_paths.push_back(path + strlen("@rpath")); - } - else - { - FileSpec file_spec(path, resolve_path); - if (files.AppendIfUnique(file_spec)) - count++; - } + case N_SECT: { + symbol_section = + section_info.GetSection(nlist.n_sect, nlist.n_value); + + if (!symbol_section) { + // TODO: warn about this? + add_nlist = false; + break; + } + + if (TEXT_eh_frame_sectID == nlist.n_sect) { + type = eSymbolTypeException; + } else { + uint32_t section_type = symbol_section->Get() & SECTION_TYPE; + + switch (section_type) { + case S_CSTRING_LITERALS: + type = eSymbolTypeData; + break; // section with only literal C strings + case S_4BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 4 byte literals + case S_8BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 8 byte literals + case S_LITERAL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only pointers to literals + case S_NON_LAZY_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only non-lazy symbol pointers + case S_LAZY_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; // section with only lazy symbol pointers + case S_SYMBOL_STUBS: + type = eSymbolTypeTrampoline; + break; // section with only symbol stubs, byte size of stub in + // the reserved2 field + case S_MOD_INIT_FUNC_POINTERS: + type = eSymbolTypeCode; + break; // section with only function pointers for initialization + case S_MOD_TERM_FUNC_POINTERS: + type = eSymbolTypeCode; + break; // section with only function pointers for termination + case S_INTERPOSING: + type = eSymbolTypeTrampoline; + break; // section with only pairs of function pointers for + // interposing + case S_16BYTE_LITERALS: + type = eSymbolTypeData; + break; // section with only 16 byte literals + case S_DTRACE_DOF: + type = eSymbolTypeInstrumentation; + break; + case S_LAZY_DYLIB_SYMBOL_POINTERS: + type = eSymbolTypeTrampoline; + break; + default: + switch (symbol_section->GetType()) { + case lldb::eSectionTypeCode: + type = eSymbolTypeCode; + break; + case eSectionTypeData: + case eSectionTypeDataCString: // Inlined C string data + case eSectionTypeDataCStringPointers: // Pointers to C string + // data + case eSectionTypeDataSymbolAddress: // Address of a symbol in + // the symbol table + case eSectionTypeData4: + case eSectionTypeData8: + case eSectionTypeData16: + type = eSymbolTypeData; + break; + default: + break; + } + break; + } + + if (type == eSymbolTypeInvalid) { + const char *symbol_sect_name = + symbol_section->GetName().AsCString(); + if (symbol_section->IsDescendant(text_section_sp.get())) { + if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | + S_ATTR_SELF_MODIFYING_CODE | + S_ATTR_SOME_INSTRUCTIONS)) + type = eSymbolTypeData; + else + type = eSymbolTypeCode; + } else if (symbol_section->IsDescendant( + data_section_sp.get()) || + symbol_section->IsDescendant( + data_dirty_section_sp.get()) || + symbol_section->IsDescendant( + data_const_section_sp.get())) { + if (symbol_sect_name && + ::strstr(symbol_sect_name, "__objc") == + symbol_sect_name) { + type = eSymbolTypeRuntime; + + if (symbol_name) { + llvm::StringRef symbol_name_ref(symbol_name); + if (symbol_name_ref.startswith("_OBJC_")) { + static const llvm::StringRef g_objc_v2_prefix_class( + "_OBJC_CLASS_$_"); + static const llvm::StringRef g_objc_v2_prefix_metaclass( + "_OBJC_METACLASS_$_"); + static const llvm::StringRef g_objc_v2_prefix_ivar( + "_OBJC_IVAR_$_"); + if (symbol_name_ref.startswith( + g_objc_v2_prefix_class)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = + symbol_name + g_objc_v2_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_metaclass)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = + symbol_name + g_objc_v2_prefix_metaclass.size(); + type = eSymbolTypeObjCMetaClass; + demangled_is_synthesized = true; + } else if (symbol_name_ref.startswith( + g_objc_v2_prefix_ivar)) { + symbol_name_non_abi_mangled = symbol_name + 1; + symbol_name = + symbol_name + g_objc_v2_prefix_ivar.size(); + type = eSymbolTypeObjCIVar; + demangled_is_synthesized = true; } + } + } + } else if (symbol_sect_name && + ::strstr(symbol_sect_name, "__gcc_except_tab") == + symbol_sect_name) { + type = eSymbolTypeException; + } else { + type = eSymbolTypeData; + } + } else if (symbol_sect_name && + ::strstr(symbol_sect_name, "__IMPORT") == + symbol_sect_name) { + type = eSymbolTypeTrampoline; + } else if (symbol_section->IsDescendant( + objc_section_sp.get())) { + type = eSymbolTypeRuntime; + if (symbol_name && symbol_name[0] == '.') { + llvm::StringRef symbol_name_ref(symbol_name); + static const llvm::StringRef g_objc_v1_prefix_class( + ".objc_class_name_"); + if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) { + symbol_name_non_abi_mangled = symbol_name; + symbol_name = symbol_name + g_objc_v1_prefix_class.size(); + type = eSymbolTypeObjCClass; + demangled_is_synthesized = true; } + } } - break; - - default: - break; + } } - offset = cmd_offset + load_cmd.cmdsize; + } break; + } } - if (!rpath_paths.empty()) - { - // Fixup all LC_RPATH values to be absolute paths - FileSpec this_file_spec(m_file); - this_file_spec.ResolvePath(); - std::string loader_path("@loader_path"); - std::string executable_path("@executable_path"); - for (auto &rpath : rpath_paths) - { - if (rpath.find(loader_path) == 0) - { - rpath.erase(0, loader_path.size()); - rpath.insert(0, this_file_spec.GetDirectory().GetCString()); + if (add_nlist) { + uint64_t symbol_value = nlist.n_value; + + if (symbol_name_non_abi_mangled) { + sym[sym_idx].GetMangled().SetMangledName( + ConstString(symbol_name_non_abi_mangled)); + sym[sym_idx].GetMangled().SetDemangledName( + ConstString(symbol_name)); + } else { + bool symbol_name_is_mangled = false; + + if (symbol_name && symbol_name[0] == '_') { + symbol_name_is_mangled = symbol_name[1] == '_'; + symbol_name++; // Skip the leading underscore + } + + if (symbol_name) { + ConstString const_symbol_name(symbol_name); + sym[sym_idx].GetMangled().SetValue(const_symbol_name, + symbol_name_is_mangled); + } + } + + if (is_gsym) { + const char *gsym_name = sym[sym_idx] + .GetMangled() + .GetName(lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) + .GetCString(); + if (gsym_name) + N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; + } + + if (symbol_section) { + const addr_t section_file_addr = symbol_section->GetFileAddress(); + if (symbol_byte_size == 0 && function_starts_count > 0) { + addr_t symbol_lookup_file_addr = nlist.n_value; + // Do an exact address match for non-ARM addresses, else get the + // closest since + // the symbol might be a thumb symbol which has an address with + // bit zero set + FunctionStarts::Entry *func_start_entry = + function_starts.FindEntry(symbol_lookup_file_addr, !is_arm); + if (is_arm && func_start_entry) { + // Verify that the function start address is the symbol address + // (ARM) + // or the symbol address + 1 (thumb) + if (func_start_entry->addr != symbol_lookup_file_addr && + func_start_entry->addr != (symbol_lookup_file_addr + 1)) { + // Not the right entry, NULL it out... + func_start_entry = NULL; } - else if (rpath.find(executable_path) == 0) - { - rpath.erase(0, executable_path.size()); - rpath.insert(0, this_file_spec.GetDirectory().GetCString()); + } + if (func_start_entry) { + func_start_entry->data = true; + + addr_t symbol_file_addr = func_start_entry->addr; + if (is_arm) + symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; + + const FunctionStarts::Entry *next_func_start_entry = + function_starts.FindNextEntry(func_start_entry); + const addr_t section_end_file_addr = + section_file_addr + symbol_section->GetByteSize(); + if (next_func_start_entry) { + addr_t next_symbol_file_addr = next_func_start_entry->addr; + // Be sure the clear the Thumb address bit when we calculate + // the size + // from the current and next address + if (is_arm) + next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; + symbol_byte_size = std::min<lldb::addr_t>( + next_symbol_file_addr - symbol_file_addr, + section_end_file_addr - symbol_file_addr); + } else { + symbol_byte_size = section_end_file_addr - symbol_file_addr; } + } } - - for (const auto &rpath_relative_path : rpath_relative_paths) - { - for (const auto &rpath : rpath_paths) - { - std::string path = rpath; - path += rpath_relative_path; - // It is OK to resolve this path because we must find a file on - // disk for us to accept it anyway if it is rpath relative. - FileSpec file_spec(path, true); - // Remove any redundant parts of the path (like "../foo") since - // LC_RPATH values often contain "..". - file_spec.NormalizePath (); - if (file_spec.Exists() && files.AppendIfUnique(file_spec)) - { - count++; - break; - } + symbol_value -= section_file_addr; + } + + if (is_debug == false) { + if (type == eSymbolTypeCode) { + // See if we can find a N_FUN entry for any code symbols. + // If we do find a match, and the name matches, then we + // can merge the two into just the function symbol to avoid + // duplicate entries in the symbol table + std::pair<ValueToSymbolIndexMap::const_iterator, + ValueToSymbolIndexMap::const_iterator> + range; + range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value); + if (range.first != range.second) { + bool found_it = false; + for (ValueToSymbolIndexMap::const_iterator pos = range.first; + pos != range.second; ++pos) { + if (sym[sym_idx].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) == + sym[pos->second].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled)) { + m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; + // We just need the flags from the linker symbol, so put + // these flags + // into the N_FUN flags to avoid duplicate symbols in the + // symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); + sym[pos->second].SetFlags(nlist.n_type << 16 | + nlist.n_desc); + if (resolver_addresses.find(nlist.n_value) != + resolver_addresses.end()) + sym[pos->second].SetType(eSymbolTypeResolver); + sym[sym_idx].Clear(); + found_it = true; + break; + } } + if (found_it) + continue; + } else { + if (resolver_addresses.find(nlist.n_value) != + resolver_addresses.end()) + type = eSymbolTypeResolver; + } + } else if (type == eSymbolTypeData || + type == eSymbolTypeObjCClass || + type == eSymbolTypeObjCMetaClass || + type == eSymbolTypeObjCIVar) { + // See if we can find a N_STSYM entry for any data symbols. + // If we do find a match, and the name matches, then we + // can merge the two into just the Static symbol to avoid + // duplicate entries in the symbol table + std::pair<ValueToSymbolIndexMap::const_iterator, + ValueToSymbolIndexMap::const_iterator> + range; + range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value); + if (range.first != range.second) { + bool found_it = false; + for (ValueToSymbolIndexMap::const_iterator pos = range.first; + pos != range.second; ++pos) { + if (sym[sym_idx].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) == + sym[pos->second].GetMangled().GetName( + lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled)) { + m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; + // We just need the flags from the linker symbol, so put + // these flags + // into the N_STSYM flags to avoid duplicate symbols in the + // symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); + sym[pos->second].SetFlags(nlist.n_type << 16 | + nlist.n_desc); + sym[sym_idx].Clear(); + found_it = true; + break; + } + } + if (found_it) + continue; + } else { + // Combine N_GSYM stab entries with the non stab symbol + const char *gsym_name = sym[sym_idx] + .GetMangled() + .GetName(lldb::eLanguageTypeUnknown, + Mangled::ePreferMangled) + .GetCString(); + if (gsym_name) { + ConstNameToSymbolIndexMap::const_iterator pos = + N_GSYM_name_to_sym_idx.find(gsym_name); + if (pos != N_GSYM_name_to_sym_idx.end()) { + const uint32_t GSYM_sym_idx = pos->second; + m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx; + // Copy the address, because often the N_GSYM address has an + // invalid address of zero + // when the global is a common symbol + sym[GSYM_sym_idx].GetAddressRef().SetSection( + symbol_section); + sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value); + // We just need the flags from the linker symbol, so put + // these flags + // into the N_GSYM flags to avoid duplicate symbols in the + // symbol table + sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 | + nlist.n_desc); + sym[sym_idx].Clear(); + continue; + } + } + } } - } - } - return count; -} + } -lldb_private::Address -ObjectFileMachO::GetEntryPointAddress () -{ - // If the object file is not an executable it can't hold the entry point. m_entry_point_address - // is initialized to an invalid address, so we can just return that. - // If m_entry_point_address is valid it means we've found it already, so return the cached value. + sym[sym_idx].SetID(nlist_idx); + sym[sym_idx].SetType(type); + if (set_value) { + sym[sym_idx].GetAddressRef().SetSection(symbol_section); + sym[sym_idx].GetAddressRef().SetOffset(symbol_value); + } + sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); - if (!IsExecutable() || m_entry_point_address.IsValid()) - return m_entry_point_address; + if (symbol_byte_size > 0) + sym[sym_idx].SetByteSize(symbol_byte_size); - // Otherwise, look for the UnixThread or Thread command. The data for the Thread command is given in - // /usr/include/mach-o.h, but it is basically: - // - // uint32_t flavor - this is the flavor argument you would pass to thread_get_state - // uint32_t count - this is the count of longs in the thread state data - // struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor. - // <repeat this trio> - // - // So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there. - // FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers - // out of data in this form & attach them to a given thread. That should underlie the MacOS X User process plugin, - // and we'll also need it for the MacOS X Core File process plugin. When we have that we can also use it here. - // - // For now we hard-code the offsets and flavors we need: - // - // + if (demangled_is_synthesized) + sym[sym_idx].SetDemangledNameIsSynthesized(true); - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - struct load_command load_cmd; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - uint32_t i; - lldb::addr_t start_address = LLDB_INVALID_ADDRESS; - bool done = false; + ++sym_idx; + } else { + sym[sym_idx].Clear(); + } + } + + for (const auto &pos : reexport_shlib_needs_fixup) { + const auto undef_pos = undefined_name_to_desc.find(pos.second); + if (undef_pos != undefined_name_to_desc.end()) { + const uint8_t dylib_ordinal = + llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); + if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize()) + sym[pos.first].SetReExportedSymbolSharedLibrary( + dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1)); + } + } + } - for (i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t cmd_offset = offset; - if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) - break; + uint32_t synthetic_sym_id = symtab_load_command.nsyms; - switch (load_cmd.cmd) - { - case LC_UNIXTHREAD: - case LC_THREAD: - { - while (offset < cmd_offset + load_cmd.cmdsize) - { - uint32_t flavor = m_data.GetU32(&offset); - uint32_t count = m_data.GetU32(&offset); - if (count == 0) - { - // We've gotten off somehow, log and exit; - return m_entry_point_address; - } + if (function_starts_count > 0) { + uint32_t num_synthetic_function_symbols = 0; + for (i = 0; i < function_starts_count; ++i) { + if (function_starts.GetEntryRef(i).data == false) + ++num_synthetic_function_symbols; + } - switch (m_header.cputype) - { - case llvm::MachO::CPU_TYPE_ARM: - if (flavor == 1 || flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 from mach/arm/thread_status.h - { - offset += 60; // This is the offset of pc in the GPR thread state data structure. - start_address = m_data.GetU32(&offset); - done = true; - } - break; - case llvm::MachO::CPU_TYPE_ARM64: - if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h - { - offset += 256; // This is the offset of pc in the GPR thread state data structure. - start_address = m_data.GetU64(&offset); - done = true; - } - break; - case llvm::MachO::CPU_TYPE_I386: - if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h - { - offset += 40; // This is the offset of eip in the GPR thread state data structure. - start_address = m_data.GetU32(&offset); - done = true; - } - break; - case llvm::MachO::CPU_TYPE_X86_64: - if (flavor == 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h - { - offset += 16 * 8; // This is the offset of rip in the GPR thread state data structure. - start_address = m_data.GetU64(&offset); - done = true; - } - break; - default: - return m_entry_point_address; - } - // Haven't found the GPR flavor yet, skip over the data for this flavor: - if (done) - break; - offset += count * 4; - } - } - break; - case LC_MAIN: - { - ConstString text_segment_name ("__TEXT"); - uint64_t entryoffset = m_data.GetU64(&offset); - SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name); - if (text_segment_sp) - { - done = true; - start_address = text_segment_sp->GetFileAddress() + entryoffset; - } + if (num_synthetic_function_symbols > 0) { + if (num_syms < sym_idx + num_synthetic_function_symbols) { + num_syms = sym_idx + num_synthetic_function_symbols; + sym = symtab->Resize(num_syms); + } + for (i = 0; i < function_starts_count; ++i) { + const FunctionStarts::Entry *func_start_entry = + function_starts.GetEntryAtIndex(i); + if (func_start_entry->data == false) { + addr_t symbol_file_addr = func_start_entry->addr; + uint32_t symbol_flags = 0; + if (is_arm) { + if (symbol_file_addr & 1) + symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB; + symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; + } + Address symbol_addr; + if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) { + SectionSP symbol_section(symbol_addr.GetSection()); + uint32_t symbol_byte_size = 0; + if (symbol_section) { + const addr_t section_file_addr = + symbol_section->GetFileAddress(); + const FunctionStarts::Entry *next_func_start_entry = + function_starts.FindNextEntry(func_start_entry); + const addr_t section_end_file_addr = + section_file_addr + symbol_section->GetByteSize(); + if (next_func_start_entry) { + addr_t next_symbol_file_addr = next_func_start_entry->addr; + if (is_arm) + next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK; + symbol_byte_size = std::min<lldb::addr_t>( + next_symbol_file_addr - symbol_file_addr, + section_end_file_addr - symbol_file_addr); + } else { + symbol_byte_size = section_end_file_addr - symbol_file_addr; } - break; - - default: - break; + sym[sym_idx].SetID(synthetic_sym_id++); + sym[sym_idx].GetMangled().SetDemangledName( + GetNextSyntheticSymbolName()); + sym[sym_idx].SetType(eSymbolTypeCode); + sym[sym_idx].SetIsSynthetic(true); + sym[sym_idx].GetAddressRef() = symbol_addr; + if (symbol_flags) + sym[sym_idx].SetFlags(symbol_flags); + if (symbol_byte_size) + sym[sym_idx].SetByteSize(symbol_byte_size); + ++sym_idx; + } } - if (done) - break; - - // Go to the next load command: - offset = cmd_offset + load_cmd.cmdsize; + } } + } + } - if (start_address != LLDB_INVALID_ADDRESS) - { - // We got the start address from the load commands, so now resolve that address in the sections - // of this ObjectFile: - if (!m_entry_point_address.ResolveAddressUsingFileSections (start_address, GetSectionList())) - { - m_entry_point_address.Clear(); - } - } - else - { - // We couldn't read the UnixThread load command - maybe it wasn't there. As a fallback look for the - // "start" symbol in the main executable. + // Trim our symbols down to just what we ended up with after + // removing any symbols. + if (sym_idx < num_syms) { + num_syms = sym_idx; + sym = symtab->Resize(num_syms); + } - ModuleSP module_sp (GetModule()); + // Now synthesize indirect symbols + if (m_dysymtab.nindirectsyms != 0) { + if (indirect_symbol_index_data.GetByteSize()) { + NListIndexToSymbolIndexMap::const_iterator end_index_pos = + m_nlist_idx_to_sym_idx.end(); + + for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); + ++sect_idx) { + if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == + S_SYMBOL_STUBS) { + uint32_t symbol_stub_byte_size = + m_mach_sections[sect_idx].reserved2; + if (symbol_stub_byte_size == 0) + continue; + + const uint32_t num_symbol_stubs = + m_mach_sections[sect_idx].size / symbol_stub_byte_size; + + if (num_symbol_stubs == 0) + continue; + + const uint32_t symbol_stub_index_offset = + m_mach_sections[sect_idx].reserved1; + for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; + ++stub_idx) { + const uint32_t symbol_stub_index = + symbol_stub_index_offset + stub_idx; + const lldb::addr_t symbol_stub_addr = + m_mach_sections[sect_idx].addr + + (stub_idx * symbol_stub_byte_size); + lldb::offset_t symbol_stub_offset = symbol_stub_index * 4; + if (indirect_symbol_index_data.ValidOffsetForDataOfSize( + symbol_stub_offset, 4)) { + const uint32_t stub_sym_id = + indirect_symbol_index_data.GetU32(&symbol_stub_offset); + if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL)) + continue; + + NListIndexToSymbolIndexMap::const_iterator index_pos = + m_nlist_idx_to_sym_idx.find(stub_sym_id); + Symbol *stub_symbol = NULL; + if (index_pos != end_index_pos) { + // We have a remapping from the original nlist index to + // a current symbol index, so just look this up by index + stub_symbol = symtab->SymbolAtIndex(index_pos->second); + } else { + // We need to lookup a symbol using the original nlist + // symbol index since this index is coming from the + // S_SYMBOL_STUBS + stub_symbol = symtab->FindSymbolByID(stub_sym_id); + } - if (module_sp) - { - SymbolContextList contexts; - SymbolContext context; - if (module_sp->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts)) - { - if (contexts.GetContextAtIndex(0, context)) - m_entry_point_address = context.symbol->GetAddress(); + if (stub_symbol) { + Address so_addr(symbol_stub_addr, section_list); + + if (stub_symbol->GetType() == eSymbolTypeUndefined) { + // Change the external symbol into a trampoline that makes + // sense + // These symbols were N_UNDF N_EXT, and are useless to us, + // so we + // can re-use them so we don't have to make up a synthetic + // symbol + // for no good reason. + if (resolver_addresses.find(symbol_stub_addr) == + resolver_addresses.end()) + stub_symbol->SetType(eSymbolTypeTrampoline); + else + stub_symbol->SetType(eSymbolTypeResolver); + stub_symbol->SetExternal(false); + stub_symbol->GetAddressRef() = so_addr; + stub_symbol->SetByteSize(symbol_stub_byte_size); + } else { + // Make a synthetic symbol to describe the trampoline stub + Mangled stub_symbol_mangled_name(stub_symbol->GetMangled()); + if (sym_idx >= num_syms) { + sym = symtab->Resize(++num_syms); + stub_symbol = NULL; // this pointer no longer valid + } + sym[sym_idx].SetID(synthetic_sym_id++); + sym[sym_idx].GetMangled() = stub_symbol_mangled_name; + if (resolver_addresses.find(symbol_stub_addr) == + resolver_addresses.end()) + sym[sym_idx].SetType(eSymbolTypeTrampoline); + else + sym[sym_idx].SetType(eSymbolTypeResolver); + sym[sym_idx].SetIsSynthetic(true); + sym[sym_idx].GetAddressRef() = so_addr; + sym[sym_idx].SetByteSize(symbol_stub_byte_size); + ++sym_idx; + } + } else { + if (log) + log->Warning("symbol stub referencing symbol table symbol " + "%u that isn't in our minimal symbol table, " + "fix this!!!", + stub_sym_id); } + } } + } } + } } - return m_entry_point_address; -} - -lldb_private::Address -ObjectFileMachO::GetHeaderAddress () -{ - lldb_private::Address header_addr; - SectionList *section_list = GetSectionList(); - if (section_list) - { - SectionSP text_segment_sp (section_list->FindSectionByName (GetSegmentNameTEXT())); - if (text_segment_sp) - { - header_addr.SetSection (text_segment_sp); - header_addr.SetOffset (0); + if (!trie_entries.empty()) { + for (const auto &e : trie_entries) { + if (e.entry.import_name) { + // Only add indirect symbols from the Trie entries if we + // didn't have a N_INDR nlist entry for this already + if (indirect_symbol_names.find(e.entry.name) == + indirect_symbol_names.end()) { + // Make a synthetic symbol to describe re-exported symbol. + if (sym_idx >= num_syms) + sym = symtab->Resize(++num_syms); + sym[sym_idx].SetID(synthetic_sym_id++); + sym[sym_idx].GetMangled() = Mangled(e.entry.name); + sym[sym_idx].SetType(eSymbolTypeReExported); + sym[sym_idx].SetIsSynthetic(true); + sym[sym_idx].SetReExportedSymbolName(e.entry.import_name); + if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) { + sym[sym_idx].SetReExportedSymbolSharedLibrary( + dylib_files.GetFileSpecAtIndex(e.entry.other - 1)); + } + ++sym_idx; + } } + } } - return header_addr; + + // StreamFile s(stdout, false); + // s.Printf ("Symbol table before CalculateSymbolSizes():\n"); + // symtab->Dump(&s, NULL, eSortOrderNone); + // Set symbol byte sizes correctly since mach-o nlist entries don't have + // sizes + symtab->CalculateSymbolSizes(); + + // s.Printf ("Symbol table after CalculateSymbolSizes():\n"); + // symtab->Dump(&s, NULL, eSortOrderNone); + + return symtab->GetNumSymbols(); + } + return 0; } -uint32_t -ObjectFileMachO::GetNumThreadContexts () -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - if (!m_thread_context_offsets_valid) - { - m_thread_context_offsets_valid = true; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - FileRangeArray::Entry file_range; - thread_command thread_cmd; - for (uint32_t i=0; i<m_header.ncmds; ++i) - { - const uint32_t cmd_offset = offset; - if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL) - break; +void ObjectFileMachO::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + s->Printf("%p: ", static_cast<void *>(this)); + s->Indent(); + if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64) + s->PutCString("ObjectFileMachO64"); + else + s->PutCString("ObjectFileMachO32"); - if (thread_cmd.cmd == LC_THREAD) - { - file_range.SetRangeBase (offset); - file_range.SetByteSize (thread_cmd.cmdsize - 8); - m_thread_context_offsets.Append (file_range); - } - offset = cmd_offset + thread_cmd.cmdsize; - } - } - } - return m_thread_context_offsets.GetSize(); + ArchSpec header_arch; + GetArchitecture(header_arch); + + *s << ", file = '" << m_file + << "', arch = " << header_arch.GetArchitectureName() << "\n"; + + SectionList *sections = GetSectionList(); + if (sections) + sections->Dump(s, NULL, true, UINT32_MAX); + + if (m_symtab_ap.get()) + m_symtab_ap->Dump(s, NULL, eSortOrderNone); + } } -lldb::RegisterContextSP -ObjectFileMachO::GetThreadContextAtIndex (uint32_t idx, lldb_private::Thread &thread) -{ - lldb::RegisterContextSP reg_ctx_sp; +bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset, + lldb_private::UUID &uuid) { + uint32_t i; + struct uuid_command load_cmd; - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - if (!m_thread_context_offsets_valid) - GetNumThreadContexts (); + lldb::offset_t offset = lc_offset; + for (i = 0; i < header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (data.GetU32(&offset, &load_cmd, 2) == NULL) + break; - const FileRangeArray::Entry *thread_context_file_range = m_thread_context_offsets.GetEntryAtIndex (idx); - if (thread_context_file_range) - { + if (load_cmd.cmd == LC_UUID) { + const uint8_t *uuid_bytes = data.PeekData(offset, 16); - DataExtractor data (m_data, - thread_context_file_range->GetRangeBase(), - thread_context_file_range->GetByteSize()); + if (uuid_bytes) { + // OpenCL on Mac OS X uses the same UUID for each of its object files. + // We pretend these object files have no UUID to prevent crashing. - switch (m_header.cputype) - { - case llvm::MachO::CPU_TYPE_ARM64: - reg_ctx_sp.reset (new RegisterContextDarwin_arm64_Mach (thread, data)); - break; - - case llvm::MachO::CPU_TYPE_ARM: - reg_ctx_sp.reset (new RegisterContextDarwin_arm_Mach (thread, data)); - break; + const uint8_t opencl_uuid[] = {0x8c, 0x8e, 0xb3, 0x9b, 0x3b, 0xa8, + 0x4b, 0x16, 0xb6, 0xa4, 0x27, 0x63, + 0xbb, 0x14, 0xf0, 0x0d}; - case llvm::MachO::CPU_TYPE_I386: - reg_ctx_sp.reset (new RegisterContextDarwin_i386_Mach (thread, data)); - break; + if (!memcmp(uuid_bytes, opencl_uuid, 16)) + return false; - case llvm::MachO::CPU_TYPE_X86_64: - reg_ctx_sp.reset (new RegisterContextDarwin_x86_64_Mach (thread, data)); - break; - } + uuid.SetBytes(uuid_bytes); + return true; + } + return false; + } + offset = cmd_offset + load_cmd.cmdsize; + } + return false; +} + +bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset, + ArchSpec &arch) { + arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype); + + if (arch.IsValid()) { + llvm::Triple &triple = arch.GetTriple(); + + // Set OS to an unspecified unknown or a "*" so it can match any OS + triple.setOS(llvm::Triple::UnknownOS); + triple.setOSName(llvm::StringRef()); + + if (header.filetype == MH_PRELOAD) { + if (header.cputype == CPU_TYPE_ARM) { + // If this is a 32-bit arm binary, and it's a standalone binary, + // force the Vendor to Apple so we don't accidentally pick up + // the generic armv7 ABI at runtime. Apple's armv7 ABI always uses + // r7 for the frame pointer register; most other armv7 ABIs use a + // combination of r7 and r11. + triple.setVendor(llvm::Triple::Apple); + } else { + // Set vendor to an unspecified unknown or a "*" so it can match any + // vendor + // This is required for correct behavior of EFI debugging on x86_64 + triple.setVendor(llvm::Triple::UnknownVendor); + triple.setVendorName(llvm::StringRef()); + } + return true; + } else { + struct load_command load_cmd; + + lldb::offset_t offset = lc_offset; + for (uint32_t i = 0; i < header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + switch (load_cmd.cmd) { + case llvm::MachO::LC_VERSION_MIN_IPHONEOS: + triple.setOS(llvm::Triple::IOS); + return true; + + case llvm::MachO::LC_VERSION_MIN_MACOSX: + triple.setOS(llvm::Triple::MacOSX); + return true; + + case llvm::MachO::LC_VERSION_MIN_TVOS: + triple.setOS(llvm::Triple::TvOS); + return true; + + case llvm::MachO::LC_VERSION_MIN_WATCHOS: + triple.setOS(llvm::Triple::WatchOS); + return true; + + default: + break; } + + offset = cmd_offset + load_cmd.cmdsize; + } + + if (header.filetype != MH_KEXT_BUNDLE) { + // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT + // so lets not say our Vendor is Apple, leave it as an unspecified + // unknown + triple.setVendor(llvm::Triple::UnknownVendor); + triple.setVendorName(llvm::StringRef()); + } } - return reg_ctx_sp; + } + return arch.IsValid(); } -ObjectFile::Type -ObjectFileMachO::CalculateType() -{ - switch (m_header.filetype) - { - case MH_OBJECT: // 0x1u - if (GetAddressByteSize () == 4) - { - // 32 bit kexts are just object files, but they do have a valid - // UUID load command. - UUID uuid; - if (GetUUID(&uuid)) - { - // this checking for the UUID load command is not enough - // we could eventually look for the symbol named - // "OSKextGetCurrentIdentifier" as this is required of kexts - if (m_strata == eStrataInvalid) - m_strata = eStrataKernel; - return eTypeSharedLibrary; - } +bool ObjectFileMachO::GetUUID(lldb_private::UUID *uuid) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + return GetUUID(m_header, m_data, offset, *uuid); + } + return false; +} + +uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { + uint32_t count = 0; + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + struct load_command load_cmd; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + std::vector<std::string> rpath_paths; + std::vector<std::string> rpath_relative_paths; + const bool resolve_path = false; // Don't resolve the dependent file paths + // since they may not reside on this system + uint32_t i; + for (i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + switch (load_cmd.cmd) { + case LC_RPATH: + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + case LC_REEXPORT_DYLIB: + case LC_LOAD_DYLINKER: + case LC_LOADFVMLIB: + case LC_LOAD_UPWARD_DYLIB: { + uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); + const char *path = m_data.PeekCStr(name_offset); + if (path) { + if (load_cmd.cmd == LC_RPATH) + rpath_paths.push_back(path); + else { + if (path[0] == '@') { + if (strncmp(path, "@rpath", strlen("@rpath")) == 0) + rpath_relative_paths.push_back(path + strlen("@rpath")); + } else { + FileSpec file_spec(path, resolve_path); + if (files.AppendIfUnique(file_spec)) + count++; } - return eTypeObjectFile; - - case MH_EXECUTE: return eTypeExecutable; // 0x2u - case MH_FVMLIB: return eTypeSharedLibrary; // 0x3u - case MH_CORE: return eTypeCoreFile; // 0x4u - case MH_PRELOAD: return eTypeSharedLibrary; // 0x5u - case MH_DYLIB: return eTypeSharedLibrary; // 0x6u - case MH_DYLINKER: return eTypeDynamicLinker; // 0x7u - case MH_BUNDLE: return eTypeSharedLibrary; // 0x8u - case MH_DYLIB_STUB: return eTypeStubLibrary; // 0x9u - case MH_DSYM: return eTypeDebugInfo; // 0xAu - case MH_KEXT_BUNDLE: return eTypeSharedLibrary; // 0xBu - default: + } + } + } break; + + default: + break; + } + offset = cmd_offset + load_cmd.cmdsize; + } + + if (!rpath_paths.empty()) { + // Fixup all LC_RPATH values to be absolute paths + FileSpec this_file_spec(m_file); + this_file_spec.ResolvePath(); + std::string loader_path("@loader_path"); + std::string executable_path("@executable_path"); + for (auto &rpath : rpath_paths) { + if (rpath.find(loader_path) == 0) { + rpath.erase(0, loader_path.size()); + rpath.insert(0, this_file_spec.GetDirectory().GetCString()); + } else if (rpath.find(executable_path) == 0) { + rpath.erase(0, executable_path.size()); + rpath.insert(0, this_file_spec.GetDirectory().GetCString()); + } + } + + for (const auto &rpath_relative_path : rpath_relative_paths) { + for (const auto &rpath : rpath_paths) { + std::string path = rpath; + path += rpath_relative_path; + // It is OK to resolve this path because we must find a file on + // disk for us to accept it anyway if it is rpath relative. + FileSpec file_spec(path, true); + // Remove any redundant parts of the path (like "../foo") since + // LC_RPATH values often contain "..". + file_spec.NormalizePath(); + if (file_spec.Exists() && files.AppendIfUnique(file_spec)) { + count++; break; + } + } + } } - return eTypeUnknown; + } + return count; } -ObjectFile::Strata -ObjectFileMachO::CalculateStrata() -{ - switch (m_header.filetype) - { - case MH_OBJECT: // 0x1u +lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { + // If the object file is not an executable it can't hold the entry point. + // m_entry_point_address + // is initialized to an invalid address, so we can just return that. + // If m_entry_point_address is valid it means we've found it already, so + // return the cached value. + + if (!IsExecutable() || m_entry_point_address.IsValid()) + return m_entry_point_address; + + // Otherwise, look for the UnixThread or Thread command. The data for the + // Thread command is given in + // /usr/include/mach-o.h, but it is basically: + // + // uint32_t flavor - this is the flavor argument you would pass to + // thread_get_state + // uint32_t count - this is the count of longs in the thread state data + // struct XXX_thread_state state - this is the structure from + // <machine/thread_status.h> corresponding to the flavor. + // <repeat this trio> + // + // So we just keep reading the various register flavors till we find the GPR + // one, then read the PC out of there. + // FIXME: We will need to have a "RegisterContext data provider" class at some + // point that can get all the registers + // out of data in this form & attach them to a given thread. That should + // underlie the MacOS X User process plugin, + // and we'll also need it for the MacOS X Core File process plugin. When we + // have that we can also use it here. + // + // For now we hard-code the offsets and flavors we need: + // + // + + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + struct load_command load_cmd; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + uint32_t i; + lldb::addr_t start_address = LLDB_INVALID_ADDRESS; + bool done = false; + + for (i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + switch (load_cmd.cmd) { + case LC_UNIXTHREAD: + case LC_THREAD: { + while (offset < cmd_offset + load_cmd.cmdsize) { + uint32_t flavor = m_data.GetU32(&offset); + uint32_t count = m_data.GetU32(&offset); + if (count == 0) { + // We've gotten off somehow, log and exit; + return m_entry_point_address; + } + + switch (m_header.cputype) { + case llvm::MachO::CPU_TYPE_ARM: + if (flavor == 1 || + flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 from + // mach/arm/thread_status.h { - // 32 bit kexts are just object files, but they do have a valid - // UUID load command. - UUID uuid; - if (GetUUID(&uuid)) - { - // this checking for the UUID load command is not enough - // we could eventually look for the symbol named - // "OSKextGetCurrentIdentifier" as this is required of kexts - if (m_type == eTypeInvalid) - m_type = eTypeSharedLibrary; - - return eStrataKernel; - } + offset += 60; // This is the offset of pc in the GPR thread state + // data structure. + start_address = m_data.GetU32(&offset); + done = true; } - return eStrataUnknown; - - case MH_EXECUTE: // 0x2u - // Check for the MH_DYLDLINK bit in the flags - if (m_header.flags & MH_DYLDLINK) + break; + case llvm::MachO::CPU_TYPE_ARM64: + if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h { - return eStrataUser; + offset += 256; // This is the offset of pc in the GPR thread state + // data structure. + start_address = m_data.GetU64(&offset); + done = true; } - else + break; + case llvm::MachO::CPU_TYPE_I386: + if (flavor == + 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h { - SectionList *section_list = GetSectionList(); - if (section_list) - { - static ConstString g_kld_section_name ("__KLD"); - if (section_list->FindSectionByName(g_kld_section_name)) - return eStrataKernel; - } + offset += 40; // This is the offset of eip in the GPR thread state + // data structure. + start_address = m_data.GetU32(&offset); + done = true; } - return eStrataRawImage; - - case MH_FVMLIB: return eStrataUser; // 0x3u - case MH_CORE: return eStrataUnknown; // 0x4u - case MH_PRELOAD: return eStrataRawImage; // 0x5u - case MH_DYLIB: return eStrataUser; // 0x6u - case MH_DYLINKER: return eStrataUser; // 0x7u - case MH_BUNDLE: return eStrataUser; // 0x8u - case MH_DYLIB_STUB: return eStrataUser; // 0x9u - case MH_DSYM: return eStrataUnknown; // 0xAu - case MH_KEXT_BUNDLE: return eStrataKernel; // 0xBu - default: break; + case llvm::MachO::CPU_TYPE_X86_64: + if (flavor == + 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h + { + offset += 16 * 8; // This is the offset of rip in the GPR thread + // state data structure. + start_address = m_data.GetU64(&offset); + done = true; + } + break; + default: + return m_entry_point_address; + } + // Haven't found the GPR flavor yet, skip over the data for this + // flavor: + if (done) + break; + offset += count * 4; + } + } break; + case LC_MAIN: { + ConstString text_segment_name("__TEXT"); + uint64_t entryoffset = m_data.GetU64(&offset); + SectionSP text_segment_sp = + GetSectionList()->FindSectionByName(text_segment_name); + if (text_segment_sp) { + done = true; + start_address = text_segment_sp->GetFileAddress() + entryoffset; + } + } break; + + default: + break; + } + if (done) + break; + + // Go to the next load command: + offset = cmd_offset + load_cmd.cmdsize; } - return eStrataUnknown; + + if (start_address != LLDB_INVALID_ADDRESS) { + // We got the start address from the load commands, so now resolve that + // address in the sections + // of this ObjectFile: + if (!m_entry_point_address.ResolveAddressUsingFileSections( + start_address, GetSectionList())) { + m_entry_point_address.Clear(); + } + } else { + // We couldn't read the UnixThread load command - maybe it wasn't there. + // As a fallback look for the + // "start" symbol in the main executable. + + ModuleSP module_sp(GetModule()); + + if (module_sp) { + SymbolContextList contexts; + SymbolContext context; + if (module_sp->FindSymbolsWithNameAndType(ConstString("start"), + eSymbolTypeCode, contexts)) { + if (contexts.GetContextAtIndex(0, context)) + m_entry_point_address = context.symbol->GetAddress(); + } + } + } + } + + return m_entry_point_address; } -uint32_t -ObjectFileMachO::GetVersion (uint32_t *versions, uint32_t num_versions) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - struct dylib_command load_cmd; - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - uint32_t version_cmd = 0; - uint64_t version = 0; - uint32_t i; - for (i=0; i<m_header.ncmds; ++i) - { - const lldb::offset_t cmd_offset = offset; - if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) - break; +lldb_private::Address ObjectFileMachO::GetHeaderAddress() { + lldb_private::Address header_addr; + SectionList *section_list = GetSectionList(); + if (section_list) { + SectionSP text_segment_sp( + section_list->FindSectionByName(GetSegmentNameTEXT())); + if (text_segment_sp) { + header_addr.SetSection(text_segment_sp); + header_addr.SetOffset(0); + } + } + return header_addr; +} - if (load_cmd.cmd == LC_ID_DYLIB) - { - if (version_cmd == 0) - { - version_cmd = load_cmd.cmd; - if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL) - break; - version = load_cmd.dylib.current_version; - } - break; // Break for now unless there is another more complete version - // number load command in the future. - } - offset = cmd_offset + load_cmd.cmdsize; +uint32_t ObjectFileMachO::GetNumThreadContexts() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (!m_thread_context_offsets_valid) { + m_thread_context_offsets_valid = true; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + FileRangeArray::Entry file_range; + thread_command thread_cmd; + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL) + break; + + if (thread_cmd.cmd == LC_THREAD) { + file_range.SetRangeBase(offset); + file_range.SetByteSize(thread_cmd.cmdsize - 8); + m_thread_context_offsets.Append(file_range); } + offset = cmd_offset + thread_cmd.cmdsize; + } + } + } + return m_thread_context_offsets.GetSize(); +} - if (version_cmd == LC_ID_DYLIB) - { - if (versions != NULL && num_versions > 0) - { - if (num_versions > 0) - versions[0] = (version & 0xFFFF0000ull) >> 16; - if (num_versions > 1) - versions[1] = (version & 0x0000FF00ull) >> 8; - if (num_versions > 2) - versions[2] = (version & 0x000000FFull); - // Fill in an remaining version numbers with invalid values - for (i=3; i<num_versions; ++i) - versions[i] = UINT32_MAX; - } - // The LC_ID_DYLIB load command has a version with 3 version numbers - // in it, so always return 3 - return 3; - } +lldb::RegisterContextSP +ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx, + lldb_private::Thread &thread) { + lldb::RegisterContextSP reg_ctx_sp; + + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (!m_thread_context_offsets_valid) + GetNumThreadContexts(); + + const FileRangeArray::Entry *thread_context_file_range = + m_thread_context_offsets.GetEntryAtIndex(idx); + if (thread_context_file_range) { + + DataExtractor data(m_data, thread_context_file_range->GetRangeBase(), + thread_context_file_range->GetByteSize()); + + switch (m_header.cputype) { + case llvm::MachO::CPU_TYPE_ARM64: + reg_ctx_sp.reset(new RegisterContextDarwin_arm64_Mach(thread, data)); + break; + + case llvm::MachO::CPU_TYPE_ARM: + reg_ctx_sp.reset(new RegisterContextDarwin_arm_Mach(thread, data)); + break; + + case llvm::MachO::CPU_TYPE_I386: + reg_ctx_sp.reset(new RegisterContextDarwin_i386_Mach(thread, data)); + break; + + case llvm::MachO::CPU_TYPE_X86_64: + reg_ctx_sp.reset(new RegisterContextDarwin_x86_64_Mach(thread, data)); + break; + } } - return false; + } + return reg_ctx_sp; } -bool -ObjectFileMachO::GetArchitecture (ArchSpec &arch) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - return GetArchitecture (m_header, m_data, MachHeaderSizeFromMagic(m_header.magic), arch); +ObjectFile::Type ObjectFileMachO::CalculateType() { + switch (m_header.filetype) { + case MH_OBJECT: // 0x1u + if (GetAddressByteSize() == 4) { + // 32 bit kexts are just object files, but they do have a valid + // UUID load command. + UUID uuid; + if (GetUUID(&uuid)) { + // this checking for the UUID load command is not enough + // we could eventually look for the symbol named + // "OSKextGetCurrentIdentifier" as this is required of kexts + if (m_strata == eStrataInvalid) + m_strata = eStrataKernel; + return eTypeSharedLibrary; + } } - return false; + return eTypeObjectFile; + + case MH_EXECUTE: + return eTypeExecutable; // 0x2u + case MH_FVMLIB: + return eTypeSharedLibrary; // 0x3u + case MH_CORE: + return eTypeCoreFile; // 0x4u + case MH_PRELOAD: + return eTypeSharedLibrary; // 0x5u + case MH_DYLIB: + return eTypeSharedLibrary; // 0x6u + case MH_DYLINKER: + return eTypeDynamicLinker; // 0x7u + case MH_BUNDLE: + return eTypeSharedLibrary; // 0x8u + case MH_DYLIB_STUB: + return eTypeStubLibrary; // 0x9u + case MH_DSYM: + return eTypeDebugInfo; // 0xAu + case MH_KEXT_BUNDLE: + return eTypeSharedLibrary; // 0xBu + default: + break; + } + return eTypeUnknown; } -UUID -ObjectFileMachO::GetProcessSharedCacheUUID (Process *process) -{ +ObjectFile::Strata ObjectFileMachO::CalculateStrata() { + switch (m_header.filetype) { + case MH_OBJECT: // 0x1u + { + // 32 bit kexts are just object files, but they do have a valid + // UUID load command. UUID uuid; - if (process && process->GetDynamicLoader()) - { - DynamicLoader *dl = process->GetDynamicLoader(); - addr_t load_address; - LazyBool using_shared_cache; - LazyBool private_shared_cache; - dl->GetSharedCacheInformation (load_address, uuid, using_shared_cache, private_shared_cache); + if (GetUUID(&uuid)) { + // this checking for the UUID load command is not enough + // we could eventually look for the symbol named + // "OSKextGetCurrentIdentifier" as this is required of kexts + if (m_type == eTypeInvalid) + m_type = eTypeSharedLibrary; + + return eStrataKernel; } - return uuid; + } + return eStrataUnknown; + + case MH_EXECUTE: // 0x2u + // Check for the MH_DYLDLINK bit in the flags + if (m_header.flags & MH_DYLDLINK) { + return eStrataUser; + } else { + SectionList *section_list = GetSectionList(); + if (section_list) { + static ConstString g_kld_section_name("__KLD"); + if (section_list->FindSectionByName(g_kld_section_name)) + return eStrataKernel; + } + } + return eStrataRawImage; + + case MH_FVMLIB: + return eStrataUser; // 0x3u + case MH_CORE: + return eStrataUnknown; // 0x4u + case MH_PRELOAD: + return eStrataRawImage; // 0x5u + case MH_DYLIB: + return eStrataUser; // 0x6u + case MH_DYLINKER: + return eStrataUser; // 0x7u + case MH_BUNDLE: + return eStrataUser; // 0x8u + case MH_DYLIB_STUB: + return eStrataUser; // 0x9u + case MH_DSYM: + return eStrataUnknown; // 0xAu + case MH_KEXT_BUNDLE: + return eStrataKernel; // 0xBu + default: + break; + } + return eStrataUnknown; } -UUID -ObjectFileMachO::GetLLDBSharedCacheUUID () -{ - UUID uuid; -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - uint8_t *(*dyld_get_all_image_infos)(void); - dyld_get_all_image_infos = (uint8_t*(*)()) dlsym (RTLD_DEFAULT, "_dyld_get_all_image_infos"); - if (dyld_get_all_image_infos) - { - uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos(); - if (dyld_all_image_infos_address) - { - uint32_t *version = (uint32_t*) dyld_all_image_infos_address; // version <mach-o/dyld_images.h> - if (*version >= 13) - { - uuid_t *sharedCacheUUID_address = 0; - int wordsize = sizeof (uint8_t *); - if (wordsize == 8) - { - sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 160); // sharedCacheUUID <mach-o/dyld_images.h> - } - else - { - sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h> - } - uuid.SetBytes (sharedCacheUUID_address); - } +uint32_t ObjectFileMachO::GetVersion(uint32_t *versions, + uint32_t num_versions) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + struct dylib_command load_cmd; + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + uint32_t version_cmd = 0; + uint64_t version = 0; + uint32_t i; + for (i = 0; i < m_header.ncmds; ++i) { + const lldb::offset_t cmd_offset = offset; + if (m_data.GetU32(&offset, &load_cmd, 2) == NULL) + break; + + if (load_cmd.cmd == LC_ID_DYLIB) { + if (version_cmd == 0) { + version_cmd = load_cmd.cmd; + if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL) + break; + version = load_cmd.dylib.current_version; } + break; // Break for now unless there is another more complete version + // number load command in the future. + } + offset = cmd_offset + load_cmd.cmdsize; } -#endif - return uuid; + + if (version_cmd == LC_ID_DYLIB) { + if (versions != NULL && num_versions > 0) { + if (num_versions > 0) + versions[0] = (version & 0xFFFF0000ull) >> 16; + if (num_versions > 1) + versions[1] = (version & 0x0000FF00ull) >> 8; + if (num_versions > 2) + versions[2] = (version & 0x000000FFull); + // Fill in an remaining version numbers with invalid values + for (i = 3; i < num_versions; ++i) + versions[i] = UINT32_MAX; + } + // The LC_ID_DYLIB load command has a version with 3 version numbers + // in it, so always return 3 + return 3; + } + } + return false; } -uint32_t -ObjectFileMachO::GetMinimumOSVersion (uint32_t *versions, uint32_t num_versions) -{ - if (m_min_os_versions.empty()) - { - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - bool success = false; - for (uint32_t i=0; success == false && i < m_header.ncmds; ++i) - { - const lldb::offset_t load_cmd_offset = offset; - - version_min_command lc; - if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) - break; - if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX - || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS - || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS - || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) - { - if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2)) - { - const uint32_t xxxx = lc.version >> 16; - const uint32_t yy = (lc.version >> 8) & 0xffu; - const uint32_t zz = lc.version & 0xffu; - if (xxxx) - { - m_min_os_versions.push_back(xxxx); - m_min_os_versions.push_back(yy); - m_min_os_versions.push_back(zz); - } - success = true; - } - } - offset = load_cmd_offset + lc.cmdsize; - } - - if (success == false) - { - // Push an invalid value so we don't keep trying to - m_min_os_versions.push_back(UINT32_MAX); +bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + return GetArchitecture(m_header, m_data, + MachHeaderSizeFromMagic(m_header.magic), arch); + } + return false; +} + +UUID ObjectFileMachO::GetProcessSharedCacheUUID(Process *process) { + UUID uuid; + if (process && process->GetDynamicLoader()) { + DynamicLoader *dl = process->GetDynamicLoader(); + addr_t load_address; + LazyBool using_shared_cache; + LazyBool private_shared_cache; + dl->GetSharedCacheInformation(load_address, uuid, using_shared_cache, + private_shared_cache); + } + return uuid; +} + +UUID ObjectFileMachO::GetLLDBSharedCacheUUID() { + UUID uuid; +#if defined(__APPLE__) && \ + (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) + uint8_t *(*dyld_get_all_image_infos)(void); + dyld_get_all_image_infos = + (uint8_t * (*)())dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos"); + if (dyld_get_all_image_infos) { + uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos(); + if (dyld_all_image_infos_address) { + uint32_t *version = (uint32_t *) + dyld_all_image_infos_address; // version <mach-o/dyld_images.h> + if (*version >= 13) { + uuid_t *sharedCacheUUID_address = 0; + int wordsize = sizeof(uint8_t *); + if (wordsize == 8) { + sharedCacheUUID_address = + (uuid_t *)((uint8_t *)dyld_all_image_infos_address + + 160); // sharedCacheUUID <mach-o/dyld_images.h> + } else { + sharedCacheUUID_address = + (uuid_t *)((uint8_t *)dyld_all_image_infos_address + + 84); // sharedCacheUUID <mach-o/dyld_images.h> } + uuid.SetBytes(sharedCacheUUID_address); + } } - - if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX) - { - if (versions != NULL && num_versions > 0) - { - for (size_t i=0; i<num_versions; ++i) - { - if (i < m_min_os_versions.size()) - versions[i] = m_min_os_versions[i]; - else - versions[i] = 0; - } + } +#endif + return uuid; +} + +uint32_t ObjectFileMachO::GetMinimumOSVersion(uint32_t *versions, + uint32_t num_versions) { + if (m_min_os_versions.empty()) { + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + bool success = false; + for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + + version_min_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX || + lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS || + lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS || + lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) { + if (m_data.GetU32(&offset, &lc.version, + (sizeof(lc) / sizeof(uint32_t)) - 2)) { + const uint32_t xxxx = lc.version >> 16; + const uint32_t yy = (lc.version >> 8) & 0xffu; + const uint32_t zz = lc.version & 0xffu; + if (xxxx) { + m_min_os_versions.push_back(xxxx); + m_min_os_versions.push_back(yy); + m_min_os_versions.push_back(zz); + } + success = true; } - return m_min_os_versions.size(); + } + offset = load_cmd_offset + lc.cmdsize; + } + + if (success == false) { + // Push an invalid value so we don't keep trying to + m_min_os_versions.push_back(UINT32_MAX); } - // Call the superclasses version that will empty out the data - return ObjectFile::GetMinimumOSVersion (versions, num_versions); + } + + if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX) { + if (versions != NULL && num_versions > 0) { + for (size_t i = 0; i < num_versions; ++i) { + if (i < m_min_os_versions.size()) + versions[i] = m_min_os_versions[i]; + else + versions[i] = 0; + } + } + return m_min_os_versions.size(); + } + // Call the superclasses version that will empty out the data + return ObjectFile::GetMinimumOSVersion(versions, num_versions); } -uint32_t -ObjectFileMachO::GetSDKVersion(uint32_t *versions, uint32_t num_versions) -{ - if (m_sdk_versions.empty()) - { - lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - bool success = false; - for (uint32_t i=0; success == false && i < m_header.ncmds; ++i) - { - const lldb::offset_t load_cmd_offset = offset; - - version_min_command lc; - if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) - break; - if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX - || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS - || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS - || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) - { - if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2)) - { - const uint32_t xxxx = lc.sdk >> 16; - const uint32_t yy = (lc.sdk >> 8) & 0xffu; - const uint32_t zz = lc.sdk & 0xffu; - if (xxxx) - { - m_sdk_versions.push_back(xxxx); - m_sdk_versions.push_back(yy); - m_sdk_versions.push_back(zz); - } - success = true; - } - } - offset = load_cmd_offset + lc.cmdsize; - } - - if (success == false) - { - // Push an invalid value so we don't keep trying to - m_sdk_versions.push_back(UINT32_MAX); +uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions, + uint32_t num_versions) { + if (m_sdk_versions.empty()) { + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + bool success = false; + for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) { + const lldb::offset_t load_cmd_offset = offset; + + version_min_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL) + break; + if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX || + lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS || + lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS || + lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) { + if (m_data.GetU32(&offset, &lc.version, + (sizeof(lc) / sizeof(uint32_t)) - 2)) { + const uint32_t xxxx = lc.sdk >> 16; + const uint32_t yy = (lc.sdk >> 8) & 0xffu; + const uint32_t zz = lc.sdk & 0xffu; + if (xxxx) { + m_sdk_versions.push_back(xxxx); + m_sdk_versions.push_back(yy); + m_sdk_versions.push_back(zz); + } + success = true; } + } + offset = load_cmd_offset + lc.cmdsize; } - - if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX) - { - if (versions != NULL && num_versions > 0) - { - for (size_t i=0; i<num_versions; ++i) - { - if (i < m_sdk_versions.size()) - versions[i] = m_sdk_versions[i]; - else - versions[i] = 0; - } - } - return m_sdk_versions.size(); + + if (success == false) { + // Push an invalid value so we don't keep trying to + m_sdk_versions.push_back(UINT32_MAX); + } + } + + if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX) { + if (versions != NULL && num_versions > 0) { + for (size_t i = 0; i < num_versions; ++i) { + if (i < m_sdk_versions.size()) + versions[i] = m_sdk_versions[i]; + else + versions[i] = 0; + } } - // Call the superclasses version that will empty out the data - return ObjectFile::GetSDKVersion (versions, num_versions); + return m_sdk_versions.size(); + } + // Call the superclasses version that will empty out the data + return ObjectFile::GetSDKVersion(versions, num_versions); } -bool -ObjectFileMachO::GetIsDynamicLinkEditor() -{ - return m_header.filetype == llvm::MachO::MH_DYLINKER; +bool ObjectFileMachO::GetIsDynamicLinkEditor() { + return m_header.filetype == llvm::MachO::MH_DYLINKER; } -bool -ObjectFileMachO::AllowAssemblyEmulationUnwindPlans () -{ - return m_allow_assembly_emulation_unwind_plans; +bool ObjectFileMachO::AllowAssemblyEmulationUnwindPlans() { + return m_allow_assembly_emulation_unwind_plans; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -ObjectFileMachO::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ObjectFileMachO::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ObjectFileMachO::GetPluginVersion() -{ - return 1; -} +uint32_t ObjectFileMachO::GetPluginVersion() { return 1; } -Section * -ObjectFileMachO::GetMachHeaderSection() -{ - // Find the first address of the mach header which is the first non-zero - // file sized section whose file offset is zero. This is the base file address - // of the mach-o file which can be subtracted from the vmaddr of the other - // segments found in memory and added to the load address - ModuleSP module_sp = GetModule(); - if (module_sp) - { - SectionList *section_list = GetSectionList (); - if (section_list) - { - lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS; - const size_t num_sections = section_list->GetSize(); - - for (size_t sect_idx = 0; - sect_idx < num_sections && mach_base_file_addr == LLDB_INVALID_ADDRESS; - ++sect_idx) - { - Section *section = section_list->GetSectionAtIndex (sect_idx).get(); - if (section && - section->GetFileSize() > 0 && - section->GetFileOffset() == 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) - { - return section; - } - } +Section *ObjectFileMachO::GetMachHeaderSection() { + // Find the first address of the mach header which is the first non-zero + // file sized section whose file offset is zero. This is the base file address + // of the mach-o file which can be subtracted from the vmaddr of the other + // segments found in memory and added to the load address + ModuleSP module_sp = GetModule(); + if (module_sp) { + SectionList *section_list = GetSectionList(); + if (section_list) { + lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS; + const size_t num_sections = section_list->GetSize(); + + for (size_t sect_idx = 0; sect_idx < num_sections && + mach_base_file_addr == LLDB_INVALID_ADDRESS; + ++sect_idx) { + Section *section = section_list->GetSectionAtIndex(sect_idx).get(); + if (section && section->GetFileSize() > 0 && + section->GetFileOffset() == 0 && + section->IsThreadSpecific() == false && + module_sp.get() == section->GetModule().get()) { + return section; } + } } - return nullptr; + } + return nullptr; } -lldb::addr_t -ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage(lldb::addr_t mach_header_load_address, const Section *mach_header_section, const Section *section) -{ - ModuleSP module_sp = GetModule(); - if (module_sp && mach_header_section && section && mach_header_load_address != LLDB_INVALID_ADDRESS) - { - lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress(); - if (mach_header_file_addr != LLDB_INVALID_ADDRESS) - { - if (section && - section->GetFileSize() > 0 && - section->IsThreadSpecific() == false && - module_sp.get() == section->GetModule().get()) - { - // Ignore __LINKEDIT and __DWARF segments - if (section->GetName() == GetSegmentNameLINKEDIT()) - { - // Only map __LINKEDIT if we have an in memory image and this isn't - // a kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - return LLDB_INVALID_ADDRESS; - } - return section->GetFileAddress() - mach_header_file_addr + mach_header_load_address; - } +lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage( + lldb::addr_t mach_header_load_address, const Section *mach_header_section, + const Section *section) { + ModuleSP module_sp = GetModule(); + if (module_sp && mach_header_section && section && + mach_header_load_address != LLDB_INVALID_ADDRESS) { + lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress(); + if (mach_header_file_addr != LLDB_INVALID_ADDRESS) { + if (section && section->GetFileSize() > 0 && + section->IsThreadSpecific() == false && + module_sp.get() == section->GetModule().get()) { + // Ignore __LINKEDIT and __DWARF segments + if (section->GetName() == GetSegmentNameLINKEDIT()) { + // Only map __LINKEDIT if we have an in memory image and this isn't + // a kernel binary like a kext or mach_kernel. + const bool is_memory_image = (bool)m_process_wp.lock(); + const Strata strata = GetStrata(); + if (is_memory_image == false || strata == eStrataKernel) + return LLDB_INVALID_ADDRESS; } + return section->GetFileAddress() - mach_header_file_addr + + mach_header_load_address; + } } - return LLDB_INVALID_ADDRESS; + } + return LLDB_INVALID_ADDRESS; } -bool -ObjectFileMachO::SetLoadAddress (Target &target, - lldb::addr_t value, - bool value_is_offset) -{ - ModuleSP module_sp = GetModule(); - if (module_sp) - { - size_t num_loaded_sections = 0; - SectionList *section_list = GetSectionList (); - if (section_list) - { - const size_t num_sections = section_list->GetSize(); - - if (value_is_offset) - { - // "value" is an offset to apply to each top level segment - for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) - { - // Iterate through the object file sections to find all - // of the sections that size on disk (to avoid __PAGEZERO) - // and load them - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - if (section_sp && - section_sp->GetFileSize() > 0 && - section_sp->IsThreadSpecific() == false && - module_sp.get() == section_sp->GetModule().get()) - { - // Ignore __LINKEDIT and __DWARF segments - if (section_sp->GetName() == GetSegmentNameLINKEDIT()) - { - // Only map __LINKEDIT if we have an in memory image and this isn't - // a kernel binary like a kext or mach_kernel. - const bool is_memory_image = (bool)m_process_wp.lock(); - const Strata strata = GetStrata(); - if (is_memory_image == false || strata == eStrataKernel) - continue; - } - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) - ++num_loaded_sections; - } - } +bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, + bool value_is_offset) { + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + const size_t num_sections = section_list->GetSize(); + + if (value_is_offset) { + // "value" is an offset to apply to each top level segment + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + // Iterate through the object file sections to find all + // of the sections that size on disk (to avoid __PAGEZERO) + // and load them + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && section_sp->GetFileSize() > 0 && + section_sp->IsThreadSpecific() == false && + module_sp.get() == section_sp->GetModule().get()) { + // Ignore __LINKEDIT and __DWARF segments + if (section_sp->GetName() == GetSegmentNameLINKEDIT()) { + // Only map __LINKEDIT if we have an in memory image and this + // isn't + // a kernel binary like a kext or mach_kernel. + const bool is_memory_image = (bool)m_process_wp.lock(); + const Strata strata = GetStrata(); + if (is_memory_image == false || strata == eStrataKernel) + continue; } - else - { - // "value" is the new base address of the mach_header, adjust each - // section accordingly - - Section *mach_header_section = GetMachHeaderSection(); - if (mach_header_section) - { - for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) - { - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - - lldb::addr_t section_load_addr = CalculateSectionLoadAddressForMemoryImage(value, mach_header_section, section_sp.get()); - if (section_load_addr != LLDB_INVALID_ADDRESS) - { - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_load_addr)) - ++num_loaded_sections; - } - } - } + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + } else { + // "value" is the new base address of the mach_header, adjust each + // section accordingly + + Section *mach_header_section = GetMachHeaderSection(); + if (mach_header_section) { + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + + lldb::addr_t section_load_addr = + CalculateSectionLoadAddressForMemoryImage( + value, mach_header_section, section_sp.get()); + if (section_load_addr != LLDB_INVALID_ADDRESS) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_load_addr)) + ++num_loaded_sections; } + } } - return num_loaded_sections > 0; + } } - return false; + return num_loaded_sections > 0; + } + return false; } -bool -ObjectFileMachO::SaveCore (const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - Error &error) -{ - if (process_sp) - { - Target &target = process_sp->GetTarget(); - const ArchSpec target_arch = target.GetArchitecture(); - const llvm::Triple &target_triple = target_arch.GetTriple(); - if (target_triple.getVendor() == llvm::Triple::Apple && - (target_triple.getOS() == llvm::Triple::MacOSX - || target_triple.getOS() == llvm::Triple::IOS - || target_triple.getOS() == llvm::Triple::WatchOS - || target_triple.getOS() == llvm::Triple::TvOS)) - { - bool make_core = false; - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::thumb: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - make_core = true; - break; - default: - error.SetErrorStringWithFormat ("unsupported core architecture: %s", target_triple.str().c_str()); - break; +bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, + const FileSpec &outfile, Error &error) { + if (process_sp) { + Target &target = process_sp->GetTarget(); + const ArchSpec target_arch = target.GetArchitecture(); + const llvm::Triple &target_triple = target_arch.GetTriple(); + if (target_triple.getVendor() == llvm::Triple::Apple && + (target_triple.getOS() == llvm::Triple::MacOSX || + target_triple.getOS() == llvm::Triple::IOS || + target_triple.getOS() == llvm::Triple::WatchOS || + target_triple.getOS() == llvm::Triple::TvOS)) { + bool make_core = false; + switch (target_arch.GetMachine()) { + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::thumb: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + make_core = true; + break; + default: + error.SetErrorStringWithFormat("unsupported core architecture: %s", + target_triple.str().c_str()); + break; + } + + if (make_core) { + std::vector<segment_command_64> segment_load_commands; + // uint32_t range_info_idx = 0; + MemoryRegionInfo range_info; + Error range_error = process_sp->GetMemoryRegionInfo(0, range_info); + const uint32_t addr_byte_size = target_arch.GetAddressByteSize(); + const ByteOrder byte_order = target_arch.GetByteOrder(); + if (range_error.Success()) { + while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) { + const addr_t addr = range_info.GetRange().GetRangeBase(); + const addr_t size = range_info.GetRange().GetByteSize(); + + if (size == 0) + break; + + // Calculate correct protections + uint32_t prot = 0; + if (range_info.GetReadable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_READ; + if (range_info.GetWritable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_WRITE; + if (range_info.GetExecutable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_EXECUTE; + + // printf ("[%3u] [0x%16.16" PRIx64 " - + // 0x%16.16" PRIx64 ") %c%c%c\n", + // range_info_idx, + // addr, + // size, + // (prot & VM_PROT_READ ) ? 'r' : + // '-', + // (prot & VM_PROT_WRITE ) ? 'w' : + // '-', + // (prot & VM_PROT_EXECUTE) ? 'x' : + // '-'); + + if (prot != 0) { + uint32_t cmd_type = LC_SEGMENT_64; + uint32_t segment_size = sizeof(segment_command_64); + if (addr_byte_size == 4) { + cmd_type = LC_SEGMENT; + segment_size = sizeof(segment_command); + } + segment_command_64 segment = { + cmd_type, // uint32_t cmd; + segment_size, // uint32_t cmdsize; + {0}, // char segname[16]; + addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O + size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O + 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O + size, // uint64_t filesize; // uint32_t for 32-bit Mach-O + prot, // uint32_t maxprot; + prot, // uint32_t initprot; + 0, // uint32_t nsects; + 0}; // uint32_t flags; + segment_load_commands.push_back(segment); + } else { + // No protections and a size of 1 used to be returned from old + // debugservers when we asked about a region that was past the + // last memory region and it indicates the end... + if (size == 1) + break; } - - if (make_core) - { - std::vector<segment_command_64> segment_load_commands; -// uint32_t range_info_idx = 0; - MemoryRegionInfo range_info; - Error range_error = process_sp->GetMemoryRegionInfo(0, range_info); - const uint32_t addr_byte_size = target_arch.GetAddressByteSize(); - const ByteOrder byte_order = target_arch.GetByteOrder(); - if (range_error.Success()) - { - while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) - { - const addr_t addr = range_info.GetRange().GetRangeBase(); - const addr_t size = range_info.GetRange().GetByteSize(); - if (size == 0) - break; - - // Calculate correct protections - uint32_t prot = 0; - if (range_info.GetReadable() == MemoryRegionInfo::eYes) - prot |= VM_PROT_READ; - if (range_info.GetWritable() == MemoryRegionInfo::eYes) - prot |= VM_PROT_WRITE; - if (range_info.GetExecutable() == MemoryRegionInfo::eYes) - prot |= VM_PROT_EXECUTE; - -// printf ("[%3u] [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") %c%c%c\n", -// range_info_idx, -// addr, -// size, -// (prot & VM_PROT_READ ) ? 'r' : '-', -// (prot & VM_PROT_WRITE ) ? 'w' : '-', -// (prot & VM_PROT_EXECUTE) ? 'x' : '-'); - - if (prot != 0) - { - uint32_t cmd_type = LC_SEGMENT_64; - uint32_t segment_size = sizeof (segment_command_64); - if (addr_byte_size == 4) - { - cmd_type = LC_SEGMENT; - segment_size = sizeof (segment_command); - } - segment_command_64 segment = { - cmd_type, // uint32_t cmd; - segment_size, // uint32_t cmdsize; - {0}, // char segname[16]; - addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O - size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O - 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O - size, // uint64_t filesize; // uint32_t for 32-bit Mach-O - prot, // uint32_t maxprot; - prot, // uint32_t initprot; - 0, // uint32_t nsects; - 0 }; // uint32_t flags; - segment_load_commands.push_back(segment); - } - else - { - // No protections and a size of 1 used to be returned from old - // debugservers when we asked about a region that was past the - // last memory region and it indicates the end... - if (size == 1) - break; - } - - range_error = process_sp->GetMemoryRegionInfo(range_info.GetRange().GetRangeEnd(), range_info); - if (range_error.Fail()) - break; - } - - StreamString buffer (Stream::eBinary, - addr_byte_size, - byte_order); + range_error = process_sp->GetMemoryRegionInfo( + range_info.GetRange().GetRangeEnd(), range_info); + if (range_error.Fail()) + break; + } + + StreamString buffer(Stream::eBinary, addr_byte_size, byte_order); + + mach_header_64 mach_header; + if (addr_byte_size == 8) { + mach_header.magic = MH_MAGIC_64; + } else { + mach_header.magic = MH_MAGIC; + } + mach_header.cputype = target_arch.GetMachOCPUType(); + mach_header.cpusubtype = target_arch.GetMachOCPUSubType(); + mach_header.filetype = MH_CORE; + mach_header.ncmds = segment_load_commands.size(); + mach_header.flags = 0; + mach_header.reserved = 0; + ThreadList &thread_list = process_sp->GetThreadList(); + const uint32_t num_threads = thread_list.GetSize(); + + // Make an array of LC_THREAD data items. Each one contains + // the contents of the LC_THREAD load command. The data doesn't + // contain the load command + load command size, we will + // add the load command and load command size as we emit the data. + std::vector<StreamString> LC_THREAD_datas(num_threads); + for (auto &LC_THREAD_data : LC_THREAD_datas) { + LC_THREAD_data.GetFlags().Set(Stream::eBinary); + LC_THREAD_data.SetAddressByteSize(addr_byte_size); + LC_THREAD_data.SetByteOrder(byte_order); + } + for (uint32_t thread_idx = 0; thread_idx < num_threads; + ++thread_idx) { + ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); + if (thread_sp) { + switch (mach_header.cputype) { + case llvm::MachO::CPU_TYPE_ARM64: + RegisterContextDarwin_arm64_Mach::Create_LC_THREAD( + thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; - mach_header_64 mach_header; - if (addr_byte_size == 8) - { - mach_header.magic = MH_MAGIC_64; - } - else - { - mach_header.magic = MH_MAGIC; - } - mach_header.cputype = target_arch.GetMachOCPUType(); - mach_header.cpusubtype = target_arch.GetMachOCPUSubType(); - mach_header.filetype = MH_CORE; - mach_header.ncmds = segment_load_commands.size(); - mach_header.flags = 0; - mach_header.reserved = 0; - ThreadList &thread_list = process_sp->GetThreadList(); - const uint32_t num_threads = thread_list.GetSize(); - - // Make an array of LC_THREAD data items. Each one contains - // the contents of the LC_THREAD load command. The data doesn't - // contain the load command + load command size, we will - // add the load command and load command size as we emit the data. - std::vector<StreamString> LC_THREAD_datas(num_threads); - for (auto &LC_THREAD_data : LC_THREAD_datas) - { - LC_THREAD_data.GetFlags().Set(Stream::eBinary); - LC_THREAD_data.SetAddressByteSize(addr_byte_size); - LC_THREAD_data.SetByteOrder(byte_order); - } - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) - { - ThreadSP thread_sp (thread_list.GetThreadAtIndex(thread_idx)); - if (thread_sp) - { - switch (mach_header.cputype) - { - case llvm::MachO::CPU_TYPE_ARM64: - RegisterContextDarwin_arm64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]); - break; - - case llvm::MachO::CPU_TYPE_ARM: - RegisterContextDarwin_arm_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]); - break; - - case llvm::MachO::CPU_TYPE_I386: - RegisterContextDarwin_i386_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]); - break; - - case llvm::MachO::CPU_TYPE_X86_64: - RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]); - break; - } - - } - } - - // The size of the load command is the size of the segments... - if (addr_byte_size == 8) - { - mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command_64); - } - else - { - mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command); - } - - // and the size of all LC_THREAD load command - for (const auto &LC_THREAD_data : LC_THREAD_datas) - { - ++mach_header.ncmds; - mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize(); - } + case llvm::MachO::CPU_TYPE_ARM: + RegisterContextDarwin_arm_Mach::Create_LC_THREAD( + thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; - printf ("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", - mach_header.magic, - mach_header.cputype, - mach_header.cpusubtype, - mach_header.filetype, - mach_header.ncmds, - mach_header.sizeofcmds, - mach_header.flags, - mach_header.reserved); - - // Write the mach header - buffer.PutHex32(mach_header.magic); - buffer.PutHex32(mach_header.cputype); - buffer.PutHex32(mach_header.cpusubtype); - buffer.PutHex32(mach_header.filetype); - buffer.PutHex32(mach_header.ncmds); - buffer.PutHex32(mach_header.sizeofcmds); - buffer.PutHex32(mach_header.flags); - if (addr_byte_size == 8) - { - buffer.PutHex32(mach_header.reserved); - } - - // Skip the mach header and all load commands and align to the next - // 0x1000 byte boundary - addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds; - if (file_offset & 0x00000fff) - { - file_offset += 0x00001000ull; - file_offset &= (~0x00001000ull + 1); - } - - for (auto &segment : segment_load_commands) - { - segment.fileoff = file_offset; - file_offset += segment.filesize; - } - - // Write out all of the LC_THREAD load commands - for (const auto &LC_THREAD_data : LC_THREAD_datas) - { - const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize(); - buffer.PutHex32(LC_THREAD); - buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data - buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size); - } + case llvm::MachO::CPU_TYPE_I386: + RegisterContextDarwin_i386_Mach::Create_LC_THREAD( + thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; - // Write out all of the segment load commands - for (const auto &segment : segment_load_commands) - { - printf ("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n", - segment.cmd, - segment.cmdsize, - segment.vmaddr, - segment.vmaddr + segment.vmsize, - segment.fileoff, - segment.filesize, - segment.maxprot, - segment.initprot, - segment.nsects, - segment.flags); - - buffer.PutHex32(segment.cmd); - buffer.PutHex32(segment.cmdsize); - buffer.PutRawBytes(segment.segname, sizeof(segment.segname)); - if (addr_byte_size == 8) - { - buffer.PutHex64(segment.vmaddr); - buffer.PutHex64(segment.vmsize); - buffer.PutHex64(segment.fileoff); - buffer.PutHex64(segment.filesize); - } - else - { - buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr)); - buffer.PutHex32(static_cast<uint32_t>(segment.vmsize)); - buffer.PutHex32(static_cast<uint32_t>(segment.fileoff)); - buffer.PutHex32(static_cast<uint32_t>(segment.filesize)); - } - buffer.PutHex32(segment.maxprot); - buffer.PutHex32(segment.initprot); - buffer.PutHex32(segment.nsects); - buffer.PutHex32(segment.flags); - } - - File core_file; - std::string core_file_path(outfile.GetPath()); - error = core_file.Open(core_file_path.c_str(), - File::eOpenOptionWrite | - File::eOpenOptionTruncate | - File::eOpenOptionCanCreate); - if (error.Success()) - { - // Read 1 page at a time - uint8_t bytes[0x1000]; - // Write the mach header and load commands out to the core file - size_t bytes_written = buffer.GetString().size(); - error = core_file.Write(buffer.GetString().data(), bytes_written); - if (error.Success()) - { - // Now write the file data for all memory segments in the process - for (const auto &segment : segment_load_commands) - { - if (core_file.SeekFromStart(segment.fileoff) == -1) - { - error.SetErrorStringWithFormat("unable to seek to offset 0x%" PRIx64 " in '%s'", segment.fileoff, core_file_path.c_str()); - break; - } - - printf ("Saving %" PRId64 " bytes of data for memory region at 0x%" PRIx64 "\n", segment.vmsize, segment.vmaddr); - addr_t bytes_left = segment.vmsize; - addr_t addr = segment.vmaddr; - Error memory_read_error; - while (bytes_left > 0 && error.Success()) - { - const size_t bytes_to_read = bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left; - const size_t bytes_read = process_sp->ReadMemory(addr, bytes, bytes_to_read, memory_read_error); - if (bytes_read == bytes_to_read) - { - size_t bytes_written = bytes_read; - error = core_file.Write(bytes, bytes_written); - bytes_left -= bytes_read; - addr += bytes_read; - } - else - { - // Some pages within regions are not readable, those - // should be zero filled - memset (bytes, 0, bytes_to_read); - size_t bytes_written = bytes_to_read; - error = core_file.Write(bytes, bytes_written); - bytes_left -= bytes_to_read; - addr += bytes_to_read; - } - } - } - } - } + case llvm::MachO::CPU_TYPE_X86_64: + RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD( + thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; + } + } + } + + // The size of the load command is the size of the segments... + if (addr_byte_size == 8) { + mach_header.sizeofcmds = segment_load_commands.size() * + sizeof(struct segment_command_64); + } else { + mach_header.sizeofcmds = + segment_load_commands.size() * sizeof(struct segment_command); + } + + // and the size of all LC_THREAD load command + for (const auto &LC_THREAD_data : LC_THREAD_datas) { + ++mach_header.ncmds; + mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize(); + } + + printf("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x " + "0x%8.8x 0x%8.8x\n", + mach_header.magic, mach_header.cputype, mach_header.cpusubtype, + mach_header.filetype, mach_header.ncmds, + mach_header.sizeofcmds, mach_header.flags, + mach_header.reserved); + + // Write the mach header + buffer.PutHex32(mach_header.magic); + buffer.PutHex32(mach_header.cputype); + buffer.PutHex32(mach_header.cpusubtype); + buffer.PutHex32(mach_header.filetype); + buffer.PutHex32(mach_header.ncmds); + buffer.PutHex32(mach_header.sizeofcmds); + buffer.PutHex32(mach_header.flags); + if (addr_byte_size == 8) { + buffer.PutHex32(mach_header.reserved); + } + + // Skip the mach header and all load commands and align to the next + // 0x1000 byte boundary + addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds; + if (file_offset & 0x00000fff) { + file_offset += 0x00001000ull; + file_offset &= (~0x00001000ull + 1); + } + + for (auto &segment : segment_load_commands) { + segment.fileoff = file_offset; + file_offset += segment.filesize; + } + + // Write out all of the LC_THREAD load commands + for (const auto &LC_THREAD_data : LC_THREAD_datas) { + const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize(); + buffer.PutHex32(LC_THREAD); + buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data + buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size); + } + + // Write out all of the segment load commands + for (const auto &segment : segment_load_commands) { + printf("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 + ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 + ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n", + segment.cmd, segment.cmdsize, segment.vmaddr, + segment.vmaddr + segment.vmsize, segment.fileoff, + segment.filesize, segment.maxprot, segment.initprot, + segment.nsects, segment.flags); + + buffer.PutHex32(segment.cmd); + buffer.PutHex32(segment.cmdsize); + buffer.PutRawBytes(segment.segname, sizeof(segment.segname)); + if (addr_byte_size == 8) { + buffer.PutHex64(segment.vmaddr); + buffer.PutHex64(segment.vmsize); + buffer.PutHex64(segment.fileoff); + buffer.PutHex64(segment.filesize); + } else { + buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr)); + buffer.PutHex32(static_cast<uint32_t>(segment.vmsize)); + buffer.PutHex32(static_cast<uint32_t>(segment.fileoff)); + buffer.PutHex32(static_cast<uint32_t>(segment.filesize)); + } + buffer.PutHex32(segment.maxprot); + buffer.PutHex32(segment.initprot); + buffer.PutHex32(segment.nsects); + buffer.PutHex32(segment.flags); + } + + File core_file; + std::string core_file_path(outfile.GetPath()); + error = core_file.Open(core_file_path.c_str(), + File::eOpenOptionWrite | + File::eOpenOptionTruncate | + File::eOpenOptionCanCreate); + if (error.Success()) { + // Read 1 page at a time + uint8_t bytes[0x1000]; + // Write the mach header and load commands out to the core file + size_t bytes_written = buffer.GetString().size(); + error = core_file.Write(buffer.GetString().data(), bytes_written); + if (error.Success()) { + // Now write the file data for all memory segments in the process + for (const auto &segment : segment_load_commands) { + if (core_file.SeekFromStart(segment.fileoff) == -1) { + error.SetErrorStringWithFormat( + "unable to seek to offset 0x%" PRIx64 " in '%s'", + segment.fileoff, core_file_path.c_str()); + break; } - else - { - error.SetErrorString("process doesn't support getting memory region info"); + + printf("Saving %" PRId64 + " bytes of data for memory region at 0x%" PRIx64 "\n", + segment.vmsize, segment.vmaddr); + addr_t bytes_left = segment.vmsize; + addr_t addr = segment.vmaddr; + Error memory_read_error; + while (bytes_left > 0 && error.Success()) { + const size_t bytes_to_read = + bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left; + const size_t bytes_read = process_sp->ReadMemory( + addr, bytes, bytes_to_read, memory_read_error); + if (bytes_read == bytes_to_read) { + size_t bytes_written = bytes_read; + error = core_file.Write(bytes, bytes_written); + bytes_left -= bytes_read; + addr += bytes_read; + } else { + // Some pages within regions are not readable, those + // should be zero filled + memset(bytes, 0, bytes_to_read); + size_t bytes_written = bytes_to_read; + error = core_file.Write(bytes, bytes_written); + bytes_left -= bytes_to_read; + addr += bytes_to_read; + } } + } } - return true; // This is the right plug to handle saving core files for this process + } + } else { + error.SetErrorString( + "process doesn't support getting memory region info"); } + } + return true; // This is the right plug to handle saving core files for + // this process } - return false; + } + return false; } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 251a0865e78..cac176fe2ca 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -14,242 +14,192 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Utility/SafeMachO.h" #include "lldb/Core/Address.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/RangeMap.h" #include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/SafeMachO.h" //---------------------------------------------------------------------- // This class needs to be hidden as eventually belongs in a plugin that // will export the ObjectFile protocol //---------------------------------------------------------------------- -class ObjectFileMachO : - public lldb_private::ObjectFile -{ +class ObjectFileMachO : public lldb_private::ObjectFile { public: - ObjectFileMachO(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t offset, - lldb::offset_t length); - - ObjectFileMachO(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - ~ObjectFileMachO() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - static lldb_private::ObjectFile * - CreateInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length); - - static lldb_private::ObjectFile * - CreateMemoryInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - static size_t - GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs); - - static bool - SaveCore (const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb_private::Error &error); - - static bool - MagicBytesMatch (lldb::DataBufferSP& data_sp, - lldb::addr_t offset, - lldb::addr_t length); - - //------------------------------------------------------------------ - // Member Functions - //------------------------------------------------------------------ - bool - ParseHeader() override; - - bool - SetLoadAddress(lldb_private::Target &target, - lldb::addr_t value, - bool value_is_offset) override; - - lldb::ByteOrder - GetByteOrder() const override; - - bool - IsExecutable() const override; - - uint32_t - GetAddressByteSize() const override; - - lldb::AddressClass - GetAddressClass(lldb::addr_t file_addr) override; - - lldb_private::Symtab * - GetSymtab() override; - - bool - IsStripped() override; - - void - CreateSections(lldb_private::SectionList &unified_section_list) override; - - void - Dump(lldb_private::Stream *s) override; - - bool - GetArchitecture(lldb_private::ArchSpec &arch) override; - - bool - GetUUID(lldb_private::UUID* uuid) override; - - uint32_t - GetDependentModules(lldb_private::FileSpecList& files) override; - - lldb_private::FileSpecList - GetReExportedLibraries() override - { - return m_reexported_dylibs; - } - - lldb_private::Address - GetEntryPointAddress() override; - - lldb_private::Address - GetHeaderAddress() override; - - uint32_t - GetNumThreadContexts() override; - - lldb::RegisterContextSP - GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; - - ObjectFile::Type - CalculateType() override; - - ObjectFile::Strata - CalculateStrata() override; - - uint32_t - GetVersion(uint32_t *versions, uint32_t num_versions) override; - - uint32_t - GetMinimumOSVersion(uint32_t *versions, uint32_t num_versions) override; - - uint32_t - GetSDKVersion(uint32_t *versions, uint32_t num_versions) override; - - bool - GetIsDynamicLinkEditor() override; - - static bool - ParseHeader (lldb_private::DataExtractor &data, - lldb::offset_t *data_offset_ptr, - llvm::MachO::mach_header &header); - - bool - AllowAssemblyEmulationUnwindPlans () override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; + ObjectFileMachO(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, lldb::offset_t offset, + lldb::offset_t length); + + ObjectFileMachO(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + ~ObjectFileMachO() override = default; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static lldb_private::ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool SaveCore(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, + lldb::addr_t length); + + //------------------------------------------------------------------ + // Member Functions + //------------------------------------------------------------------ + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + lldb::AddressClass GetAddressClass(lldb::addr_t file_addr) override; + + lldb_private::Symtab *GetSymtab() override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + bool GetArchitecture(lldb_private::ArchSpec &arch) override; + + bool GetUUID(lldb_private::UUID *uuid) override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + lldb_private::FileSpecList GetReExportedLibraries() override { + return m_reexported_dylibs; + } + + lldb_private::Address GetEntryPointAddress() override; + + lldb_private::Address GetHeaderAddress() override; + + uint32_t GetNumThreadContexts() override; + + lldb::RegisterContextSP + GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + uint32_t GetVersion(uint32_t *versions, uint32_t num_versions) override; + + uint32_t GetMinimumOSVersion(uint32_t *versions, + uint32_t num_versions) override; + + uint32_t GetSDKVersion(uint32_t *versions, uint32_t num_versions) override; + + bool GetIsDynamicLinkEditor() override; + + static bool ParseHeader(lldb_private::DataExtractor &data, + lldb::offset_t *data_offset_ptr, + llvm::MachO::mach_header &header); + + bool AllowAssemblyEmulationUnwindPlans() override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; protected: - static bool - GetUUID (const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, // Offset to the first load command - lldb_private::UUID& uuid); - - static bool - GetArchitecture (const llvm::MachO::mach_header &header, - const lldb_private::DataExtractor &data, - lldb::offset_t lc_offset, - lldb_private::ArchSpec &arch); - - // Intended for same-host arm device debugging where lldb needs to - // detect libraries in the shared cache and augment the nlist entries - // with an on-disk dyld_shared_cache file. The process will record - // the shared cache UUID so the on-disk cache can be matched or rejected - // correctly. - lldb_private::UUID - GetProcessSharedCacheUUID (lldb_private::Process *); - - // Intended for same-host arm device debugging where lldb will read - // shared cache libraries out of its own memory instead of the remote - // process' memory as an optimization. If lldb's shared cache UUID - // does not match the process' shared cache UUID, this optimization - // should not be used. - lldb_private::UUID - GetLLDBSharedCacheUUID (); - - lldb_private::Section * - GetMachHeaderSection(); - - lldb::addr_t - CalculateSectionLoadAddressForMemoryImage(lldb::addr_t mach_header_load_address, - const lldb_private::Section *mach_header_section, - const lldb_private::Section *section); - - lldb_private::UUID - GetSharedCacheUUID (lldb_private::FileSpec dyld_shared_cache, const lldb::ByteOrder byte_order, const uint32_t addr_byte_size); - - size_t - ParseSymtab(); - - llvm::MachO::mach_header m_header; - static const lldb_private::ConstString &GetSegmentNameTEXT(); - static const lldb_private::ConstString &GetSegmentNameDATA(); - static const lldb_private::ConstString &GetSegmentNameDATA_DIRTY(); - static const lldb_private::ConstString &GetSegmentNameDATA_CONST(); - static const lldb_private::ConstString &GetSegmentNameOBJC(); - static const lldb_private::ConstString &GetSegmentNameLINKEDIT(); - static const lldb_private::ConstString &GetSectionNameEHFrame(); - - llvm::MachO::dysymtab_command m_dysymtab; - std::vector<llvm::MachO::segment_command_64> m_mach_segments; - std::vector<llvm::MachO::section_64> m_mach_sections; - std::vector<uint32_t> m_min_os_versions; - std::vector<uint32_t> m_sdk_versions; - typedef lldb_private::RangeVector<uint32_t, uint32_t> FileRangeArray; - lldb_private::Address m_entry_point_address; - FileRangeArray m_thread_context_offsets; - bool m_thread_context_offsets_valid; - lldb_private::FileSpecList m_reexported_dylibs; - bool m_allow_assembly_emulation_unwind_plans; + static bool + GetUUID(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset, // Offset to the first load command + lldb_private::UUID &uuid); + + static bool GetArchitecture(const llvm::MachO::mach_header &header, + const lldb_private::DataExtractor &data, + lldb::offset_t lc_offset, + lldb_private::ArchSpec &arch); + + // Intended for same-host arm device debugging where lldb needs to + // detect libraries in the shared cache and augment the nlist entries + // with an on-disk dyld_shared_cache file. The process will record + // the shared cache UUID so the on-disk cache can be matched or rejected + // correctly. + lldb_private::UUID GetProcessSharedCacheUUID(lldb_private::Process *); + + // Intended for same-host arm device debugging where lldb will read + // shared cache libraries out of its own memory instead of the remote + // process' memory as an optimization. If lldb's shared cache UUID + // does not match the process' shared cache UUID, this optimization + // should not be used. + lldb_private::UUID GetLLDBSharedCacheUUID(); + + lldb_private::Section *GetMachHeaderSection(); + + lldb::addr_t CalculateSectionLoadAddressForMemoryImage( + lldb::addr_t mach_header_load_address, + const lldb_private::Section *mach_header_section, + const lldb_private::Section *section); + + lldb_private::UUID + GetSharedCacheUUID(lldb_private::FileSpec dyld_shared_cache, + const lldb::ByteOrder byte_order, + const uint32_t addr_byte_size); + + size_t ParseSymtab(); + + llvm::MachO::mach_header m_header; + static const lldb_private::ConstString &GetSegmentNameTEXT(); + static const lldb_private::ConstString &GetSegmentNameDATA(); + static const lldb_private::ConstString &GetSegmentNameDATA_DIRTY(); + static const lldb_private::ConstString &GetSegmentNameDATA_CONST(); + static const lldb_private::ConstString &GetSegmentNameOBJC(); + static const lldb_private::ConstString &GetSegmentNameLINKEDIT(); + static const lldb_private::ConstString &GetSectionNameEHFrame(); + + llvm::MachO::dysymtab_command m_dysymtab; + std::vector<llvm::MachO::segment_command_64> m_mach_segments; + std::vector<llvm::MachO::section_64> m_mach_sections; + std::vector<uint32_t> m_min_os_versions; + std::vector<uint32_t> m_sdk_versions; + typedef lldb_private::RangeVector<uint32_t, uint32_t> FileRangeArray; + lldb_private::Address m_entry_point_address; + FileRangeArray m_thread_context_offsets; + bool m_thread_context_offsets_valid; + lldb_private::FileSpecList m_reexported_dylibs; + bool m_allow_assembly_emulation_unwind_plans; }; #endif // liblldb_ObjectFileMachO_h_ diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 5f5a0ab07ad..82624b3a8a1 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -14,7 +14,6 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBuffer.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -24,858 +23,781 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" -#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ -#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 -#define OPT_HEADER_MAGIC_PE32 0x010b -#define OPT_HEADER_MAGIC_PE32_PLUS 0x020b +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define OPT_HEADER_MAGIC_PE32 0x010b +#define OPT_HEADER_MAGIC_PE32_PLUS 0x020b using namespace lldb; using namespace lldb_private; -void -ObjectFilePECOFF::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - CreateMemoryInstance, - GetModuleSpecifications, - SaveCore); +void ObjectFilePECOFF::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications, SaveCore); } -void -ObjectFilePECOFF::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void ObjectFilePECOFF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } - -lldb_private::ConstString -ObjectFilePECOFF::GetPluginNameStatic() -{ - static ConstString g_name("pe-coff"); - return g_name; +lldb_private::ConstString ObjectFilePECOFF::GetPluginNameStatic() { + static ConstString g_name("pe-coff"); + return g_name; } -const char * -ObjectFilePECOFF::GetPluginDescriptionStatic() -{ - return "Portable Executable and Common Object File Format object file reader (32 and 64 bit)"; +const char *ObjectFilePECOFF::GetPluginDescriptionStatic() { + return "Portable Executable and Common Object File Format object file reader " + "(32 and 64 bit)"; } +ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) { + if (!data_sp) { + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + data_offset = 0; + } -ObjectFile * -ObjectFilePECOFF::CreateInstance (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) -{ - if (!data_sp) - { - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - data_offset = 0; - } - - if (ObjectFilePECOFF::MagicBytesMatch(data_sp)) - { - // Update the data to contain the entire file if it doesn't already - if (data_sp->GetByteSize() < length) - data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); - std::unique_ptr<ObjectFile> objfile_ap(new ObjectFilePECOFF (module_sp, data_sp, data_offset, file, file_offset, length)); - if (objfile_ap.get() && objfile_ap->ParseHeader()) - return objfile_ap.release(); - } - return NULL; + if (ObjectFilePECOFF::MagicBytesMatch(data_sp)) { + // Update the data to contain the entire file if it doesn't already + if (data_sp->GetByteSize() < length) + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); + std::unique_ptr<ObjectFile> objfile_ap(new ObjectFilePECOFF( + module_sp, data_sp, data_offset, file, file_offset, length)); + if (objfile_ap.get() && objfile_ap->ParseHeader()) + return objfile_ap.release(); + } + return NULL; } -ObjectFile * -ObjectFilePECOFF::CreateMemoryInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr) -{ - return NULL; +ObjectFile *ObjectFilePECOFF::CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) { + return NULL; } -size_t -ObjectFilePECOFF::GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs) -{ - const size_t initial_count = specs.GetSize(); - - if (ObjectFilePECOFF::MagicBytesMatch(data_sp)) - { - DataExtractor data; - data.SetData(data_sp, data_offset, length); - data.SetByteOrder(eByteOrderLittle); - - dos_header_t dos_header; - coff_header_t coff_header; - - if (ParseDOSHeader(data, dos_header)) - { - lldb::offset_t offset = dos_header.e_lfanew; - uint32_t pe_signature = data.GetU32(&offset); - if (pe_signature != IMAGE_NT_SIGNATURE) - return false; - if (ParseCOFFHeader(data, &offset, coff_header)) - { - ArchSpec spec; - if (coff_header.machine == MachineAmd64) - { - spec.SetTriple("x86_64-pc-windows"); - specs.Append(ModuleSpec(file, spec)); - } - else if (coff_header.machine == MachineX86) - { - spec.SetTriple("i386-pc-windows"); - specs.Append(ModuleSpec(file, spec)); - spec.SetTriple("i686-pc-windows"); - specs.Append(ModuleSpec(file, spec)); - } - } +size_t ObjectFilePECOFF::GetModuleSpecifications( + const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, lldb::offset_t file_offset, + lldb::offset_t length, lldb_private::ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + + if (ObjectFilePECOFF::MagicBytesMatch(data_sp)) { + DataExtractor data; + data.SetData(data_sp, data_offset, length); + data.SetByteOrder(eByteOrderLittle); + + dos_header_t dos_header; + coff_header_t coff_header; + + if (ParseDOSHeader(data, dos_header)) { + lldb::offset_t offset = dos_header.e_lfanew; + uint32_t pe_signature = data.GetU32(&offset); + if (pe_signature != IMAGE_NT_SIGNATURE) + return false; + if (ParseCOFFHeader(data, &offset, coff_header)) { + ArchSpec spec; + if (coff_header.machine == MachineAmd64) { + spec.SetTriple("x86_64-pc-windows"); + specs.Append(ModuleSpec(file, spec)); + } else if (coff_header.machine == MachineX86) { + spec.SetTriple("i386-pc-windows"); + specs.Append(ModuleSpec(file, spec)); + spec.SetTriple("i686-pc-windows"); + specs.Append(ModuleSpec(file, spec)); } + } } + } - return specs.GetSize() - initial_count; + return specs.GetSize() - initial_count; } -bool -ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb_private::Error &error) -{ - return SaveMiniDump(process_sp, outfile, error); +bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error) { + return SaveMiniDump(process_sp, outfile, error); } - -bool -ObjectFilePECOFF::MagicBytesMatch (DataBufferSP& data_sp) -{ - DataExtractor data(data_sp, eByteOrderLittle, 4); - lldb::offset_t offset = 0; - uint16_t magic = data.GetU16 (&offset); - return magic == IMAGE_DOS_SIGNATURE; +bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP &data_sp) { + DataExtractor data(data_sp, eByteOrderLittle, 4); + lldb::offset_t offset = 0; + uint16_t magic = data.GetU16(&offset); + return magic == IMAGE_DOS_SIGNATURE; } -lldb::SymbolType -ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) -{ - // TODO: We need to complete this mapping of COFF symbol types to LLDB ones. - // For now, here's a hack to make sure our function have types. - const auto complex_type = coff_symbol_type >> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT; - if (complex_type == llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) - { - return lldb::eSymbolTypeCode; - } - return lldb::eSymbolTypeInvalid; +lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) { + // TODO: We need to complete this mapping of COFF symbol types to LLDB ones. + // For now, here's a hack to make sure our function have types. + const auto complex_type = + coff_symbol_type >> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT; + if (complex_type == llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) { + return lldb::eSymbolTypeCode; + } + return lldb::eSymbolTypeInvalid; } -ObjectFilePECOFF::ObjectFilePECOFF (const lldb::ModuleSP &module_sp, - DataBufferSP& data_sp, - lldb::offset_t data_offset, - const FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length) : - ObjectFile (module_sp, file, file_offset, length, data_sp, data_offset), - m_dos_header (), - m_coff_header (), - m_coff_header_opt (), - m_sect_headers (), - m_entry_point_address () -{ - ::memset (&m_dos_header, 0, sizeof(m_dos_header)); - ::memset (&m_coff_header, 0, sizeof(m_coff_header)); - ::memset (&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); +ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, + DataBufferSP &data_sp, + lldb::offset_t data_offset, + const FileSpec *file, + lldb::offset_t file_offset, + lldb::offset_t length) + : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), + m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(), + m_entry_point_address() { + ::memset(&m_dos_header, 0, sizeof(m_dos_header)); + ::memset(&m_coff_header, 0, sizeof(m_coff_header)); + ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt)); } +ObjectFilePECOFF::~ObjectFilePECOFF() {} -ObjectFilePECOFF::~ObjectFilePECOFF() -{ -} - +bool ObjectFilePECOFF::ParseHeader() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + m_sect_headers.clear(); + m_data.SetByteOrder(eByteOrderLittle); + lldb::offset_t offset = 0; -bool -ObjectFilePECOFF::ParseHeader () -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - m_sect_headers.clear(); - m_data.SetByteOrder (eByteOrderLittle); - lldb::offset_t offset = 0; - - if (ParseDOSHeader(m_data, m_dos_header)) - { - offset = m_dos_header.e_lfanew; - uint32_t pe_signature = m_data.GetU32 (&offset); - if (pe_signature != IMAGE_NT_SIGNATURE) - return false; - if (ParseCOFFHeader(m_data, &offset, m_coff_header)) - { - if (m_coff_header.hdrsize > 0) - ParseCOFFOptionalHeader(&offset); - ParseSectionHeaders (offset); - } - return true; - } + if (ParseDOSHeader(m_data, m_dos_header)) { + offset = m_dos_header.e_lfanew; + uint32_t pe_signature = m_data.GetU32(&offset); + if (pe_signature != IMAGE_NT_SIGNATURE) + return false; + if (ParseCOFFHeader(m_data, &offset, m_coff_header)) { + if (m_coff_header.hdrsize > 0) + ParseCOFFOptionalHeader(&offset); + ParseSectionHeaders(offset); + } + return true; } - return false; + } + return false; } -bool -ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value, bool value_is_offset) -{ - bool changed = false; - ModuleSP module_sp = GetModule(); - if (module_sp) - { - size_t num_loaded_sections = 0; - SectionList *section_list = GetSectionList (); - if (section_list) - { - if (!value_is_offset) - { - value -= m_image_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. - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - if (section_sp && !section_sp->IsThreadSpecific()) - { - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) - ++num_loaded_sections; - } - } - changed = num_loaded_sections > 0; +bool ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value, + bool value_is_offset) { + bool changed = false; + ModuleSP module_sp = GetModule(); + if (module_sp) { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (section_list) { + if (!value_is_offset) { + value -= m_image_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. + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp && !section_sp->IsThreadSpecific()) { + if (target.GetSectionLoadList().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; } + } + changed = num_loaded_sections > 0; } - return changed; + } + return changed; } +ByteOrder ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle; } -ByteOrder -ObjectFilePECOFF::GetByteOrder () const -{ - return eByteOrderLittle; -} - -bool -ObjectFilePECOFF::IsExecutable() const -{ - return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0; +bool ObjectFilePECOFF::IsExecutable() const { + return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0; } -uint32_t -ObjectFilePECOFF::GetAddressByteSize () const -{ - if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS) - return 8; - else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) - return 4; +uint32_t ObjectFilePECOFF::GetAddressByteSize() const { + if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS) + return 8; + else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) return 4; + return 4; } //---------------------------------------------------------------------- // NeedsEndianSwap // -// Return true if an endian swap needs to occur when extracting data +// Return true if an endian swap needs to occur when extracting data // from this file. //---------------------------------------------------------------------- -bool -ObjectFilePECOFF::NeedsEndianSwap() const -{ +bool ObjectFilePECOFF::NeedsEndianSwap() const { #if defined(__LITTLE_ENDIAN__) - return false; + return false; #else - return true; + return true; #endif } //---------------------------------------------------------------------- // ParseDOSHeader //---------------------------------------------------------------------- -bool -ObjectFilePECOFF::ParseDOSHeader (DataExtractor &data, dos_header_t &dos_header) -{ - bool success = false; - lldb::offset_t offset = 0; - success = data.ValidOffsetForDataOfSize(0, sizeof(dos_header)); - - if (success) - { - dos_header.e_magic = data.GetU16(&offset); // Magic number - success = dos_header.e_magic == IMAGE_DOS_SIGNATURE; - - if (success) - { - dos_header.e_cblp = data.GetU16(&offset); // Bytes on last page of file - dos_header.e_cp = data.GetU16(&offset); // Pages in file - dos_header.e_crlc = data.GetU16(&offset); // Relocations - dos_header.e_cparhdr = data.GetU16(&offset); // Size of header in paragraphs - dos_header.e_minalloc = data.GetU16(&offset); // Minimum extra paragraphs needed - dos_header.e_maxalloc = data.GetU16(&offset); // Maximum extra paragraphs needed - dos_header.e_ss = data.GetU16(&offset); // Initial (relative) SS value - dos_header.e_sp = data.GetU16(&offset); // Initial SP value - dos_header.e_csum = data.GetU16(&offset); // Checksum - dos_header.e_ip = data.GetU16(&offset); // Initial IP value - dos_header.e_cs = data.GetU16(&offset); // Initial (relative) CS value - dos_header.e_lfarlc = data.GetU16(&offset); // File address of relocation table - dos_header.e_ovno = data.GetU16(&offset); // Overlay number - - dos_header.e_res[0] = data.GetU16(&offset); // Reserved words - dos_header.e_res[1] = data.GetU16(&offset); // Reserved words - dos_header.e_res[2] = data.GetU16(&offset); // Reserved words - dos_header.e_res[3] = data.GetU16(&offset); // Reserved words - - dos_header.e_oemid = data.GetU16(&offset); // OEM identifier (for e_oeminfo) - dos_header.e_oeminfo = data.GetU16(&offset); // OEM information; e_oemid specific - dos_header.e_res2[0] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[1] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[2] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[3] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[4] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[5] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[6] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[7] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[8] = data.GetU16(&offset); // Reserved words - dos_header.e_res2[9] = data.GetU16(&offset); // Reserved words - - dos_header.e_lfanew = data.GetU32(&offset); // File address of new exe header - } +bool ObjectFilePECOFF::ParseDOSHeader(DataExtractor &data, + dos_header_t &dos_header) { + bool success = false; + lldb::offset_t offset = 0; + success = data.ValidOffsetForDataOfSize(0, sizeof(dos_header)); + + if (success) { + dos_header.e_magic = data.GetU16(&offset); // Magic number + success = dos_header.e_magic == IMAGE_DOS_SIGNATURE; + + if (success) { + dos_header.e_cblp = data.GetU16(&offset); // Bytes on last page of file + dos_header.e_cp = data.GetU16(&offset); // Pages in file + dos_header.e_crlc = data.GetU16(&offset); // Relocations + dos_header.e_cparhdr = + data.GetU16(&offset); // Size of header in paragraphs + dos_header.e_minalloc = + data.GetU16(&offset); // Minimum extra paragraphs needed + dos_header.e_maxalloc = + data.GetU16(&offset); // Maximum extra paragraphs needed + dos_header.e_ss = data.GetU16(&offset); // Initial (relative) SS value + dos_header.e_sp = data.GetU16(&offset); // Initial SP value + dos_header.e_csum = data.GetU16(&offset); // Checksum + dos_header.e_ip = data.GetU16(&offset); // Initial IP value + dos_header.e_cs = data.GetU16(&offset); // Initial (relative) CS value + dos_header.e_lfarlc = + data.GetU16(&offset); // File address of relocation table + dos_header.e_ovno = data.GetU16(&offset); // Overlay number + + dos_header.e_res[0] = data.GetU16(&offset); // Reserved words + dos_header.e_res[1] = data.GetU16(&offset); // Reserved words + dos_header.e_res[2] = data.GetU16(&offset); // Reserved words + dos_header.e_res[3] = data.GetU16(&offset); // Reserved words + + dos_header.e_oemid = + data.GetU16(&offset); // OEM identifier (for e_oeminfo) + dos_header.e_oeminfo = + data.GetU16(&offset); // OEM information; e_oemid specific + dos_header.e_res2[0] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[1] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[2] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[3] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[4] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[5] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[6] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[7] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[8] = data.GetU16(&offset); // Reserved words + dos_header.e_res2[9] = data.GetU16(&offset); // Reserved words + + dos_header.e_lfanew = + data.GetU32(&offset); // File address of new exe header } - if (!success) - memset(&dos_header, 0, sizeof(dos_header)); - return success; + } + if (!success) + memset(&dos_header, 0, sizeof(dos_header)); + return success; } - //---------------------------------------------------------------------- // ParserCOFFHeader //---------------------------------------------------------------------- -bool -ObjectFilePECOFF::ParseCOFFHeader(DataExtractor &data, lldb::offset_t *offset_ptr, coff_header_t &coff_header) -{ - bool success = data.ValidOffsetForDataOfSize (*offset_ptr, sizeof(coff_header)); - if (success) - { - coff_header.machine = data.GetU16(offset_ptr); - coff_header.nsects = data.GetU16(offset_ptr); - coff_header.modtime = data.GetU32(offset_ptr); - coff_header.symoff = data.GetU32(offset_ptr); - coff_header.nsyms = data.GetU32(offset_ptr); - coff_header.hdrsize = data.GetU16(offset_ptr); - coff_header.flags = data.GetU16(offset_ptr); - } - if (!success) - memset(&coff_header, 0, sizeof(coff_header)); - return success; -} - -bool -ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) -{ - bool success = false; - const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize; - if (*offset_ptr < end_offset) - { - success = true; - m_coff_header_opt.magic = m_data.GetU16(offset_ptr); - m_coff_header_opt.major_linker_version = m_data.GetU8 (offset_ptr); - m_coff_header_opt.minor_linker_version = m_data.GetU8 (offset_ptr); - m_coff_header_opt.code_size = m_data.GetU32(offset_ptr); - m_coff_header_opt.data_size = m_data.GetU32(offset_ptr); - m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr); - m_coff_header_opt.entry = m_data.GetU32(offset_ptr); - m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr); - - const uint32_t addr_byte_size = GetAddressByteSize (); - - if (*offset_ptr < end_offset) - { - if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) - { - // PE32 only - m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr); - } - else - m_coff_header_opt.data_offset = 0; - - if (*offset_ptr < end_offset) - { - m_coff_header_opt.image_base = m_data.GetMaxU64 (offset_ptr, addr_byte_size); - m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr); - m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr); - m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr); - m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr); - m_coff_header_opt.image_size = m_data.GetU32(offset_ptr); - m_coff_header_opt.header_size = m_data.GetU32(offset_ptr); - m_coff_header_opt.checksum = m_data.GetU32(offset_ptr); - m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr); - m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr); - m_coff_header_opt.stack_reserve_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size); - m_coff_header_opt.stack_commit_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size); - m_coff_header_opt.heap_reserve_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size); - m_coff_header_opt.heap_commit_size = m_data.GetMaxU64 (offset_ptr, addr_byte_size); - m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr); - uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr); - m_coff_header_opt.data_dirs.clear(); - m_coff_header_opt.data_dirs.resize(num_data_dir_entries); - uint32_t i; - for (i=0; i<num_data_dir_entries; i++) - { - m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr); - m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr); - } - - m_file_offset = m_coff_header_opt.image_base; - m_image_base = m_coff_header_opt.image_base; - } +bool ObjectFilePECOFF::ParseCOFFHeader(DataExtractor &data, + lldb::offset_t *offset_ptr, + coff_header_t &coff_header) { + bool success = + data.ValidOffsetForDataOfSize(*offset_ptr, sizeof(coff_header)); + if (success) { + coff_header.machine = data.GetU16(offset_ptr); + coff_header.nsects = data.GetU16(offset_ptr); + coff_header.modtime = data.GetU32(offset_ptr); + coff_header.symoff = data.GetU32(offset_ptr); + coff_header.nsyms = data.GetU32(offset_ptr); + coff_header.hdrsize = data.GetU16(offset_ptr); + coff_header.flags = data.GetU16(offset_ptr); + } + if (!success) + memset(&coff_header, 0, sizeof(coff_header)); + return success; +} + +bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) { + bool success = false; + const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize; + if (*offset_ptr < end_offset) { + success = true; + m_coff_header_opt.magic = m_data.GetU16(offset_ptr); + m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr); + m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr); + m_coff_header_opt.code_size = m_data.GetU32(offset_ptr); + m_coff_header_opt.data_size = m_data.GetU32(offset_ptr); + m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr); + m_coff_header_opt.entry = m_data.GetU32(offset_ptr); + m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr); + + const uint32_t addr_byte_size = GetAddressByteSize(); + + if (*offset_ptr < end_offset) { + if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) { + // PE32 only + m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr); + } else + m_coff_header_opt.data_offset = 0; + + if (*offset_ptr < end_offset) { + m_coff_header_opt.image_base = + m_data.GetMaxU64(offset_ptr, addr_byte_size); + m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr); + m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr); + m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr); + m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr); + m_coff_header_opt.image_size = m_data.GetU32(offset_ptr); + m_coff_header_opt.header_size = m_data.GetU32(offset_ptr); + m_coff_header_opt.checksum = m_data.GetU32(offset_ptr); + m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr); + m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr); + m_coff_header_opt.stack_reserve_size = + m_data.GetMaxU64(offset_ptr, addr_byte_size); + m_coff_header_opt.stack_commit_size = + m_data.GetMaxU64(offset_ptr, addr_byte_size); + m_coff_header_opt.heap_reserve_size = + m_data.GetMaxU64(offset_ptr, addr_byte_size); + m_coff_header_opt.heap_commit_size = + m_data.GetMaxU64(offset_ptr, addr_byte_size); + m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr); + uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr); + m_coff_header_opt.data_dirs.clear(); + m_coff_header_opt.data_dirs.resize(num_data_dir_entries); + uint32_t i; + for (i = 0; i < num_data_dir_entries; i++) { + m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr); + m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr); } + + m_file_offset = m_coff_header_opt.image_base; + m_image_base = m_coff_header_opt.image_base; + } } - // Make sure we are on track for section data which follows - *offset_ptr = end_offset; - return success; + } + // Make sure we are on track for section data which follows + *offset_ptr = end_offset; + return success; } - //---------------------------------------------------------------------- // ParseSectionHeaders //---------------------------------------------------------------------- -bool -ObjectFilePECOFF::ParseSectionHeaders (uint32_t section_header_data_offset) -{ - const uint32_t nsects = m_coff_header.nsects; - m_sect_headers.clear(); - - if (nsects > 0) - { - const uint32_t addr_byte_size = GetAddressByteSize (); - const size_t section_header_byte_size = nsects * sizeof(section_header_t); - DataBufferSP section_header_data_sp(m_file.ReadFileContents (section_header_data_offset, section_header_byte_size)); - DataExtractor section_header_data (section_header_data_sp, GetByteOrder(), addr_byte_size); +bool ObjectFilePECOFF::ParseSectionHeaders( + uint32_t section_header_data_offset) { + const uint32_t nsects = m_coff_header.nsects; + m_sect_headers.clear(); + + if (nsects > 0) { + const uint32_t addr_byte_size = GetAddressByteSize(); + const size_t section_header_byte_size = nsects * sizeof(section_header_t); + DataBufferSP section_header_data_sp(m_file.ReadFileContents( + section_header_data_offset, section_header_byte_size)); + DataExtractor section_header_data(section_header_data_sp, GetByteOrder(), + addr_byte_size); - lldb::offset_t offset = 0; - if (section_header_data.ValidOffsetForDataOfSize (offset, section_header_byte_size)) - { - m_sect_headers.resize(nsects); - - for (uint32_t idx = 0; idx<nsects; ++idx) - { - const void *name_data = section_header_data.GetData(&offset, 8); - if (name_data) - { - memcpy(m_sect_headers[idx].name, name_data, 8); - m_sect_headers[idx].vmsize = section_header_data.GetU32(&offset); - m_sect_headers[idx].vmaddr = section_header_data.GetU32(&offset); - m_sect_headers[idx].size = section_header_data.GetU32(&offset); - m_sect_headers[idx].offset = section_header_data.GetU32(&offset); - m_sect_headers[idx].reloff = section_header_data.GetU32(&offset); - m_sect_headers[idx].lineoff = section_header_data.GetU32(&offset); - m_sect_headers[idx].nreloc = section_header_data.GetU16(&offset); - m_sect_headers[idx].nline = section_header_data.GetU16(&offset); - m_sect_headers[idx].flags = section_header_data.GetU32(&offset); - } - } + lldb::offset_t offset = 0; + if (section_header_data.ValidOffsetForDataOfSize( + offset, section_header_byte_size)) { + m_sect_headers.resize(nsects); + + for (uint32_t idx = 0; idx < nsects; ++idx) { + const void *name_data = section_header_data.GetData(&offset, 8); + if (name_data) { + memcpy(m_sect_headers[idx].name, name_data, 8); + m_sect_headers[idx].vmsize = section_header_data.GetU32(&offset); + m_sect_headers[idx].vmaddr = section_header_data.GetU32(&offset); + m_sect_headers[idx].size = section_header_data.GetU32(&offset); + m_sect_headers[idx].offset = section_header_data.GetU32(&offset); + m_sect_headers[idx].reloff = section_header_data.GetU32(&offset); + m_sect_headers[idx].lineoff = section_header_data.GetU32(&offset); + m_sect_headers[idx].nreloc = section_header_data.GetU16(&offset); + m_sect_headers[idx].nline = section_header_data.GetU16(&offset); + m_sect_headers[idx].flags = section_header_data.GetU32(&offset); } + } } - - return m_sect_headers.empty() == false; + } + + return m_sect_headers.empty() == false; } -bool -ObjectFilePECOFF::GetSectionName(std::string& sect_name, const section_header_t& sect) -{ - if (sect.name[0] == '/') - { - lldb::offset_t stroff = strtoul(§.name[1], NULL, 10); - lldb::offset_t string_file_offset = m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff; - const char *name = m_data.GetCStr (&string_file_offset); - if (name) - { - sect_name = name; - return true; - } - - return false; +bool ObjectFilePECOFF::GetSectionName(std::string §_name, + const section_header_t §) { + if (sect.name[0] == '/') { + lldb::offset_t stroff = strtoul(§.name[1], NULL, 10); + lldb::offset_t string_file_offset = + m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff; + const char *name = m_data.GetCStr(&string_file_offset); + if (name) { + sect_name = name; + return true; } - sect_name = sect.name; - return true; -} + + return false; + } + sect_name = sect.name; + return true; +} //---------------------------------------------------------------------- // GetNListSymtab //---------------------------------------------------------------------- -Symtab * -ObjectFilePECOFF::GetSymtab() -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - if (m_symtab_ap.get() == NULL) - { - SectionList *sect_list = GetSectionList(); - m_symtab_ap.reset(new Symtab(this)); - std::lock_guard<std::recursive_mutex> guard(m_symtab_ap->GetMutex()); - - const uint32_t num_syms = m_coff_header.nsyms; - - if (num_syms > 0 && m_coff_header.symoff > 0) - { - const uint32_t symbol_size = 18; - const uint32_t addr_byte_size = GetAddressByteSize (); - const size_t symbol_data_size = num_syms * symbol_size; - // Include the 4-byte string table size at the end of the symbols - DataBufferSP symtab_data_sp(m_file.ReadFileContents (m_coff_header.symoff, symbol_data_size + 4)); - DataExtractor symtab_data (symtab_data_sp, GetByteOrder(), addr_byte_size); - lldb::offset_t offset = symbol_data_size; - const uint32_t strtab_size = symtab_data.GetU32 (&offset); - DataBufferSP strtab_data_sp(m_file.ReadFileContents (m_coff_header.symoff + symbol_data_size, strtab_size)); - DataExtractor strtab_data (strtab_data_sp, GetByteOrder(), addr_byte_size); - - // First 4 bytes should be zeroed after strtab_size has been read, - // because it is used as offset 0 to encode a NULL string. - uint32_t* strtab_data_start = (uint32_t*)strtab_data_sp->GetBytes(); - strtab_data_start[0] = 0; - - offset = 0; - std::string symbol_name; - Symbol *symbols = m_symtab_ap->Resize (num_syms); - for (uint32_t i=0; i<num_syms; ++i) - { - coff_symbol_t symbol; - const uint32_t symbol_offset = offset; - const char *symbol_name_cstr = NULL; - // If the first 4 bytes of the symbol string are zero, then they - // are followed by a 4-byte string table offset. Else these - // 8 bytes contain the symbol name - if (symtab_data.GetU32 (&offset) == 0) - { - // Long string that doesn't fit into the symbol table name, - // so now we must read the 4 byte string table offset - uint32_t strtab_offset = symtab_data.GetU32 (&offset); - symbol_name_cstr = strtab_data.PeekCStr (strtab_offset); - symbol_name.assign (symbol_name_cstr); - } - else - { - // Short string that fits into the symbol table name which is 8 bytes - offset += sizeof(symbol.name) - 4; // Skip remaining - symbol_name_cstr = symtab_data.PeekCStr (symbol_offset); - if (symbol_name_cstr == NULL) - break; - symbol_name.assign (symbol_name_cstr, sizeof(symbol.name)); - } - symbol.value = symtab_data.GetU32 (&offset); - symbol.sect = symtab_data.GetU16 (&offset); - symbol.type = symtab_data.GetU16 (&offset); - symbol.storage = symtab_data.GetU8 (&offset); - symbol.naux = symtab_data.GetU8 (&offset); - symbols[i].GetMangled ().SetValue (ConstString(symbol_name.c_str())); - if ((int16_t)symbol.sect >= 1) - { - Address symbol_addr(sect_list->GetSectionAtIndex(symbol.sect-1), symbol.value); - symbols[i].GetAddressRef() = symbol_addr; - symbols[i].SetType(MapSymbolType(symbol.type)); - } - - if (symbol.naux > 0) - { - i += symbol.naux; - offset += symbol_size; - } - } - - } - - // Read export header - if (coff_data_dir_export_table < m_coff_header_opt.data_dirs.size() - && m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmsize > 0 && m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr > 0) - { - export_directory_entry export_table; - uint32_t data_start = m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr; - Address address(m_coff_header_opt.image_base + data_start, sect_list); - DataBufferSP symtab_data_sp(m_file.ReadFileContents(address.GetSection()->GetFileOffset() + address.GetOffset(), m_coff_header_opt.data_dirs[0].vmsize)); - DataExtractor symtab_data (symtab_data_sp, GetByteOrder(), GetAddressByteSize()); - lldb::offset_t offset = 0; - - // Read export_table header - export_table.characteristics = symtab_data.GetU32(&offset); - export_table.time_date_stamp = symtab_data.GetU32(&offset); - export_table.major_version = symtab_data.GetU16(&offset); - export_table.minor_version = symtab_data.GetU16(&offset); - export_table.name = symtab_data.GetU32(&offset); - export_table.base = symtab_data.GetU32(&offset); - export_table.number_of_functions = symtab_data.GetU32(&offset); - export_table.number_of_names = symtab_data.GetU32(&offset); - export_table.address_of_functions = symtab_data.GetU32(&offset); - export_table.address_of_names = symtab_data.GetU32(&offset); - export_table.address_of_name_ordinals = symtab_data.GetU32(&offset); - - bool has_ordinal = export_table.address_of_name_ordinals != 0; - - lldb::offset_t name_offset = export_table.address_of_names - data_start; - lldb::offset_t name_ordinal_offset = export_table.address_of_name_ordinals - data_start; - - Symbol *symbols = m_symtab_ap->Resize(export_table.number_of_names); - - std::string symbol_name; - - // Read each export table entry - for (size_t i = 0; i < export_table.number_of_names; ++i) - { - uint32_t name_ordinal = has_ordinal ? symtab_data.GetU16(&name_ordinal_offset) : i; - uint32_t name_address = symtab_data.GetU32(&name_offset); - - const char* symbol_name_cstr = symtab_data.PeekCStr(name_address - data_start); - symbol_name.assign(symbol_name_cstr); - - lldb::offset_t function_offset = export_table.address_of_functions - data_start + sizeof(uint32_t) * name_ordinal; - uint32_t function_rva = symtab_data.GetU32(&function_offset); - - Address symbol_addr(m_coff_header_opt.image_base + function_rva, sect_list); - symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str())); - symbols[i].GetAddressRef() = symbol_addr; - symbols[i].SetType(lldb::eSymbolTypeCode); - symbols[i].SetDebug(true); - } - } - m_symtab_ap->CalculateSymbolSizes(); +Symtab *ObjectFilePECOFF::GetSymtab() { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + if (m_symtab_ap.get() == NULL) { + SectionList *sect_list = GetSectionList(); + m_symtab_ap.reset(new Symtab(this)); + std::lock_guard<std::recursive_mutex> guard(m_symtab_ap->GetMutex()); + + const uint32_t num_syms = m_coff_header.nsyms; + + if (num_syms > 0 && m_coff_header.symoff > 0) { + const uint32_t symbol_size = 18; + const uint32_t addr_byte_size = GetAddressByteSize(); + const size_t symbol_data_size = num_syms * symbol_size; + // Include the 4-byte string table size at the end of the symbols + DataBufferSP symtab_data_sp(m_file.ReadFileContents( + m_coff_header.symoff, symbol_data_size + 4)); + DataExtractor symtab_data(symtab_data_sp, GetByteOrder(), + addr_byte_size); + lldb::offset_t offset = symbol_data_size; + const uint32_t strtab_size = symtab_data.GetU32(&offset); + DataBufferSP strtab_data_sp(m_file.ReadFileContents( + m_coff_header.symoff + symbol_data_size, strtab_size)); + DataExtractor strtab_data(strtab_data_sp, GetByteOrder(), + addr_byte_size); + + // First 4 bytes should be zeroed after strtab_size has been read, + // because it is used as offset 0 to encode a NULL string. + uint32_t *strtab_data_start = (uint32_t *)strtab_data_sp->GetBytes(); + strtab_data_start[0] = 0; + + offset = 0; + std::string symbol_name; + Symbol *symbols = m_symtab_ap->Resize(num_syms); + for (uint32_t i = 0; i < num_syms; ++i) { + coff_symbol_t symbol; + const uint32_t symbol_offset = offset; + const char *symbol_name_cstr = NULL; + // If the first 4 bytes of the symbol string are zero, then they + // are followed by a 4-byte string table offset. Else these + // 8 bytes contain the symbol name + if (symtab_data.GetU32(&offset) == 0) { + // Long string that doesn't fit into the symbol table name, + // so now we must read the 4 byte string table offset + uint32_t strtab_offset = symtab_data.GetU32(&offset); + symbol_name_cstr = strtab_data.PeekCStr(strtab_offset); + symbol_name.assign(symbol_name_cstr); + } else { + // Short string that fits into the symbol table name which is 8 + // bytes + offset += sizeof(symbol.name) - 4; // Skip remaining + symbol_name_cstr = symtab_data.PeekCStr(symbol_offset); + if (symbol_name_cstr == NULL) + break; + symbol_name.assign(symbol_name_cstr, sizeof(symbol.name)); + } + symbol.value = symtab_data.GetU32(&offset); + symbol.sect = symtab_data.GetU16(&offset); + symbol.type = symtab_data.GetU16(&offset); + symbol.storage = symtab_data.GetU8(&offset); + symbol.naux = symtab_data.GetU8(&offset); + symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str())); + if ((int16_t)symbol.sect >= 1) { + Address symbol_addr(sect_list->GetSectionAtIndex(symbol.sect - 1), + symbol.value); + symbols[i].GetAddressRef() = symbol_addr; + symbols[i].SetType(MapSymbolType(symbol.type)); + } + + if (symbol.naux > 0) { + i += symbol.naux; + offset += symbol_size; + } } - } - return m_symtab_ap.get(); + } + + // Read export header + if (coff_data_dir_export_table < m_coff_header_opt.data_dirs.size() && + m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmsize > 0 && + m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr > 0) { + export_directory_entry export_table; + uint32_t data_start = + m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr; + Address address(m_coff_header_opt.image_base + data_start, sect_list); + DataBufferSP symtab_data_sp(m_file.ReadFileContents( + address.GetSection()->GetFileOffset() + address.GetOffset(), + m_coff_header_opt.data_dirs[0].vmsize)); + DataExtractor symtab_data(symtab_data_sp, GetByteOrder(), + GetAddressByteSize()); + lldb::offset_t offset = 0; + // Read export_table header + export_table.characteristics = symtab_data.GetU32(&offset); + export_table.time_date_stamp = symtab_data.GetU32(&offset); + export_table.major_version = symtab_data.GetU16(&offset); + export_table.minor_version = symtab_data.GetU16(&offset); + export_table.name = symtab_data.GetU32(&offset); + export_table.base = symtab_data.GetU32(&offset); + export_table.number_of_functions = symtab_data.GetU32(&offset); + export_table.number_of_names = symtab_data.GetU32(&offset); + export_table.address_of_functions = symtab_data.GetU32(&offset); + export_table.address_of_names = symtab_data.GetU32(&offset); + export_table.address_of_name_ordinals = symtab_data.GetU32(&offset); + + bool has_ordinal = export_table.address_of_name_ordinals != 0; + + lldb::offset_t name_offset = export_table.address_of_names - data_start; + lldb::offset_t name_ordinal_offset = + export_table.address_of_name_ordinals - data_start; + + Symbol *symbols = m_symtab_ap->Resize(export_table.number_of_names); + + std::string symbol_name; + + // Read each export table entry + for (size_t i = 0; i < export_table.number_of_names; ++i) { + uint32_t name_ordinal = + has_ordinal ? symtab_data.GetU16(&name_ordinal_offset) : i; + uint32_t name_address = symtab_data.GetU32(&name_offset); + + const char *symbol_name_cstr = + symtab_data.PeekCStr(name_address - data_start); + symbol_name.assign(symbol_name_cstr); + + lldb::offset_t function_offset = export_table.address_of_functions - + data_start + + sizeof(uint32_t) * name_ordinal; + uint32_t function_rva = symtab_data.GetU32(&function_offset); + + Address symbol_addr(m_coff_header_opt.image_base + function_rva, + sect_list); + symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str())); + symbols[i].GetAddressRef() = symbol_addr; + symbols[i].SetType(lldb::eSymbolTypeCode); + symbols[i].SetDebug(true); + } + } + m_symtab_ap->CalculateSymbolSizes(); + } + } + return m_symtab_ap.get(); } -bool -ObjectFilePECOFF::IsStripped () -{ - // TODO: determine this for COFF - return false; +bool ObjectFilePECOFF::IsStripped() { + // TODO: determine this for COFF + return false; } +void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { + if (!m_sections_ap.get()) { + m_sections_ap.reset(new SectionList()); - -void -ObjectFilePECOFF::CreateSections (SectionList &unified_section_list) -{ - if (!m_sections_ap.get()) - { - m_sections_ap.reset(new SectionList()); - - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - const uint32_t nsects = m_sect_headers.size(); - ModuleSP module_sp (GetModule()); - for (uint32_t idx = 0; idx<nsects; ++idx) - { - std::string sect_name; - GetSectionName (sect_name, m_sect_headers[idx]); - ConstString const_sect_name (sect_name.c_str()); - static ConstString g_code_sect_name (".code"); - static ConstString g_CODE_sect_name ("CODE"); - static ConstString g_data_sect_name (".data"); - static ConstString g_DATA_sect_name ("DATA"); - static ConstString g_bss_sect_name (".bss"); - static ConstString g_BSS_sect_name ("BSS"); - static ConstString g_debug_sect_name (".debug"); - static ConstString g_reloc_sect_name (".reloc"); - static ConstString g_stab_sect_name (".stab"); - static ConstString g_stabstr_sect_name (".stabstr"); - static ConstString g_sect_name_dwarf_debug_abbrev (".debug_abbrev"); - 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_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_eh_frame (".eh_frame"); - static ConstString g_sect_name_go_symtab (".gosymtab"); - SectionType section_type = eSectionTypeOther; - if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && - ((const_sect_name == g_code_sect_name) || (const_sect_name == g_CODE_sect_name))) - { - section_type = eSectionTypeCode; - } - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && - ((const_sect_name == g_data_sect_name) || (const_sect_name == g_DATA_sect_name))) - { - section_type = eSectionTypeData; - } - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && - ((const_sect_name == g_bss_sect_name) || (const_sect_name == g_BSS_sect_name))) - { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } - else if (const_sect_name == g_debug_sect_name) - { - section_type = eSectionTypeDebug; - } - else if (const_sect_name == g_stabstr_sect_name) - { - section_type = eSectionTypeDataCString; - } - else if (const_sect_name == g_reloc_sect_name) - { - section_type = eSectionTypeOther; - } - else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) section_type = eSectionTypeDWARFDebugAbbrev; - else if (const_sect_name == g_sect_name_dwarf_debug_aranges) section_type = eSectionTypeDWARFDebugAranges; - else if (const_sect_name == g_sect_name_dwarf_debug_frame) section_type = eSectionTypeDWARFDebugFrame; - else if (const_sect_name == g_sect_name_dwarf_debug_info) section_type = eSectionTypeDWARFDebugInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_line) section_type = eSectionTypeDWARFDebugLine; - else if (const_sect_name == g_sect_name_dwarf_debug_loc) section_type = eSectionTypeDWARFDebugLoc; - else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) section_type = eSectionTypeDWARFDebugMacInfo; - else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) section_type = eSectionTypeDWARFDebugPubNames; - else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) section_type = eSectionTypeDWARFDebugPubTypes; - else if (const_sect_name == g_sect_name_dwarf_debug_ranges) section_type = eSectionTypeDWARFDebugRanges; - else if (const_sect_name == g_sect_name_dwarf_debug_str) section_type = eSectionTypeDWARFDebugStr; - else if (const_sect_name == g_sect_name_eh_frame) section_type = eSectionTypeEHFrame; - else if (const_sect_name == g_sect_name_go_symtab) section_type = eSectionTypeGoSymtab; - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) - { - section_type = eSectionTypeCode; - } - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) - { - section_type = eSectionTypeData; - } - else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) - { - if (m_sect_headers[idx].size == 0) - section_type = eSectionTypeZeroFill; - else - section_type = eSectionTypeData; - } - - // Use a segment ID of the segment index shifted left by 8 so they - // never conflict with any of the sections. - SectionSP section_sp (new Section (module_sp, // Module to which this section belongs - this, // Object file to which this section belongs - idx + 1, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible - const_sect_name, // Name of this section - section_type, // This section is a container of other sections. - m_coff_header_opt.image_base + m_sect_headers[idx].vmaddr, // File VM address == addresses as they are found in the object file - m_sect_headers[idx].vmsize, // VM size in bytes of this section - m_sect_headers[idx].offset, // Offset to the data for this section in the file - m_sect_headers[idx].size, // Size in bytes of this section as found in the file - m_coff_header_opt.sect_alignment, // Section alignment - m_sect_headers[idx].flags)); // Flags for this section - - //section_sp->SetIsEncrypted (segment_is_encrypted); - - unified_section_list.AddSection(section_sp); - m_sections_ap->AddSection (section_sp); - } + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + const uint32_t nsects = m_sect_headers.size(); + ModuleSP module_sp(GetModule()); + for (uint32_t idx = 0; idx < nsects; ++idx) { + std::string sect_name; + GetSectionName(sect_name, m_sect_headers[idx]); + ConstString const_sect_name(sect_name.c_str()); + static ConstString g_code_sect_name(".code"); + static ConstString g_CODE_sect_name("CODE"); + static ConstString g_data_sect_name(".data"); + static ConstString g_DATA_sect_name("DATA"); + static ConstString g_bss_sect_name(".bss"); + static ConstString g_BSS_sect_name("BSS"); + static ConstString g_debug_sect_name(".debug"); + static ConstString g_reloc_sect_name(".reloc"); + static ConstString g_stab_sect_name(".stab"); + static ConstString g_stabstr_sect_name(".stabstr"); + static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev"); + 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_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_eh_frame(".eh_frame"); + static ConstString g_sect_name_go_symtab(".gosymtab"); + SectionType section_type = eSectionTypeOther; + if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE && + ((const_sect_name == g_code_sect_name) || + (const_sect_name == g_CODE_sect_name))) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA && + ((const_sect_name == g_data_sect_name) || + (const_sect_name == g_DATA_sect_name))) { + section_type = eSectionTypeData; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA && + ((const_sect_name == g_bss_sect_name) || + (const_sect_name == g_BSS_sect_name))) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else + section_type = eSectionTypeData; + } else if (const_sect_name == g_debug_sect_name) { + section_type = eSectionTypeDebug; + } else if (const_sect_name == g_stabstr_sect_name) { + section_type = eSectionTypeDataCString; + } else if (const_sect_name == g_reloc_sect_name) { + section_type = eSectionTypeOther; + } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev) + section_type = eSectionTypeDWARFDebugAbbrev; + else if (const_sect_name == g_sect_name_dwarf_debug_aranges) + section_type = eSectionTypeDWARFDebugAranges; + else if (const_sect_name == g_sect_name_dwarf_debug_frame) + section_type = eSectionTypeDWARFDebugFrame; + else if (const_sect_name == g_sect_name_dwarf_debug_info) + section_type = eSectionTypeDWARFDebugInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_line) + section_type = eSectionTypeDWARFDebugLine; + else if (const_sect_name == g_sect_name_dwarf_debug_loc) + section_type = eSectionTypeDWARFDebugLoc; + else if (const_sect_name == g_sect_name_dwarf_debug_macinfo) + section_type = eSectionTypeDWARFDebugMacInfo; + else if (const_sect_name == g_sect_name_dwarf_debug_pubnames) + section_type = eSectionTypeDWARFDebugPubNames; + else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes) + section_type = eSectionTypeDWARFDebugPubTypes; + else if (const_sect_name == g_sect_name_dwarf_debug_ranges) + section_type = eSectionTypeDWARFDebugRanges; + else if (const_sect_name == g_sect_name_dwarf_debug_str) + section_type = eSectionTypeDWARFDebugStr; + else if (const_sect_name == g_sect_name_eh_frame) + section_type = eSectionTypeEHFrame; + else if (const_sect_name == g_sect_name_go_symtab) + section_type = eSectionTypeGoSymtab; + else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) { + section_type = eSectionTypeCode; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) { + section_type = eSectionTypeData; + } else if (m_sect_headers[idx].flags & + llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + if (m_sect_headers[idx].size == 0) + section_type = eSectionTypeZeroFill; + else + section_type = eSectionTypeData; } + + // Use a segment ID of the segment index shifted left by 8 so they + // never conflict with any of the sections. + SectionSP section_sp(new Section( + module_sp, // Module to which this section belongs + this, // Object file to which this section belongs + idx + 1, // Section ID is the 1 based segment index shifted right by + // 8 bits as not to collide with any of the 256 section IDs + // that are possible + const_sect_name, // Name of this section + section_type, // This section is a container of other sections. + m_coff_header_opt.image_base + + m_sect_headers[idx].vmaddr, // File VM address == addresses as + // they are found in the object file + m_sect_headers[idx].vmsize, // VM size in bytes of this section + m_sect_headers[idx] + .offset, // Offset to the data for this section in the file + m_sect_headers[idx] + .size, // Size in bytes of this section as found in the file + m_coff_header_opt.sect_alignment, // Section alignment + m_sect_headers[idx].flags)); // Flags for this section + + // section_sp->SetIsEncrypted (segment_is_encrypted); + + unified_section_list.AddSection(section_sp); + m_sections_ap->AddSection(section_sp); + } } + } } -bool -ObjectFilePECOFF::GetUUID (UUID* uuid) -{ - return false; -} +bool ObjectFilePECOFF::GetUUID(UUID *uuid) { return false; } -uint32_t -ObjectFilePECOFF::GetDependentModules (FileSpecList& files) -{ - return 0; +uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) { + return 0; } -lldb_private::Address -ObjectFilePECOFF::GetEntryPointAddress () -{ - if (m_entry_point_address.IsValid()) - return m_entry_point_address; +lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() { + if (m_entry_point_address.IsValid()) + return m_entry_point_address; - if (!ParseHeader() || !IsExecutable()) - return m_entry_point_address; + if (!ParseHeader() || !IsExecutable()) + return m_entry_point_address; - SectionList *section_list = GetSectionList(); - addr_t offset = m_coff_header_opt.entry; + SectionList *section_list = GetSectionList(); + addr_t offset = m_coff_header_opt.entry; - if (!section_list) - m_entry_point_address.SetOffset(offset); - else - m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); - return m_entry_point_address; + if (!section_list) + m_entry_point_address.SetOffset(offset); + else + m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list); + return m_entry_point_address; } - //---------------------------------------------------------------------- // Dump // // Dump the specifics of the runtime file container (such as any headers // segments, sections, etc). //---------------------------------------------------------------------- -void -ObjectFilePECOFF::Dump(Stream *s) -{ - ModuleSP module_sp(GetModule()); - if (module_sp) - { - std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); - s->Printf("%p: ", static_cast<void*>(this)); - s->Indent(); - s->PutCString("ObjectFilePECOFF"); - - ArchSpec header_arch; - GetArchitecture (header_arch); - - *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n"; - - SectionList *sections = GetSectionList(); - if (sections) - sections->Dump(s, NULL, true, UINT32_MAX); - - if (m_symtab_ap.get()) - m_symtab_ap->Dump(s, NULL, eSortOrderNone); - - if (m_dos_header.e_magic) - DumpDOSHeader (s, m_dos_header); - if (m_coff_header.machine) - { - DumpCOFFHeader (s, m_coff_header); - if (m_coff_header.hdrsize) - DumpOptCOFFHeader (s, m_coff_header_opt); - } - s->EOL(); - DumpSectionHeaders(s); - s->EOL(); +void ObjectFilePECOFF::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + s->Printf("%p: ", static_cast<void *>(this)); + s->Indent(); + s->PutCString("ObjectFilePECOFF"); + + ArchSpec header_arch; + GetArchitecture(header_arch); + + *s << ", file = '" << m_file + << "', arch = " << header_arch.GetArchitectureName() << "\n"; + + SectionList *sections = GetSectionList(); + if (sections) + sections->Dump(s, NULL, true, UINT32_MAX); + + if (m_symtab_ap.get()) + m_symtab_ap->Dump(s, NULL, eSortOrderNone); + + if (m_dos_header.e_magic) + DumpDOSHeader(s, m_dos_header); + if (m_coff_header.machine) { + DumpCOFFHeader(s, m_coff_header); + if (m_coff_header.hdrsize) + DumpOptCOFFHeader(s, m_coff_header_opt); } + s->EOL(); + DumpSectionHeaders(s); + s->EOL(); + } } //---------------------------------------------------------------------- @@ -883,43 +805,33 @@ ObjectFilePECOFF::Dump(Stream *s) // // Dump the MS-DOS header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t& header) -{ - s->PutCString ("MSDOS Header\n"); - s->Printf (" e_magic = 0x%4.4x\n", header.e_magic); - s->Printf (" e_cblp = 0x%4.4x\n", header.e_cblp); - s->Printf (" e_cp = 0x%4.4x\n", header.e_cp); - s->Printf (" e_crlc = 0x%4.4x\n", header.e_crlc); - s->Printf (" e_cparhdr = 0x%4.4x\n", header.e_cparhdr); - s->Printf (" e_minalloc = 0x%4.4x\n", header.e_minalloc); - s->Printf (" e_maxalloc = 0x%4.4x\n", header.e_maxalloc); - s->Printf (" e_ss = 0x%4.4x\n", header.e_ss); - s->Printf (" e_sp = 0x%4.4x\n", header.e_sp); - s->Printf (" e_csum = 0x%4.4x\n", header.e_csum); - s->Printf (" e_ip = 0x%4.4x\n", header.e_ip); - s->Printf (" e_cs = 0x%4.4x\n", header.e_cs); - s->Printf (" e_lfarlc = 0x%4.4x\n", header.e_lfarlc); - s->Printf (" e_ovno = 0x%4.4x\n", header.e_ovno); - s->Printf (" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n", - header.e_res[0], - header.e_res[1], - header.e_res[2], - header.e_res[3]); - s->Printf (" e_oemid = 0x%4.4x\n", header.e_oemid); - s->Printf (" e_oeminfo = 0x%4.4x\n", header.e_oeminfo); - s->Printf (" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n", - header.e_res2[0], - header.e_res2[1], - header.e_res2[2], - header.e_res2[3], - header.e_res2[4], - header.e_res2[5], - header.e_res2[6], - header.e_res2[7], - header.e_res2[8], - header.e_res2[9]); - s->Printf (" e_lfanew = 0x%8.8x\n", header.e_lfanew); +void ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t &header) { + s->PutCString("MSDOS Header\n"); + s->Printf(" e_magic = 0x%4.4x\n", header.e_magic); + s->Printf(" e_cblp = 0x%4.4x\n", header.e_cblp); + s->Printf(" e_cp = 0x%4.4x\n", header.e_cp); + s->Printf(" e_crlc = 0x%4.4x\n", header.e_crlc); + s->Printf(" e_cparhdr = 0x%4.4x\n", header.e_cparhdr); + s->Printf(" e_minalloc = 0x%4.4x\n", header.e_minalloc); + s->Printf(" e_maxalloc = 0x%4.4x\n", header.e_maxalloc); + s->Printf(" e_ss = 0x%4.4x\n", header.e_ss); + s->Printf(" e_sp = 0x%4.4x\n", header.e_sp); + s->Printf(" e_csum = 0x%4.4x\n", header.e_csum); + s->Printf(" e_ip = 0x%4.4x\n", header.e_ip); + s->Printf(" e_cs = 0x%4.4x\n", header.e_cs); + s->Printf(" e_lfarlc = 0x%4.4x\n", header.e_lfarlc); + s->Printf(" e_ovno = 0x%4.4x\n", header.e_ovno); + s->Printf(" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n", + header.e_res[0], header.e_res[1], header.e_res[2], header.e_res[3]); + s->Printf(" e_oemid = 0x%4.4x\n", header.e_oemid); + s->Printf(" e_oeminfo = 0x%4.4x\n", header.e_oeminfo); + s->Printf(" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, " + "0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n", + header.e_res2[0], header.e_res2[1], header.e_res2[2], + header.e_res2[3], header.e_res2[4], header.e_res2[5], + header.e_res2[6], header.e_res2[7], header.e_res2[8], + header.e_res2[9]); + s->Printf(" e_lfanew = 0x%8.8x\n", header.e_lfanew); } //---------------------------------------------------------------------- @@ -927,16 +839,14 @@ ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t& header) // // Dump the COFF header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t& header) -{ - s->PutCString ("COFF Header\n"); - s->Printf (" machine = 0x%4.4x\n", header.machine); - s->Printf (" nsects = 0x%4.4x\n", header.nsects); - s->Printf (" modtime = 0x%8.8x\n", header.modtime); - s->Printf (" symoff = 0x%8.8x\n", header.symoff); - s->Printf (" nsyms = 0x%8.8x\n", header.nsyms); - s->Printf (" hdrsize = 0x%4.4x\n", header.hdrsize); +void ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t &header) { + s->PutCString("COFF Header\n"); + s->Printf(" machine = 0x%4.4x\n", header.machine); + s->Printf(" nsects = 0x%4.4x\n", header.nsects); + s->Printf(" modtime = 0x%8.8x\n", header.modtime); + s->Printf(" symoff = 0x%8.8x\n", header.symoff); + s->Printf(" nsyms = 0x%8.8x\n", header.nsyms); + s->Printf(" hdrsize = 0x%4.4x\n", header.hdrsize); } //---------------------------------------------------------------------- @@ -944,147 +854,128 @@ ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t& header) // // Dump the optional COFF header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s, const coff_opt_header_t& header) -{ - s->PutCString ("Optional COFF Header\n"); - s->Printf (" magic = 0x%4.4x\n", header.magic); - s->Printf (" major_linker_version = 0x%2.2x\n", header.major_linker_version); - s->Printf (" minor_linker_version = 0x%2.2x\n", header.minor_linker_version); - s->Printf (" code_size = 0x%8.8x\n", header.code_size); - s->Printf (" data_size = 0x%8.8x\n", header.data_size); - s->Printf (" bss_size = 0x%8.8x\n", header.bss_size); - s->Printf (" entry = 0x%8.8x\n", header.entry); - s->Printf (" code_offset = 0x%8.8x\n", header.code_offset); - s->Printf (" data_offset = 0x%8.8x\n", header.data_offset); - s->Printf (" image_base = 0x%16.16" PRIx64 "\n", header.image_base); - s->Printf (" sect_alignment = 0x%8.8x\n", header.sect_alignment); - s->Printf (" file_alignment = 0x%8.8x\n", header.file_alignment); - s->Printf (" major_os_system_version = 0x%4.4x\n", header.major_os_system_version); - s->Printf (" minor_os_system_version = 0x%4.4x\n", header.minor_os_system_version); - s->Printf (" major_image_version = 0x%4.4x\n", header.major_image_version); - s->Printf (" minor_image_version = 0x%4.4x\n", header.minor_image_version); - s->Printf (" major_subsystem_version = 0x%4.4x\n", header.major_subsystem_version); - s->Printf (" minor_subsystem_version = 0x%4.4x\n", header.minor_subsystem_version); - s->Printf (" reserved1 = 0x%8.8x\n", header.reserved1); - s->Printf (" image_size = 0x%8.8x\n", header.image_size); - s->Printf (" header_size = 0x%8.8x\n", header.header_size); - s->Printf (" checksum = 0x%8.8x\n", header.checksum); - s->Printf (" subsystem = 0x%4.4x\n", header.subsystem); - s->Printf (" dll_flags = 0x%4.4x\n", header.dll_flags); - s->Printf (" stack_reserve_size = 0x%16.16" PRIx64 "\n", header.stack_reserve_size); - s->Printf (" stack_commit_size = 0x%16.16" PRIx64 "\n", header.stack_commit_size); - s->Printf (" heap_reserve_size = 0x%16.16" PRIx64 "\n", header.heap_reserve_size); - s->Printf (" heap_commit_size = 0x%16.16" PRIx64 "\n", header.heap_commit_size); - s->Printf (" loader_flags = 0x%8.8x\n", header.loader_flags); - s->Printf (" num_data_dir_entries = 0x%8.8x\n", (uint32_t)header.data_dirs.size()); - uint32_t i; - for (i=0; i<header.data_dirs.size(); i++) - { - s->Printf (" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n", - i, - header.data_dirs[i].vmaddr, - header.data_dirs[i].vmsize); - } +void ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s, + const coff_opt_header_t &header) { + s->PutCString("Optional COFF Header\n"); + s->Printf(" magic = 0x%4.4x\n", header.magic); + s->Printf(" major_linker_version = 0x%2.2x\n", + header.major_linker_version); + s->Printf(" minor_linker_version = 0x%2.2x\n", + header.minor_linker_version); + s->Printf(" code_size = 0x%8.8x\n", header.code_size); + s->Printf(" data_size = 0x%8.8x\n", header.data_size); + s->Printf(" bss_size = 0x%8.8x\n", header.bss_size); + s->Printf(" entry = 0x%8.8x\n", header.entry); + s->Printf(" code_offset = 0x%8.8x\n", header.code_offset); + s->Printf(" data_offset = 0x%8.8x\n", header.data_offset); + s->Printf(" image_base = 0x%16.16" PRIx64 "\n", + header.image_base); + s->Printf(" sect_alignment = 0x%8.8x\n", header.sect_alignment); + s->Printf(" file_alignment = 0x%8.8x\n", header.file_alignment); + s->Printf(" major_os_system_version = 0x%4.4x\n", + header.major_os_system_version); + s->Printf(" minor_os_system_version = 0x%4.4x\n", + header.minor_os_system_version); + s->Printf(" major_image_version = 0x%4.4x\n", + header.major_image_version); + s->Printf(" minor_image_version = 0x%4.4x\n", + header.minor_image_version); + s->Printf(" major_subsystem_version = 0x%4.4x\n", + header.major_subsystem_version); + s->Printf(" minor_subsystem_version = 0x%4.4x\n", + header.minor_subsystem_version); + s->Printf(" reserved1 = 0x%8.8x\n", header.reserved1); + s->Printf(" image_size = 0x%8.8x\n", header.image_size); + s->Printf(" header_size = 0x%8.8x\n", header.header_size); + s->Printf(" checksum = 0x%8.8x\n", header.checksum); + s->Printf(" subsystem = 0x%4.4x\n", header.subsystem); + s->Printf(" dll_flags = 0x%4.4x\n", header.dll_flags); + s->Printf(" stack_reserve_size = 0x%16.16" PRIx64 "\n", + header.stack_reserve_size); + s->Printf(" stack_commit_size = 0x%16.16" PRIx64 "\n", + header.stack_commit_size); + s->Printf(" heap_reserve_size = 0x%16.16" PRIx64 "\n", + header.heap_reserve_size); + s->Printf(" heap_commit_size = 0x%16.16" PRIx64 "\n", + header.heap_commit_size); + s->Printf(" loader_flags = 0x%8.8x\n", header.loader_flags); + s->Printf(" num_data_dir_entries = 0x%8.8x\n", + (uint32_t)header.data_dirs.size()); + uint32_t i; + for (i = 0; i < header.data_dirs.size(); i++) { + s->Printf(" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n", i, + header.data_dirs[i].vmaddr, header.data_dirs[i].vmsize); + } } //---------------------------------------------------------------------- // DumpSectionHeader // // Dump a single ELF section header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFilePECOFF::DumpSectionHeader(Stream *s, const section_header_t& sh) -{ - std::string name; - GetSectionName(name, sh); - s->Printf ("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x 0x%4.4x 0x%8.8x\n", - name.c_str(), - sh.vmaddr, - sh.vmsize, - sh.offset, - sh.size, - sh.reloff, - sh.lineoff, - sh.nreloc, - sh.nline, - sh.flags); +void ObjectFilePECOFF::DumpSectionHeader(Stream *s, + const section_header_t &sh) { + std::string name; + GetSectionName(name, sh); + s->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x " + "0x%4.4x 0x%8.8x\n", + name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff, + sh.lineoff, sh.nreloc, sh.nline, sh.flags); } - //---------------------------------------------------------------------- // DumpSectionHeaders // // Dump all of the ELF section header to the specified output stream //---------------------------------------------------------------------- -void -ObjectFilePECOFF::DumpSectionHeaders(Stream *s) -{ - - s->PutCString ("Section Headers\n"); - s->PutCString ("IDX name vm addr vm size file off file size reloc off line off nreloc nline flags\n"); - s->PutCString ("==== ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ------ ------ ----------\n"); - - uint32_t idx = 0; - SectionHeaderCollIter pos, end = m_sect_headers.end(); - - for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx) - { - s->Printf ("[%2u] ", idx); - ObjectFilePECOFF::DumpSectionHeader(s, *pos); - } -} - -bool -ObjectFilePECOFF::GetArchitecture (ArchSpec &arch) -{ - uint16_t machine = m_coff_header.machine; - switch (machine) - { - case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: - case llvm::COFF::IMAGE_FILE_MACHINE_I386: - case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC: - case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP: - case llvm::COFF::IMAGE_FILE_MACHINE_ARM: - case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: - case llvm::COFF::IMAGE_FILE_MACHINE_THUMB: - arch.SetArchitecture (eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE); - return true; - default: - break; - } - return false; +void ObjectFilePECOFF::DumpSectionHeaders(Stream *s) { + + s->PutCString("Section Headers\n"); + s->PutCString("IDX name vm addr vm size file off file " + "size reloc off line off nreloc nline flags\n"); + s->PutCString("==== ---------------- ---------- ---------- ---------- " + "---------- ---------- ---------- ------ ------ ----------\n"); + + uint32_t idx = 0; + SectionHeaderCollIter pos, end = m_sect_headers.end(); + + for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx) { + s->Printf("[%2u] ", idx); + ObjectFilePECOFF::DumpSectionHeader(s, *pos); + } +} + +bool ObjectFilePECOFF::GetArchitecture(ArchSpec &arch) { + uint16_t machine = m_coff_header.machine; + switch (machine) { + case llvm::COFF::IMAGE_FILE_MACHINE_AMD64: + case llvm::COFF::IMAGE_FILE_MACHINE_I386: + case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC: + case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP: + case llvm::COFF::IMAGE_FILE_MACHINE_ARM: + case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT: + case llvm::COFF::IMAGE_FILE_MACHINE_THUMB: + arch.SetArchitecture(eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE); + return true; + default: + break; + } + return false; } -ObjectFile::Type -ObjectFilePECOFF::CalculateType() -{ - if (m_coff_header.machine != 0) - { - if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0) - return eTypeExecutable; - else - return eTypeSharedLibrary; - } - return eTypeExecutable; +ObjectFile::Type ObjectFilePECOFF::CalculateType() { + if (m_coff_header.machine != 0) { + if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0) + return eTypeExecutable; + else + return eTypeSharedLibrary; + } + return eTypeExecutable; } -ObjectFile::Strata -ObjectFilePECOFF::CalculateStrata() -{ - return eStrataUser; -} +ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -ConstString -ObjectFilePECOFF::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -ObjectFilePECOFF::GetPluginVersion() -{ - return 1; -} +ConstString ObjectFilePECOFF::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ObjectFilePECOFF::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index 6c1cdbf56c6..2031382a1e1 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -18,290 +18,262 @@ // Project includes #include "lldb/Symbol/ObjectFile.h" -class ObjectFilePECOFF : - public lldb_private::ObjectFile -{ +class ObjectFilePECOFF : public lldb_private::ObjectFile { public: - typedef enum MachineType - { - MachineUnknown = 0x0, - MachineAm33 = 0x1d3, - MachineAmd64 = 0x8664, - MachineArm = 0x1c0, - MachineArmNt = 0x1c4, - MachineArm64 = 0xaa64, - MachineEbc = 0xebc, - MachineX86 = 0x14c, - MachineIA64 = 0x200, - MachineM32R = 0x9041, - MachineMips16 = 0x266, - MachineMipsFpu = 0x366, - MachineMipsFpu16 = 0x466, - MachinePowerPc = 0x1f0, - MachinePowerPcfp = 0x1f1, - MachineR4000 = 0x166, - MachineSh3 = 0x1a2, - MachineSh3dsp = 0x1a3, - MachineSh4 = 0x1a6, - MachineSh5 = 0x1a8, - MachineThumb = 0x1c2, - MachineWcemIpsv2 = 0x169 - } MachineType; - - ObjectFilePECOFF(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t file_offset, - lldb::offset_t length); - - ~ObjectFilePECOFF() override; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static const char * - GetPluginDescriptionStatic(); - - static ObjectFile * - CreateInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - const lldb_private::FileSpec* file, - lldb::offset_t offset, - lldb::offset_t length); - - static lldb_private::ObjectFile * - CreateMemoryInstance (const lldb::ModuleSP &module_sp, - lldb::DataBufferSP& data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - static size_t - GetModuleSpecifications (const lldb_private::FileSpec& file, - lldb::DataBufferSP& data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - lldb_private::ModuleSpecList &specs); - - static bool - SaveCore (const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb_private::Error &error); - - static bool - MagicBytesMatch (lldb::DataBufferSP& data_sp); - - static lldb::SymbolType - MapSymbolType(uint16_t coff_symbol_type); - - bool - ParseHeader() override; - - bool - SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, bool value_is_offset) override; - - lldb::ByteOrder - GetByteOrder() const override; - - bool - IsExecutable() const override; - - uint32_t - GetAddressByteSize() const override; - -// virtual lldb_private::AddressClass -// GetAddressClass (lldb::addr_t file_addr); - - lldb_private::Symtab * - GetSymtab() override; - - bool - IsStripped() override; - - void - CreateSections(lldb_private::SectionList &unified_section_list) override; - - void - Dump(lldb_private::Stream *s) override; - - bool - GetArchitecture(lldb_private::ArchSpec &arch) override; - - bool - GetUUID(lldb_private::UUID* uuid) override; - - uint32_t - GetDependentModules(lldb_private::FileSpecList& files) override; - - virtual lldb_private::Address - GetEntryPointAddress () override; - - ObjectFile::Type - CalculateType() override; - - ObjectFile::Strata - CalculateStrata() override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; + typedef enum MachineType { + MachineUnknown = 0x0, + MachineAm33 = 0x1d3, + MachineAmd64 = 0x8664, + MachineArm = 0x1c0, + MachineArmNt = 0x1c4, + MachineArm64 = 0xaa64, + MachineEbc = 0xebc, + MachineX86 = 0x14c, + MachineIA64 = 0x200, + MachineM32R = 0x9041, + MachineMips16 = 0x266, + MachineMipsFpu = 0x366, + MachineMipsFpu16 = 0x466, + MachinePowerPc = 0x1f0, + MachinePowerPcfp = 0x1f1, + MachineR4000 = 0x166, + MachineSh3 = 0x1a2, + MachineSh3dsp = 0x1a3, + MachineSh4 = 0x1a6, + MachineSh5 = 0x1a8, + MachineThumb = 0x1c2, + MachineWcemIpsv2 = 0x169 + } MachineType; + + ObjectFilePECOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + const lldb_private::FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + ~ObjectFilePECOFF() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const lldb_private::FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + + static lldb_private::ObjectFile *CreateMemoryInstance( + const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + lldb_private::ModuleSpecList &specs); + + static bool SaveCore(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error); + + static bool MagicBytesMatch(lldb::DataBufferSP &data_sp); + + static lldb::SymbolType MapSymbolType(uint16_t coff_symbol_type); + + bool ParseHeader() override; + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb::ByteOrder GetByteOrder() const override; + + bool IsExecutable() const override; + + uint32_t GetAddressByteSize() const override; + + // virtual lldb_private::AddressClass + // GetAddressClass (lldb::addr_t file_addr); + + lldb_private::Symtab *GetSymtab() override; + + bool IsStripped() override; + + void CreateSections(lldb_private::SectionList &unified_section_list) override; + + void Dump(lldb_private::Stream *s) override; + + bool GetArchitecture(lldb_private::ArchSpec &arch) override; + + bool GetUUID(lldb_private::UUID *uuid) override; + + uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; + + virtual lldb_private::Address GetEntryPointAddress() override; + + ObjectFile::Type CalculateType() override; + + ObjectFile::Strata CalculateStrata() override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; protected: - bool NeedsEndianSwap() const; - - typedef struct dos_header { // DOS .EXE header - uint16_t e_magic; // Magic number - uint16_t e_cblp; // Bytes on last page of file - uint16_t e_cp; // Pages in file - uint16_t e_crlc; // Relocations - uint16_t e_cparhdr; // Size of header in paragraphs - uint16_t e_minalloc; // Minimum extra paragraphs needed - uint16_t e_maxalloc; // Maximum extra paragraphs needed - uint16_t e_ss; // Initial (relative) SS value - uint16_t e_sp; // Initial SP value - uint16_t e_csum; // Checksum - uint16_t e_ip; // Initial IP value - uint16_t e_cs; // Initial (relative) CS value - uint16_t e_lfarlc; // File address of relocation table - uint16_t e_ovno; // Overlay number - uint16_t e_res[4]; // Reserved words - uint16_t e_oemid; // OEM identifier (for e_oeminfo) - uint16_t e_oeminfo; // OEM information; e_oemid specific - uint16_t e_res2[10]; // Reserved words - uint32_t e_lfanew; // File address of new exe header - } dos_header_t; - - typedef struct coff_header { - uint16_t machine; - uint16_t nsects; - uint32_t modtime; - uint32_t symoff; - uint32_t nsyms; - uint16_t hdrsize; - uint16_t flags; - } coff_header_t; - - typedef struct data_directory { - uint32_t vmaddr; - uint32_t vmsize; - } data_directory_t; - - typedef struct coff_opt_header - { - uint16_t magic; - uint8_t major_linker_version; - uint8_t minor_linker_version; - uint32_t code_size; - uint32_t data_size; - uint32_t bss_size; - uint32_t entry; - uint32_t code_offset; - uint32_t data_offset; - - uint64_t image_base; - uint32_t sect_alignment; - uint32_t file_alignment; - uint16_t major_os_system_version; - uint16_t minor_os_system_version; - uint16_t major_image_version; - uint16_t minor_image_version; - uint16_t major_subsystem_version; - uint16_t minor_subsystem_version; - uint32_t reserved1; - uint32_t image_size; - uint32_t header_size; - uint32_t checksum; - uint16_t subsystem; - uint16_t dll_flags; - uint64_t stack_reserve_size; - uint64_t stack_commit_size; - uint64_t heap_reserve_size; - uint64_t heap_commit_size; - uint32_t loader_flags; - // uint32_t num_data_dir_entries; - std::vector<data_directory> data_dirs; // will contain num_data_dir_entries entries - } coff_opt_header_t; - - typedef enum coff_data_dir_type - { - coff_data_dir_export_table = 0, - coff_data_dir_import_table = 1, - } coff_data_dir_type; - - typedef struct section_header { - char name[8]; - uint32_t vmsize; // Virtual Size - uint32_t vmaddr; // Virtual Addr - uint32_t size; // File size - uint32_t offset; // File offset - uint32_t reloff; // Offset to relocations - uint32_t lineoff;// Offset to line table entries - uint16_t nreloc; // Number of relocation entries - uint16_t nline; // Number of line table entries - uint32_t flags; - } section_header_t; - - typedef struct coff_symbol { - char name[8]; - uint32_t value; - uint16_t sect; - uint16_t type; - uint8_t storage; - uint8_t naux; - } coff_symbol_t; - - typedef struct export_directory_entry { - uint32_t characteristics; - uint32_t time_date_stamp; - uint16_t major_version; - uint16_t minor_version; - uint32_t name; - uint32_t base; - uint32_t number_of_functions; - uint32_t number_of_names; - uint32_t address_of_functions; - uint32_t address_of_names; - uint32_t address_of_name_ordinals; - } export_directory_entry; - - static bool ParseDOSHeader (lldb_private::DataExtractor &data, dos_header_t &dos_header); - static bool ParseCOFFHeader (lldb_private::DataExtractor &data, lldb::offset_t *offset_ptr, coff_header_t &coff_header); - bool ParseCOFFOptionalHeader (lldb::offset_t *offset_ptr); - bool ParseSectionHeaders (uint32_t offset); - - static void DumpDOSHeader(lldb_private::Stream *s, const dos_header_t& header); - static void DumpCOFFHeader(lldb_private::Stream *s, const coff_header_t& header); - static void DumpOptCOFFHeader(lldb_private::Stream *s, const coff_opt_header_t& header); - void DumpSectionHeaders(lldb_private::Stream *s); - void DumpSectionHeader(lldb_private::Stream *s, const section_header_t& sh); - bool GetSectionName(std::string& sect_name, const section_header_t& sect); - - typedef std::vector<section_header_t> SectionHeaderColl; - typedef SectionHeaderColl::iterator SectionHeaderCollIter; - typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; + bool NeedsEndianSwap() const; + + typedef struct dos_header { // DOS .EXE header + uint16_t e_magic; // Magic number + uint16_t e_cblp; // Bytes on last page of file + uint16_t e_cp; // Pages in file + uint16_t e_crlc; // Relocations + uint16_t e_cparhdr; // Size of header in paragraphs + uint16_t e_minalloc; // Minimum extra paragraphs needed + uint16_t e_maxalloc; // Maximum extra paragraphs needed + uint16_t e_ss; // Initial (relative) SS value + uint16_t e_sp; // Initial SP value + uint16_t e_csum; // Checksum + uint16_t e_ip; // Initial IP value + uint16_t e_cs; // Initial (relative) CS value + uint16_t e_lfarlc; // File address of relocation table + uint16_t e_ovno; // Overlay number + uint16_t e_res[4]; // Reserved words + uint16_t e_oemid; // OEM identifier (for e_oeminfo) + uint16_t e_oeminfo; // OEM information; e_oemid specific + uint16_t e_res2[10]; // Reserved words + uint32_t e_lfanew; // File address of new exe header + } dos_header_t; + + typedef struct coff_header { + uint16_t machine; + uint16_t nsects; + uint32_t modtime; + uint32_t symoff; + uint32_t nsyms; + uint16_t hdrsize; + uint16_t flags; + } coff_header_t; + + typedef struct data_directory { + uint32_t vmaddr; + uint32_t vmsize; + } data_directory_t; + + typedef struct coff_opt_header { + uint16_t magic; + uint8_t major_linker_version; + uint8_t minor_linker_version; + uint32_t code_size; + uint32_t data_size; + uint32_t bss_size; + uint32_t entry; + uint32_t code_offset; + uint32_t data_offset; + + uint64_t image_base; + uint32_t sect_alignment; + uint32_t file_alignment; + uint16_t major_os_system_version; + uint16_t minor_os_system_version; + uint16_t major_image_version; + uint16_t minor_image_version; + uint16_t major_subsystem_version; + uint16_t minor_subsystem_version; + uint32_t reserved1; + uint32_t image_size; + uint32_t header_size; + uint32_t checksum; + uint16_t subsystem; + uint16_t dll_flags; + uint64_t stack_reserve_size; + uint64_t stack_commit_size; + uint64_t heap_reserve_size; + uint64_t heap_commit_size; + uint32_t loader_flags; + // uint32_t num_data_dir_entries; + std::vector<data_directory> + data_dirs; // will contain num_data_dir_entries entries + } coff_opt_header_t; + + typedef enum coff_data_dir_type { + coff_data_dir_export_table = 0, + coff_data_dir_import_table = 1, + } coff_data_dir_type; + + typedef struct section_header { + char name[8]; + uint32_t vmsize; // Virtual Size + uint32_t vmaddr; // Virtual Addr + uint32_t size; // File size + uint32_t offset; // File offset + uint32_t reloff; // Offset to relocations + uint32_t lineoff; // Offset to line table entries + uint16_t nreloc; // Number of relocation entries + uint16_t nline; // Number of line table entries + uint32_t flags; + } section_header_t; + + typedef struct coff_symbol { + char name[8]; + uint32_t value; + uint16_t sect; + uint16_t type; + uint8_t storage; + uint8_t naux; + } coff_symbol_t; + + typedef struct export_directory_entry { + uint32_t characteristics; + uint32_t time_date_stamp; + uint16_t major_version; + uint16_t minor_version; + uint32_t name; + uint32_t base; + uint32_t number_of_functions; + uint32_t number_of_names; + uint32_t address_of_functions; + uint32_t address_of_names; + uint32_t address_of_name_ordinals; + } export_directory_entry; + + static bool ParseDOSHeader(lldb_private::DataExtractor &data, + dos_header_t &dos_header); + static bool ParseCOFFHeader(lldb_private::DataExtractor &data, + lldb::offset_t *offset_ptr, + coff_header_t &coff_header); + bool ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr); + bool ParseSectionHeaders(uint32_t offset); + + static void DumpDOSHeader(lldb_private::Stream *s, + const dos_header_t &header); + static void DumpCOFFHeader(lldb_private::Stream *s, + const coff_header_t &header); + static void DumpOptCOFFHeader(lldb_private::Stream *s, + const coff_opt_header_t &header); + void DumpSectionHeaders(lldb_private::Stream *s); + void DumpSectionHeader(lldb_private::Stream *s, const section_header_t &sh); + bool GetSectionName(std::string §_name, const section_header_t §); + + typedef std::vector<section_header_t> SectionHeaderColl; + typedef SectionHeaderColl::iterator SectionHeaderCollIter; + typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; + private: - dos_header_t m_dos_header; - coff_header_t m_coff_header; - coff_opt_header_t m_coff_header_opt; - SectionHeaderColl m_sect_headers; - lldb::addr_t m_image_base; - lldb_private::Address m_entry_point_address; + dos_header_t m_dos_header; + coff_header_t m_coff_header; + coff_opt_header_t m_coff_header_opt; + SectionHeaderColl m_sect_headers; + lldb::addr_t m_image_base; + lldb_private::Address m_entry_point_address; }; #endif // liblldb_ObjectFilePECOFF_h_ diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp index 14c73eff238..1e3ad68b36a 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp @@ -16,41 +16,44 @@ #ifdef _WIN32 #include "lldb/Host/windows/windows.h" -#include <DbgHelp.h> // for MiniDumpWriteDump +#include <DbgHelp.h> // for MiniDumpWriteDump #endif namespace lldb_private { -bool -SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb_private::Error &error) -{ - if (!process_sp) return false; +bool SaveMiniDump(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error) { + if (!process_sp) + return false; #ifdef _WIN32 - HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID()); - const std::string file_name = outfile.GetCString(); - std::wstring wide_name; - wide_name.resize(file_name.size() + 1); - char * result_ptr = reinterpret_cast<char *>(&wide_name[0]); - const UTF8 *error_ptr = nullptr; - if (!llvm::ConvertUTF8toWide(sizeof(wchar_t), file_name, result_ptr, error_ptr)) { - error.SetErrorString("cannot convert file name"); - return false; - } - HANDLE file_handle = ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - const auto result = ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle, - MiniDumpWithFullMemoryInfo, NULL, NULL, NULL); - ::CloseHandle(file_handle); - ::CloseHandle(process_handle); - if (!result) - { - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - return false; - } - return true; -#endif + HANDLE process_handle = ::OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID()); + const std::string file_name = outfile.GetCString(); + std::wstring wide_name; + wide_name.resize(file_name.size() + 1); + char *result_ptr = reinterpret_cast<char *>(&wide_name[0]); + const UTF8 *error_ptr = nullptr; + if (!llvm::ConvertUTF8toWide(sizeof(wchar_t), file_name, result_ptr, + error_ptr)) { + error.SetErrorString("cannot convert file name"); return false; + } + HANDLE file_handle = + ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + const auto result = + ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle, + MiniDumpWithFullMemoryInfo, NULL, NULL, NULL); + ::CloseHandle(file_handle); + ::CloseHandle(process_handle); + if (!result) { + error.SetError(::GetLastError(), lldb::eErrorTypeWin32); + return false; + } + return true; +#endif + return false; } -} // namesapce lldb_private +} // namesapce lldb_private diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h index cbea88af1fb..3f741dc04f5 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h @@ -14,11 +14,10 @@ namespace lldb_private { -bool -SaveMiniDump(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb_private::Error &error); +bool SaveMiniDump(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error); -} // namespace lldb_private +} // namespace lldb_private #endif |