Skip to content

Commit

Permalink
[lldb] Read modules from memory when a local copy is not available
Browse files Browse the repository at this point in the history
Summary:
When the local lldb doesn't have access to a copy of the modules in the target, e.g. winphone, with this change now we read these modules from memory.

There are mainly 2 changes:
1. create pecoff object files from memory
2. read from memory when the local file is not available

Reviewers: sas, fjricci, zturner

Subscribers: #lldb

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D24284

llvm-svn: 284422
  • Loading branch information
walter-erquinigo committed Oct 17, 2016
1 parent a7cab58 commit 344546b
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 69 deletions.
176 changes: 107 additions & 69 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
Expand Up @@ -14,6 +14,7 @@

#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
Expand Down Expand Up @@ -83,7 +84,14 @@ ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp,
ObjectFile *ObjectFilePECOFF::CreateMemoryInstance(
const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
return NULL;
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(
Expand Down Expand Up @@ -161,6 +169,18 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
::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() {
Expand Down Expand Up @@ -396,6 +416,27 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) {
return success;
}

DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
if (m_file) {
DataBufferSP buffer_sp(m_file.ReadFileContents(offset, size));
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);
Error 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
//----------------------------------------------------------------------
Expand All @@ -405,12 +446,9 @@ bool ObjectFilePECOFF::ParseSectionHeaders(
m_sect_headers.clear();

if (nsects > 0) {
const uint32_t addr_byte_size = GetAddressByteSize();
const size_t section_header_byte_size = nsects * sizeof(section_header_t);
DataBufferSP section_header_data_sp(m_file.ReadFileContents(
section_header_data_offset, section_header_byte_size));
DataExtractor section_header_data(section_header_data_sp, GetByteOrder(),
addr_byte_size);
DataExtractor section_header_data =
ReadImageData(section_header_data_offset, section_header_byte_size);

lldb::offset_t offset = 0;
if (section_header_data.ValidOffsetForDataOfSize(
Expand Down Expand Up @@ -470,68 +508,65 @@ Symtab *ObjectFilePECOFF::GetSymtab() {

const uint32_t num_syms = m_coff_header.nsyms;

if (num_syms > 0 && m_coff_header.symoff > 0) {
if (m_file && num_syms > 0 && m_coff_header.symoff > 0) {
const uint32_t symbol_size = 18;
const uint32_t addr_byte_size = GetAddressByteSize();
const size_t symbol_data_size = num_syms * symbol_size;
// Include the 4-byte string table size at the end of the symbols
DataBufferSP symtab_data_sp(m_file.ReadFileContents(
m_coff_header.symoff, symbol_data_size + 4));
DataExtractor symtab_data(symtab_data_sp, GetByteOrder(),
addr_byte_size);
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);
DataBufferSP strtab_data_sp(m_file.ReadFileContents(
m_coff_header.symoff + symbol_data_size, strtab_size));
DataExtractor strtab_data(strtab_data_sp, GetByteOrder(),
addr_byte_size);

// First 4 bytes should be zeroed after strtab_size has been read,
// because it is used as offset 0 to encode a NULL string.
uint32_t *strtab_data_start = (uint32_t *)strtab_data_sp->GetBytes();
strtab_data_start[0] = 0;

offset = 0;
std::string symbol_name;
Symbol *symbols = m_symtab_ap->Resize(num_syms);
for (uint32_t i = 0; i < num_syms; ++i) {
coff_symbol_t symbol;
const uint32_t symbol_offset = offset;
const char *symbol_name_cstr = NULL;
// If the first 4 bytes of the symbol string are zero, then they
// are followed by a 4-byte string table offset. Else these
// 8 bytes contain the symbol name
if (symtab_data.GetU32(&offset) == 0) {
// Long string that doesn't fit into the symbol table name,
// so now we must read the 4 byte string table offset
uint32_t strtab_offset = symtab_data.GetU32(&offset);
symbol_name_cstr = strtab_data.PeekCStr(strtab_offset);
symbol_name.assign(symbol_name_cstr);
} else {
// Short string that fits into the symbol table name which is 8
// bytes
offset += sizeof(symbol.name) - 4; // Skip remaining
symbol_name_cstr = symtab_data.PeekCStr(symbol_offset);
if (symbol_name_cstr == NULL)
break;
symbol_name.assign(symbol_name_cstr, sizeof(symbol.name));
}
symbol.value = symtab_data.GetU32(&offset);
symbol.sect = symtab_data.GetU16(&offset);
symbol.type = symtab_data.GetU16(&offset);
symbol.storage = symtab_data.GetU8(&offset);
symbol.naux = symtab_data.GetU8(&offset);
symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
if ((int16_t)symbol.sect >= 1) {
Address symbol_addr(sect_list->GetSectionAtIndex(symbol.sect - 1),
symbol.value);
symbols[i].GetAddressRef() = symbol_addr;
symbols[i].SetType(MapSymbolType(symbol.type));
}

if (symbol.naux > 0) {
i += symbol.naux;
offset += symbol_size;
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 = (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;
}
}
}
}
Expand All @@ -543,12 +578,15 @@ Symtab *ObjectFilePECOFF::GetSymtab() {
export_directory_entry export_table;
uint32_t data_start =
m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr;
Address address(m_coff_header_opt.image_base + data_start, sect_list);
DataBufferSP symtab_data_sp(m_file.ReadFileContents(
address.GetSection()->GetFileOffset() + address.GetOffset(),
m_coff_header_opt.data_dirs[0].vmsize));
DataExtractor symtab_data(symtab_data_sp, GetByteOrder(),
GetAddressByteSize());

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
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
Expand Up @@ -50,6 +50,10 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
const lldb_private::FileSpec *file,
lldb::offset_t file_offset, lldb::offset_t length);

ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
lldb::DataBufferSP &header_data_sp,
const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);

~ObjectFilePECOFF() override;

//------------------------------------------------------------------
Expand Down Expand Up @@ -130,6 +134,8 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {

bool IsWindowsSubsystem();

lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size);

protected:
bool NeedsEndianSwap() const;

Expand Down

0 comments on commit 344546b

Please sign in to comment.