forked from OSchip/llvm-project
Add a method "GetEntryPoint" to the ObjectFile class, and implement it on MachO & ELF - though the ELF implementation is probably a little weak. Then use this method in place of directly looking for "start" in the ThreadPlanCallFunction constructor to find the stopping point for our function evaluation.
llvm-svn: 127194
This commit is contained in:
parent
77ad1dc56d
commit
672e6f59c5
|
@ -338,6 +338,17 @@ public:
|
|||
/// object file format does not support or contain such information.
|
||||
virtual lldb_private::Address
|
||||
GetImageInfoAddress () { return Address(); }
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns the address of the Entry Point in this object file - if
|
||||
/// the object file doesn't have an entry point (because it is not an
|
||||
/// executable file) then an invalid address is returned.
|
||||
///
|
||||
/// @return
|
||||
/// Returns the entry address for this module.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb_private::Address
|
||||
GetEntryPointAddress () { return Address();}
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
#include "lldb/Core/DataBuffer.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/FileSpecList.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/Section.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Symbol/SymbolContext.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
|
||||
#define CASE_AND_STREAM(s, def, width) \
|
||||
|
@ -276,6 +278,32 @@ ObjectFileELF::GetImageInfoAddress()
|
|||
return Address();
|
||||
}
|
||||
|
||||
lldb_private::Address
|
||||
ObjectFileELF::GetEntryPointAddress ()
|
||||
{
|
||||
// If the object file is not an executable it can't hold the entry point. m_entry_point_address
|
||||
// is initialized to an invalid address, so we can just return that.
|
||||
// If m_entry_point_address is valid it means we've found it already, so return the cached value.
|
||||
|
||||
if (!IsExecutable() || m_entry_point_address.IsValid())
|
||||
return m_entry_point_address;
|
||||
|
||||
// FIXME: This is just looking for the "start" symbol, but that will fail if "start" is stripped.
|
||||
// There's probably a better way in ELF to find the start address of an executable module.
|
||||
|
||||
SymbolContextList contexts;
|
||||
SymbolContext context;
|
||||
if (!m_module->FindSymbolsWithNameAndType(ConstString ("start"), lldb::eSymbolTypeCode, contexts))
|
||||
return m_entry_point_address;
|
||||
|
||||
contexts.GetContextAtIndex(0, context);
|
||||
|
||||
m_entry_point_address = context.symbol->GetValue();
|
||||
|
||||
return m_entry_point_address;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ParseDependentModules
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -115,6 +115,9 @@ public:
|
|||
|
||||
virtual lldb_private::Address
|
||||
GetImageInfoAddress();
|
||||
|
||||
virtual lldb_private::Address
|
||||
GetEntryPointAddress ();
|
||||
|
||||
private:
|
||||
ObjectFileELF(lldb_private::Module* module,
|
||||
|
@ -156,6 +159,9 @@ private:
|
|||
/// Data extractor holding the string table used to resolve section names.
|
||||
lldb_private::DataExtractor m_shstr_data;
|
||||
|
||||
/// Cached value of the entry point for this module.
|
||||
lldb_private::Address m_entry_point_address;
|
||||
|
||||
/// Returns a 1 based index of the given section header.
|
||||
unsigned
|
||||
SectionIndex(const SectionHeaderCollIter &I);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/MachO.h"
|
||||
|
||||
#include "ObjectFileMachO.h"
|
||||
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
|
@ -105,7 +107,8 @@ ObjectFileMachO::ObjectFileMachO(Module* module, DataBufferSP& dataSP, const Fil
|
|||
m_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_header(),
|
||||
m_sections_ap(),
|
||||
m_symtab_ap()
|
||||
m_symtab_ap(),
|
||||
m_entry_point_address ()
|
||||
{
|
||||
::memset (&m_header, 0, sizeof(m_header));
|
||||
::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
|
||||
|
@ -1435,6 +1438,136 @@ ObjectFileMachO::GetDependentModules (FileSpecList& files)
|
|||
return count;
|
||||
}
|
||||
|
||||
lldb_private::Address
|
||||
ObjectFileMachO::GetEntryPointAddress ()
|
||||
{
|
||||
// If the object file is not an executable it can't hold the entry point. m_entry_point_address
|
||||
// is initialized to an invalid address, so we can just return that.
|
||||
// If m_entry_point_address is valid it means we've found it already, so return the cached value.
|
||||
|
||||
if (!IsExecutable() || m_entry_point_address.IsValid())
|
||||
return m_entry_point_address;
|
||||
|
||||
// Otherwise, look for the UnixThread or Thread command. The data for the Thread command is given in
|
||||
// /usr/include/mach-o.h, but it is basically:
|
||||
//
|
||||
// uint32_t flavor - this is the flavor argument you would pass to thread_get_state
|
||||
// uint32_t count - this is the count of longs in the thread state data
|
||||
// struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor.
|
||||
// <repeat this trio>
|
||||
//
|
||||
// So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there.
|
||||
// FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers
|
||||
// out of data in this form & attach them to a given thread. That should underlie the MacOS X User process plugin,
|
||||
// and we'll also need it for the MacOS X Core File process plugin. When we have that we can also use it here.
|
||||
//
|
||||
// For now we hard-code the offsets and flavors we need:
|
||||
//
|
||||
//
|
||||
|
||||
lldb_private::Mutex::Locker locker(m_mutex);
|
||||
struct load_command load_cmd;
|
||||
uint32_t offset = MachHeaderSizeFromMagic(m_header.magic);
|
||||
uint32_t i;
|
||||
lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
|
||||
bool done = false;
|
||||
|
||||
for (i=0; i<m_header.ncmds; ++i)
|
||||
{
|
||||
const uint32_t cmd_offset = offset;
|
||||
if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
|
||||
break;
|
||||
|
||||
switch (load_cmd.cmd)
|
||||
{
|
||||
case LoadCommandUnixThread:
|
||||
case LoadCommandThread:
|
||||
{
|
||||
while (offset < cmd_offset + load_cmd.cmdsize)
|
||||
{
|
||||
uint32_t flavor = m_data.GetU32(&offset);
|
||||
uint32_t count = m_data.GetU32(&offset);
|
||||
if (count == 0)
|
||||
{
|
||||
// We've gotten off somehow, log and exit;
|
||||
return m_entry_point_address;
|
||||
}
|
||||
|
||||
switch (m_header.cputype)
|
||||
{
|
||||
case llvm::MachO::CPUTypeARM:
|
||||
if (flavor == 1) // ARM_THREAD_STATE from mach/arm/thread_status.h
|
||||
{
|
||||
offset += 60; // This is the offset of pc in the GPR thread state data structure.
|
||||
start_address = m_data.GetU32(&offset);
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
case llvm::MachO::CPUTypeI386:
|
||||
if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
|
||||
{
|
||||
offset += 40; // This is the offset of eip in the GPR thread state data structure.
|
||||
start_address = m_data.GetU32(&offset);
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
case llvm::MachO::CPUTypeX86_64:
|
||||
if (flavor == 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
|
||||
{
|
||||
offset += 16 * 8; // This is the offset of rip in the GPR thread state data structure.
|
||||
start_address = m_data.GetU64(&offset);
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return m_entry_point_address;
|
||||
}
|
||||
// Haven't found the GPR flavor yet, skip over the data for this flavor:
|
||||
if (done)
|
||||
break;
|
||||
offset += count * 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
|
||||
// Go to the next load command:
|
||||
offset = cmd_offset + load_cmd.cmdsize;
|
||||
}
|
||||
|
||||
if (start_address != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
// We got the start address from the load commands, so now resolve that address in the sections
|
||||
// of this ObjectFile:
|
||||
if (!m_entry_point_address.ResolveAddressUsingFileSections (start_address, GetSectionList()))
|
||||
{
|
||||
m_entry_point_address.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't read the UnixThread load command - maybe it wasn't there. As a fallback look for the
|
||||
// "start" symbol in the main executable.
|
||||
|
||||
SymbolContextList contexts;
|
||||
SymbolContext context;
|
||||
if (!m_module->FindSymbolsWithNameAndType(ConstString ("start"), lldb::eSymbolTypeCode, contexts))
|
||||
return m_entry_point_address;
|
||||
|
||||
contexts.GetContextAtIndex(0, context);
|
||||
|
||||
m_entry_point_address = context.symbol->GetValue();
|
||||
}
|
||||
|
||||
return m_entry_point_address;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectFileMachO::GetArchitecture (ArchSpec &arch)
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "llvm/Support/MachO.h"
|
||||
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Host/FileSpec.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
|
@ -112,7 +113,8 @@ public:
|
|||
virtual lldb_private::Log *
|
||||
EnablePluginLogging (lldb_private::Stream *strm, lldb_private::Args &command);
|
||||
|
||||
|
||||
virtual lldb_private::Address
|
||||
GetEntryPointAddress ();
|
||||
|
||||
protected:
|
||||
mutable lldb_private::Mutex m_mutex;
|
||||
|
@ -123,6 +125,7 @@ protected:
|
|||
llvm::MachO::dysymtab_command m_dysymtab;
|
||||
std::vector<llvm::MachO::segment_command_64> m_mach_segments;
|
||||
std::vector<llvm::MachO::section_64> m_mach_sections;
|
||||
lldb_private::Address m_entry_point_address;
|
||||
|
||||
size_t
|
||||
ParseSections ();
|
||||
|
|
|
@ -66,19 +66,33 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
|
|||
|
||||
lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
|
||||
|
||||
SymbolContextList contexts;
|
||||
SymbolContext context;
|
||||
ModuleSP executableModuleSP (target.GetExecutableModule());
|
||||
|
||||
if (!executableModuleSP ||
|
||||
!executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
|
||||
if (!executableModuleSP)
|
||||
{
|
||||
log->Printf ("Can't execute code without an executable module.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectFile *objectFile = executableModuleSP->GetObjectFile();
|
||||
if (!objectFile)
|
||||
{
|
||||
log->Printf ("Could not find object file for module \"%s\".",
|
||||
executableModuleSP->GetFileSpec().GetFilename().AsCString());
|
||||
return;
|
||||
}
|
||||
m_start_addr = objectFile->GetEntryPointAddress();
|
||||
if (!m_start_addr.IsValid())
|
||||
{
|
||||
log->Printf ("Could not find entry point address for executable module \"%s\".",
|
||||
executableModuleSP->GetFileSpec().GetFilename().AsCString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
contexts.GetContextAtIndex(0, context);
|
||||
|
||||
m_start_addr = context.symbol->GetValue();
|
||||
lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
|
||||
|
||||
|
||||
// Checkpoint the thread state so we can restore it later.
|
||||
if (log && log->GetVerbose())
|
||||
ReportRegisterState ("About to checkpoint thread before function call. Original register state was:");
|
||||
|
|
Loading…
Reference in New Issue