llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp

2924 lines
107 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- ObjectFileELF.cpp ------------------------------------- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ObjectFileELF.h"
#include <cassert>
#include <algorithm>
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Host/HostInfo.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MathExtras.h"
#define CASE_AND_STREAM(s, def, width) \
case def: s->Printf("%-*s", width, #def); break;
using namespace lldb;
using namespace lldb_private;
using namespace elf;
using namespace llvm::ELF;
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_ANDROID = "Android";
// ELF note type definitions
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_BUILD_ID_TAG = 0x03;
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_SOLARIS = 0x02;
//===----------------------------------------------------------------------===//
/// @class ELFRelocation
/// @brief Generic wrapper for ELFRel and ELFRela.
///
/// This helper class allows us to parse both ELFRel and ELFRela relocation
/// entries in a generic manner.
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);
~ELFRelocation();
bool
Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
static unsigned
RelocType32(const ELFRelocation &rel);
static unsigned
RelocType64(const ELFRelocation &rel);
static unsigned
RelocSymbol32(const ELFRelocation &rel);
static unsigned
RelocSymbol64(const ELFRelocation &rel);
static unsigned
RelocOffset32(const ELFRelocation &rel);
static unsigned
RelocOffset64(const ELFRelocation &rel);
static unsigned
RelocAddend32(const ELFRelocation &rel);
static unsigned
RelocAddend64(const ELFRelocation &rel);
private:
typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion;
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()
{
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);
}
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::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::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::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;
}
} // 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::RoundUpToAlignment (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 = LLDB_INVALID_CPUTYPE;
switch (mips_arch)
{
case llvm::ELF::EF_MIPS_ARCH_64:
if (endian == ELFDATA2LSB)
arch_variant = llvm::Triple::mips64el;
else
arch_variant = llvm::Triple::mips64;
break;
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;
}
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;
}
return eSectionTypeOther;
}
// Arbitrary constant used as UUID prefix for core files.
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;
}
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;
}
/*
* crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c
*
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
static uint32_t
calc_crc32(uint32_t crc, const void *buf, size_t size)
{
static const uint32_t g_crc32_tab[] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
const uint8_t *p = (const uint8_t *)buf;
crc = crc ^ ~0U;
while (size--)
crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
static uint32_t
calc_gnu_debuglink_crc32(const void *buf, size_t size)
{
return calc_crc32(0U, buf, size);
}
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
}
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);
if (spec.GetArchitecture().IsValid())
{
llvm::Triple::OSType ostype;
// First try to determine the OS type from the OSABI field in the elf header.
if (log)
log->Printf ("ObjectFileELF::%s file '%s' module OSABI: %s", __FUNCTION__, file.GetPath ().c_str (), OSABIAsCString (header.e_ident[EI_OSABI]));
if (GetOsFromOSABI (header.e_ident[EI_OSABI], ostype) && ostype != llvm::Triple::OSType::UnknownOS)
{
spec.GetArchitecture ().GetTriple ().setOS (ostype);
// Also clear the vendor so we don't end up with situations like
// x86_64-apple-FreeBSD.
spec.GetArchitecture ().GetTriple ().setVendor (llvm::Triple::VendorType::UnknownVendor);
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();
GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture ());
// If the module vendor is not set and the module OS matches this host OS, set the module vendor to the host vendor.
llvm::Triple &spec_triple = spec.GetArchitecture ().GetTriple ();
if (spec_triple.getVendor () == llvm::Triple::VendorType::UnknownVendor)
{
const llvm::Triple &host_triple = HostInfo::GetArchitecture().GetTriple();
if (spec_triple.getOS () == host_triple.getOS ())
spec_triple.setVendor (host_triple.getVendor ());
}
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 (__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, 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;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString
ObjectFileELF::GetPluginName()
{
return GetPluginNameStatic();
}
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& data_sp,
const lldb::ProcessSP &process_sp,
addr_t header_addr) :
ObjectFile(module_sp, process_sp, LLDB_INVALID_ADDRESS, 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)
{
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 (section_sp && section_sp->Test(SHF_ALLOC))
{
if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
++num_loaded_sections;
}
}
return num_loaded_sections > 0;
}
else
{
// Not sure how to slide an ELF file given the base address
// of the ELF file in memory
}
}
}
return false; // If it changed
}
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();
}
// Top 16 bits of the `Symbol` flags are available.
#define ARM_ELF_SYM_IS_THUMB (1 << 16)
AddressClass
ObjectFileELF::GetAddressClass (addr_t file_addr)
{
auto res = ObjectFile::GetAddressClass (file_addr);
if (res != eAddressClassCode)
return res;
ArchSpec arch_spec;
GetArchitecture(arch_spec);
if (arch_spec.GetMachine() != llvm::Triple::arm)
return res;
auto symtab = GetSymtab();
if (symtab == nullptr)
return res;
auto symbol = symtab->FindSymbolContainingFileAddress(file_addr);
if (symbol == nullptr)
return res;
// Thumb symbols have the lower bit set in the flags field so we just check
// for that.
if (symbol->GetFlags() & ARM_ELF_SYM_IS_THUMB)
res = eAddressClassCodeAlternateISA;
return res;
}
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;
}
bool
ObjectFileELF::ParseHeader()
{
lldb::offset_t offset = 0;
return m_header.Parse(m_data, &offset);
}
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())
{
*uuid = m_uuid;
return true;
}
return false;
}
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;
}
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++;
}
return num_specs;
}
Address
ObjectFileELF::GetImageInfoAddress(Target *target)
{
if (!ParseDynamicSymbols())
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);
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];
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);
}
else if (symbol.d_tag == DT_MIPS_RLD_MAP && 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();
Address addr;
Error error;
if (target->ReadPointerFromMemory(dyn_base + offset, false, error, addr))
return addr;
}
}
return 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;
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;
}
//----------------------------------------------------------------------
// ParseDependentModules
//----------------------------------------------------------------------
size_t
ObjectFileELF::ParseDependentModules()
{
if (m_filespec_ap.get())
return m_filespec_ap->GetSize();
m_filespec_ap.reset(new FileSpecList());
if (!ParseSectionHeaders())
return 0;
SectionList *section_list = GetSectionList();
if (!section_list)
return 0;
// Find the SHT_DYNAMIC section.
Section *dynsym = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
if (!dynsym)
return 0;
assert (dynsym->GetObjectFile() == this);
const ELFSectionHeaderInfo *header = GetSectionHeaderByIndex (dynsym->GetID());
if (!header)
return 0;
// sh_link: section header index of string table used by entries in the section.
Section *dynstr = section_list->FindSectionByID (header->sh_link + 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();
}
//----------------------------------------------------------------------
// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t
ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
DataExtractor &object_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 (data.SetData(object_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()
{
return GetProgramHeaderInfo(m_program_headers, m_data, 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;
lldb::offset_t offset = 0;
while (true)
{
// Parse the note header. If this fails, bail out.
ELFNote note = ELFNote();
if (!note.Parse(data, &offset))
{
// We're done.
return error;
}
// If a tag processor handles the tag, it should set processed to true, and
// the loop will assume the tag processing has moved entirely past the note's payload.
// Otherwise, leave it false and the end of the loop will handle the offset properly.
bool processed = false;
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))
{
// We'll consume the payload below.
processed = true;
// 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)
{
// We'll consume the payload below.
processed = true;
// 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())
{
// We'll consume the payload below.
processed = true;
// 16 bytes is UUID|MD5, 20 bytes is SHA1
if ((note.n_descsz == 16 || 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))
{
// We'll consume the payload below.
processed = true;
// 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))
{
// We'll consume the payload below.
processed = true;
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::RoundUpToAlignment (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);
}
if (!processed)
offset += llvm::RoundUpToAlignment(note.n_descsz, 4);
}
return error;
}
//----------------------------------------------------------------------
// GetSectionHeaderInfo
//----------------------------------------------------------------------
size_t
ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
lldb_private::DataExtractor &object_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)
{
const uint32_t sub_type = subTypeFromElfHeader(header);
arch_spec.SetArchitecture (eArchTypeELF, header.e_machine, sub_type);
switch (arch_spec.GetAddressByteSize())
{
case 4:
{
const ArchSpec host_arch32 = HostInfo::GetArchitecture(HostInfo::eArchKind32);
if (host_arch32.GetCore() == arch_spec.GetCore())
{
arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data());
arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data());
}
}
break;
case 8:
{
const ArchSpec host_arch64 = HostInfo::GetArchitecture(HostInfo::eArchKind64);
if (host_arch64.GetCore() == arch_spec.GetCore())
{
arch_spec.GetTriple().setOSName(HostInfo::GetOSString().data());
arch_spec.GetTriple().setVendorName(HostInfo::GetVendorString().data());
}
}
break;
}
}
// If there are no section headers we are done.
if (header.e_shnum == 0)
return 0;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MODULES));
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 (sh_data.SetData (object_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)
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 (shstr_data.SetData (object_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 &header = *I;
const uint64_t section_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
ConstString name(shstr_data.PeekCStr(I->sh_name));
I->section_name = name;
if (name == g_sect_name_gnu_debuglink)
{
DataExtractor data;
if (section_size && (data.SetData (object_data, header.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::RoundUpToAlignment (gnu_debuglink_offset, 4);
data.GetU32 (&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
}
}
// Process ELF note section entries.
bool is_note_header = (header.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 && (data.SetData (object_data, header.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 ());
}
}
}
}
return section_headers.size();
}
}
section_headers.clear();
return 0;
}
size_t
ObjectFileELF::GetProgramHeaderCount()
{
return ParseProgramHeaders();
}
const elf::ELFProgramHeader *
ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id)
{
if (!id || !ParseProgramHeaders())
return NULL;
if (--id < m_program_headers.size())
return &m_program_headers[id];
return NULL;
}
DataExtractor
ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
{
const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id);
if (segment_header == NULL)
return DataExtractor();
return DataExtractor(m_data, segment_header->p_offset, segment_header->p_filesz);
}
std::string
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()
{
return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
}
const ObjectFileELF::ELFSectionHeaderInfo *
ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
{
if (!id || !ParseSectionHeaders())
return NULL;
if (--id < m_section_headers.size())
return &m_section_headers[id];
return NULL;
}
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_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");
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_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_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_eh_frame) sect_type = eSectionTypeEHFrame;
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
// supports linkscripts which (can) give rise to various arbitarily 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
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[] =
{
eSectionTypeDWARFDebugAranges,
eSectionTypeDWARFDebugInfo,
eSectionTypeDWARFDebugAbbrev,
eSectionTypeDWARFDebugFrame,
eSectionTypeDWARFDebugLine,
eSectionTypeDWARFDebugStr,
eSectionTypeDWARFDebugLoc,
eSectionTypeDWARFDebugMacInfo,
eSectionTypeDWARFDebugPubNames,
eSectionTypeDWARFDebugPubTypes,
eSectionTypeDWARFDebugRanges,
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;
}
}
}
// 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;
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
//StreamFile strm(stdout, false);
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);
// No need to add non-section symbols that have no names
if (symbol.getType() != STT_SECTION &&
(symbol_name == NULL || symbol_name[0] == '\0'))
continue;
//symbol.Dump (&strm, i, &strtab_data, section_list);
SectionSP symbol_section_sp;
SymbolType symbol_type = eSymbolTypeInvalid;
Elf64_Half symbol_idx = symbol.st_shndx;
switch (symbol_idx)
{
case SHN_ABS:
symbol_type = eSymbolTypeAbsolute;
break;
case SHN_UNDEF:
symbol_type = eSymbolTypeUndefined;
break;
default:
symbol_section_sp = section_list->GetSectionAtIndex(symbol_idx);
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;
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)
{
if (symbol_section_sp)
{
const ConstString &sect_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;
}
}
}
ArchSpec arch;
int64_t symbol_value_offset = 0;
uint32_t additional_flags = 0;
if (GetArchitecture(arch) &&
arch.GetMachine() == llvm::Triple::arm)
{
// ELF symbol tables may contain some mapping symbols. They provide
// information about the underlying data. There are three of them
// currently defined:
// $a[.<any>]* - marks an ARM instruction sequence
// $t[.<any>]* - marks a THUMB instruction sequence
// $d[.<any>]* - marks a data item sequence (e.g. lit pool)
// These symbols interfere with normal debugger operations and we
// don't need them. We can drop them here.
static const llvm::StringRef g_armelf_arm_marker("$a");
static const llvm::StringRef g_armelf_thumb_marker("$t");
static const llvm::StringRef g_armelf_data_marker("$d");
llvm::StringRef symbol_name_ref(symbol_name);
if (symbol_name &&
(symbol_name_ref.startswith(g_armelf_arm_marker) ||
symbol_name_ref.startswith(g_armelf_thumb_marker) ||
symbol_name_ref.startswith(g_armelf_data_marker)))
continue;
// THUMB functions have the lower bit of their address set. Fixup
// the actual address and mark the symbol as THUMB.
if (symbol_type == eSymbolTypeCode && symbol.st_value & 1)
{
// Substracting 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 conjuction with
// symbol.st_value to produce the final symbol_value
// that we store in the symtab.
symbol_value_offset = -1;
additional_flags = ARM_ELF_SYM_IS_THUMB;
}
}
// If the symbol section we've found has no data (SHT_NOBITS), then check the module section
// list. This can happen if we're parsing the debug file and it has no .text section, for example.
if (symbol_section_sp && (symbol_section_sp->GetFileSize() == 0))
{
ModuleSP module_sp(GetModule());
if (module_sp)
{
SectionList *module_section_list = module_sp->GetSectionList();
if (module_section_list && module_section_list != section_list)
{
const ConstString &sect_name = symbol_section_sp->GetName();
lldb::SectionSP section_sp (module_section_list->FindSectionByName (sect_name));
if (section_sp && section_sp->GetFileSize())
{
symbol_section_sp = section_sp;
}
}
}
}
// 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 && CalculateType() != ObjectFile::Type::eTypeObjectFile)
symbol_value -= symbol_section_sp->GetFileAddress();
bool is_global = symbol.getBinding() == STB_GLOBAL;
uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags;
bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
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 sucessful (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()) );
llvm::StringRef demangled_name = mangled.GetDemangledName().GetStringRef();
if (! demangled_name.empty())
mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) );
}
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.
true, // 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;
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);
}
}
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);
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;
m_dynamic_symbols.push_back(symbol);
}
}
return m_dynamic_symbols.size();
}
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;
if (symbol->d_tag == tag)
return symbol;
}
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;
return 0;
}
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;
// 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.
const elf_xword plt_entsize = plt_hdr->sh_addralign ?
llvm::RoundUpToAlignment (plt_hdr->sh_entsize, plt_hdr->sh_addralign) : plt_hdr->sh_entsize;
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;
uint64_t plt_index = (i + 1) * plt_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;
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,
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. The info field
// points to the section holding the plt.
user_id_t symtab_id = rel_hdr->sh_link;
user_id_t plt_id = rel_hdr->sh_info;
if (!symtab_id || !plt_id)
return 0;
// Section ID's are ones based;
symtab_id++;
plt_id++;
const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id);
if (!plt_hdr)
return 0;
const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id);
if (!sym_hdr)
return 0;
SectionList *section_list = m_sections_ap.get();
if (!section_list)
return 0;
Section *rel_section = section_list->FindSectionByID(rel_id).get();
if (!rel_section)
return 0;
SectionSP plt_section_sp (section_list->FindSectionByID(plt_id));
if (!plt_section_sp)
return 0;
Section *symtab = section_list->FindSectionByID(symtab_id).get();
if (!symtab)
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 rel_data;
if (!ReadSectionData(rel_section, rel_data))
return 0;
DataExtractor symtab_data;
if (!ReadSectionData(symtab, symtab_data))
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);
}
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->GetAddress().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->GetAddress().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;
}
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;
// 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 *debug_hdr = GetSectionHeaderByIndex(debug_id);
if (!debug_hdr)
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 *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);
}
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;
lldb_private::Mutex::Locker locker(module_sp->GetMutex());
m_symtab_ap.reset(new Symtab(this));
// 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)
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);
ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id);
}
}
}
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();
}
Symbol *
ObjectFileELF::ResolveSymbolForAddress(const Address& so_addr, bool verify_unique)
{
if (!m_symtab_ap.get())
return nullptr; // GetSymtab() should be called first.
const SectionList *section_list = GetSectionList();
if (!section_list)
return nullptr;
if (DWARFCallFrameInfo *eh_frame = GetUnwindTable().GetEHFrameInfo())
{
AddressRange range;
if (eh_frame->GetAddressRange (so_addr, range))
{
const addr_t file_addr = range.GetBaseAddress().GetFileAddress();
Symbol * symbol = verify_unique ? m_symtab_ap->FindSymbolContainingFileAddress(file_addr) : nullptr;
if (symbol)
return symbol;
// Note that a (stripped) symbol won't be found by GetSymtab()...
lldb::SectionSP eh_sym_section_sp = section_list->FindSectionContainingFileAddress(file_addr);
if (eh_sym_section_sp.get())
{
addr_t section_base = eh_sym_section_sp->GetFileAddress();
addr_t offset = file_addr - section_base;
uint64_t symbol_id = m_symtab_ap->GetNumSymbols();
Symbol eh_symbol(
symbol_id, // Symbol table index.
"???", // 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?
eh_sym_section_sp, // Section in which this symbol is defined or null.
offset, // Offset in section or symbol value.
range.GetByteSize(), // Size in bytes of this symbol.
true, // Size is valid.
false, // Contains linker annotations?
0); // Symbol flags.
if (symbol_id == m_symtab_ap->AddSymbol(eh_symbol))
return m_symtab_ap->SymbolAtIndex(symbol_id);
}
}
}
return nullptr;
}
bool
ObjectFileELF::IsStripped ()
{
// TODO: determine this for ELF
return false;
}
//===----------------------------------------------------------------------===//
// Dump
//
// Dump the specifics of the runtime file container (such as any headers
// segments, sections, etc).
//----------------------------------------------------------------------
void
ObjectFileELF::Dump(Stream *s)
{
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();
}
//----------------------------------------------------------------------
// DumpELFHeader
//
// 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);
}
//----------------------------------------------------------------------
// DumpELFHeader_e_type
//
// 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;
}
}
//----------------------------------------------------------------------
// DumpELFHeader_e_ident_EI_DATA
//
// 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;
}
}
//----------------------------------------------------------------------
// 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);
DumpELFProgramHeader_p_flags(s, ph.p_flags);
s->Printf(") %8.8" PRIx64, ph.p_align);
}
//----------------------------------------------------------------------
// DumpELFProgramHeader_p_type
//
// 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);
CASE_AND_STREAM(s, PT_GNU_EH_FRAME, kStrWidth);
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" : " ");
}
//----------------------------------------------------------------------
// DumpELFProgramHeaders
//
// 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();
}
}
//----------------------------------------------------------------------
// DumpELFSectionHeader
//
// 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);
}
//----------------------------------------------------------------------
// DumpELFSectionHeader_sh_type
//
// 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;
}
}
//----------------------------------------------------------------------
// DumpELFSectionHeader_sh_flags
//
// 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" : " ");
}
//----------------------------------------------------------------------
// DumpELFSectionHeaders
//
// 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();
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 (m_section_headers.empty())
{
// Allow elf notes to be parsed which may affect the detected architecture.
ParseSectionHeaders();
}
arch = m_arch_spec;
return true;
}
ObjectFile::Type
ObjectFileELF::CalculateType()
{
switch (m_header.e_type)
{
case llvm::ELF::ET_NONE:
// 0 - No file type
return eTypeUnknown;
case llvm::ELF::ET_REL:
// 1 - Relocatable file
return eTypeObjectFile;
case llvm::ELF::ET_EXEC:
// 2 - Executable file
return eTypeExecutable;
case llvm::ELF::ET_DYN:
// 3 - Shared object file
return eTypeSharedLibrary;
case ET_CORE:
// 4 - Core file
return eTypeCoreFile;
default:
break;
}
return eTypeUnknown;
}
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;
}
return eStrataUnknown;
}