
The rationale here is that ArchSpec is used throughout the codebase, including in places which should not depend on the rest of the code in the Core module. This commit touches many files, but most of it is just renaming of #include lines. In a couple of cases, I removed the #include ArchSpec line altogether, as the file was not using it. In one or two places, this necessitated adding other #includes like lldb-private-defines.h. llvm-svn: 318048
1057 lines
44 KiB
C++
1057 lines
44 KiB
C++
//===-- ObjectFilePECOFF.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ObjectFilePECOFF.h"
|
|
#include "WindowsMiniDump.h"
|
|
|
|
#include "lldb/Core/FileSpecList.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Core/StreamFile.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/SectionLoadList.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/ArchSpec.h"
|
|
#include "lldb/Utility/DataBufferHeap.h"
|
|
#include "lldb/Utility/DataBufferLLVM.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "lldb/Utility/Timer.h"
|
|
#include "lldb/Utility/UUID.h"
|
|
#include "llvm/BinaryFormat/COFF.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.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
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
void ObjectFilePECOFF::Initialize() {
|
|
PluginManager::RegisterPlugin(
|
|
GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
|
|
CreateMemoryInstance, GetModuleSpecifications, SaveCore);
|
|
}
|
|
|
|
void ObjectFilePECOFF::Terminate() {
|
|
PluginManager::UnregisterPlugin(CreateInstance);
|
|
}
|
|
|
|
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)";
|
|
}
|
|
|
|
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 =
|
|
DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset);
|
|
if (!data_sp)
|
|
return nullptr;
|
|
data_offset = 0;
|
|
}
|
|
|
|
if (!ObjectFilePECOFF::MagicBytesMatch(data_sp))
|
|
return nullptr;
|
|
|
|
// Update the data to contain the entire file if it doesn't already
|
|
if (data_sp->GetByteSize() < length) {
|
|
data_sp =
|
|
DataBufferLLVM::CreateSliceFromPath(file->GetPath(), length, file_offset);
|
|
if (!data_sp)
|
|
return nullptr;
|
|
}
|
|
|
|
auto objfile_ap = llvm::make_unique<ObjectFilePECOFF>(
|
|
module_sp, data_sp, data_offset, file, file_offset, length);
|
|
if (!objfile_ap || !objfile_ap->ParseHeader())
|
|
return nullptr;
|
|
|
|
return objfile_ap.release();
|
|
}
|
|
|
|
ObjectFile *ObjectFilePECOFF::CreateMemoryInstance(
|
|
const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
|
|
const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
|
|
if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp))
|
|
return nullptr;
|
|
auto objfile_ap = llvm::make_unique<ObjectFilePECOFF>(
|
|
module_sp, data_sp, process_sp, header_addr);
|
|
if (objfile_ap.get() && objfile_ap->ParseHeader()) {
|
|
return objfile_ap.release();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
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));
|
|
}
|
|
else if (coff_header.machine == MachineArmNt)
|
|
{
|
|
spec.SetTriple("arm-pc-windows");
|
|
specs.Append(ModuleSpec(file, spec));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return specs.GetSize() - initial_count;
|
|
}
|
|
|
|
bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp,
|
|
const lldb_private::FileSpec &outfile,
|
|
lldb_private::Status &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;
|
|
}
|
|
|
|
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 &header_data_sp,
|
|
const lldb::ProcessSP &process_sp,
|
|
addr_t header_addr)
|
|
: ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
|
|
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() {}
|
|
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
ByteOrder ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle; }
|
|
|
|
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;
|
|
return 4;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// NeedsEndianSwap
|
|
//
|
|
// Return true if an endian swap needs to occur when extracting data
|
|
// from this file.
|
|
//----------------------------------------------------------------------
|
|
bool ObjectFilePECOFF::NeedsEndianSwap() const {
|
|
#if defined(__LITTLE_ENDIAN__)
|
|
return false;
|
|
#else
|
|
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
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
// Make sure we are on track for section data which follows
|
|
*offset_ptr = end_offset;
|
|
return success;
|
|
}
|
|
|
|
DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
|
|
if (m_file) {
|
|
// A bit of a hack, but we intend to write to this buffer, so we can't
|
|
// mmap it.
|
|
auto buffer_sp =
|
|
DataBufferLLVM::CreateSliceFromPath(m_file.GetPath(), size, offset, true);
|
|
return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
|
|
}
|
|
ProcessSP process_sp(m_process_wp.lock());
|
|
DataExtractor data;
|
|
if (process_sp) {
|
|
auto data_ap = llvm::make_unique<DataBufferHeap>(size, 0);
|
|
Status readmem_error;
|
|
size_t bytes_read =
|
|
process_sp->ReadMemory(m_image_base + offset, data_ap->GetBytes(),
|
|
data_ap->GetByteSize(), readmem_error);
|
|
if (bytes_read == size) {
|
|
DataBufferSP buffer_sp(data_ap.release());
|
|
data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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 size_t section_header_byte_size = nsects * sizeof(section_header_t);
|
|
DataExtractor section_header_data =
|
|
ReadImageData(section_header_data_offset, section_header_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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_sect_headers.empty() == 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;
|
|
}
|
|
|
|
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 (m_file && num_syms > 0 && m_coff_header.symoff > 0) {
|
|
const uint32_t symbol_size = 18;
|
|
const size_t symbol_data_size = num_syms * symbol_size;
|
|
// Include the 4-byte string table size at the end of the symbols
|
|
DataExtractor symtab_data =
|
|
ReadImageData(m_coff_header.symoff, symbol_data_size + 4);
|
|
lldb::offset_t offset = symbol_data_size;
|
|
const uint32_t strtab_size = symtab_data.GetU32(&offset);
|
|
if (strtab_size > 0) {
|
|
DataExtractor strtab_data = ReadImageData(
|
|
m_coff_header.symoff + symbol_data_size, strtab_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 = const_cast<uint32_t *>(
|
|
reinterpret_cast<const uint32_t *>(strtab_data.GetDataStart()));
|
|
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;
|
|
|
|
uint32_t address_rva = data_start;
|
|
if (m_file) {
|
|
Address address(m_coff_header_opt.image_base + data_start, sect_list);
|
|
address_rva =
|
|
address.GetSection()->GetFileOffset() + address.GetOffset();
|
|
}
|
|
DataExtractor symtab_data =
|
|
ReadImageData(address_rva, m_coff_header_opt.data_dirs[0].vmsize);
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ObjectFilePECOFF::GetUUID(UUID *uuid) { return false; }
|
|
|
|
uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) {
|
|
return 0;
|
|
}
|
|
|
|
lldb_private::Address ObjectFilePECOFF::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_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;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// DumpDOSHeader
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// DumpCOFFHeader
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// DumpOptCOFFHeader
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------
|
|
// 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);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// 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::IsWindowsSubsystem() {
|
|
switch (m_coff_header_opt.subsystem) {
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_XBOX:
|
|
case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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,
|
|
IsWindowsSubsystem() ? llvm::Triple::Win32
|
|
: llvm::Triple::UnknownOS);
|
|
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::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; }
|
|
//------------------------------------------------------------------
|
|
// PluginInterface protocol
|
|
//------------------------------------------------------------------
|
|
ConstString ObjectFilePECOFF::GetPluginName() { return GetPluginNameStatic(); }
|
|
|
|
uint32_t ObjectFilePECOFF::GetPluginVersion() { return 1; }
|