diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 623016e9033f..70e889e3572f 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -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: //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 8793cfac93ee..546dc7840d26 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -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 //---------------------------------------------------------------------- diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 5de0a8aa83af..2b78da5436b7 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -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); diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index deac8947521a..fa88b184a311 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -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 corresponding to the flavor. + // + // + // 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; iFindSymbolsWithNameAndType(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) { diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index c20ff1e4106a..1289b9d3e280 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -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 m_mach_segments; std::vector m_mach_sections; + lldb_private::Address m_entry_point_address; size_t ParseSections (); diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index d3b62e6c7aaa..a5e1c1a0e794 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -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:");