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.

git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@127194 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 8793cfa..546dc78 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/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 @@
     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/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 5de0a8a..2b78da5 100644
--- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -115,6 +115,9 @@
 
     virtual lldb_private::Address
     GetImageInfoAddress();
+    
+    virtual lldb_private::Address
+    GetEntryPointAddress ();
 
 private:
     ObjectFileELF(lldb_private::Module* module,
@@ -156,6 +159,9 @@
     /// 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/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index deac894..fa88b18 100644
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/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 @@
     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 @@
     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)
 {
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index c20ff1e..1289b9d 100644
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/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 @@
     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 @@
     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 ();
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
index d3b62e6..a5e1c1a 100644
--- a/source/Target/ThreadPlanCallFunction.cpp
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -66,19 +66,33 @@
     
     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:");