[Lldb-commits] [lldb] r366493 - Fall back to dyld's _dyld_start when no LC_MAIN / main() func can be found

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 18 13:55:24 PDT 2019


Author: jmolenda
Date: Thu Jul 18 13:55:24 2019
New Revision: 366493

URL: http://llvm.org/viewvc/llvm-project?rev=366493&view=rev
Log:
Fall back to dyld's _dyld_start when no LC_MAIN / main() func can be found

The new DriverKit user-land kernel drivers in macOS 10.15 / Catalina 
do not have a main() function or an LC_MAIN load command.  lldb uses
the address of main() as the return address for inferior function
calls; it puts a breakpoint on main, runs the inferior function call,
and when the main() breakpoint is hit, lldb knows unambiguously that
the inferior function call ran to completion - no other function calls
main.

This change hoists the logic for finding the "entry address" from 
ThreadPlanCallFunction to Target.  It changes the logic to first
try to get the entry address from the main executable module,
but if that module does not have one, it will iterate through all
modules looking for an entry address.

The patch also adds code to ObjectFileMachO to use dyld's 
_dyld_start function as an entry address.

<rdar://problem/52343958> 

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

Modified:
    lldb/trunk/include/lldb/Target/Target.h
    lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
    lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
    lldb/trunk/source/Target/Target.cpp
    lldb/trunk/source/Target/ThreadPlanCallFunction.cpp

Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=366493&r1=366492&r2=366493&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Thu Jul 18 13:55:24 2019
@@ -1116,6 +1116,24 @@ public:
 
   lldb::addr_t GetPersistentSymbol(ConstString name);
 
+  /// This method will return the address of the starting function for
+  /// this binary, e.g. main() or its equivalent.  This can be used as
+  /// an address of a function that is not called once a binary has 
+  /// started running - e.g. as a return address for inferior function
+  /// calls that are unambiguous completion of the function call, not
+  /// called during the course of the inferior function code running.
+  ///
+  /// If no entry point can be found, an invalid address is returned.
+  ///
+  /// \param [out] err
+  ///     This object will be set to failure if no entry address could
+  ///     be found, and may contain a helpful error message.
+  //
+  /// \return
+  ///     Returns the entry address for this program, LLDB_INVALID_ADDRESS
+  ///     if none can be found.
+  lldb_private::Address GetEntryPointAddress(Status &err);
+
   // Target Stop Hooks
   class StopHook : public UserID {
   public:

Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp?rev=366493&r1=366492&r2=366493&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp Thu Jul 18 13:55:24 2019
@@ -1144,6 +1144,10 @@ bool ObjectFileMachO::IsExecutable() con
   return m_header.filetype == MH_EXECUTE;
 }
 
+bool ObjectFileMachO::IsDynamicLoader() const {
+  return m_header.filetype == MH_DYLINKER;
+}
+
 uint32_t ObjectFileMachO::GetAddressByteSize() const {
   return m_data.GetAddressByteSize();
 }
@@ -5177,8 +5181,10 @@ lldb_private::Address ObjectFileMachO::G
   // 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())
+  if ((!IsExecutable() && !IsDynamicLoader()) || 
+      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:
@@ -5300,6 +5306,17 @@ lldb_private::Address ObjectFileMachO::G
       offset = cmd_offset + load_cmd.cmdsize;
     }
 
+    if (start_address == LLDB_INVALID_ADDRESS && IsDynamicLoader()) {
+      if (GetSymtab()) {
+        Symbol *dyld_start_sym = GetSymtab()->FindFirstSymbolWithNameAndType(
+                      ConstString("_dyld_start"), SymbolType::eSymbolTypeCode, 
+                      Symtab::eDebugAny, Symtab::eVisibilityAny);
+        if (dyld_start_sym && dyld_start_sym->GetAddress().IsValid()) {
+          start_address = dyld_start_sym->GetAddress().GetFileAddress();
+        }
+      }
+    }
+
     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:

Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h?rev=366493&r1=366492&r2=366493&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h (original)
+++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h Thu Jul 18 13:55:24 2019
@@ -73,6 +73,8 @@ public:
 
   bool IsExecutable() const override;
 
+  bool IsDynamicLoader() const;
+
   uint32_t GetAddressByteSize() const override;
 
   lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override;

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=366493&r1=366492&r2=366493&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Thu Jul 18 13:55:24 2019
@@ -2448,6 +2448,44 @@ lldb::addr_t Target::GetPersistentSymbol
   return address;
 }
 
+lldb_private::Address Target::GetEntryPointAddress(Status &err) {
+  err.Clear();
+  Address entry_addr;
+  Module *exe_module = GetExecutableModulePointer();
+
+  if (!exe_module || !exe_module->GetObjectFile()) {
+    err.SetErrorStringWithFormat("No primary executable found");
+  } else {
+    entry_addr = exe_module->GetObjectFile()->GetEntryPointAddress();
+    if (!entry_addr.IsValid()) {
+      err.SetErrorStringWithFormat(
+         "Could not find entry point address for executable module \"%s\".",
+         exe_module->GetFileSpec().GetFilename().AsCString());
+    }
+  }
+
+  if (!entry_addr.IsValid()) {
+    const ModuleList &modules = GetImages();
+    const size_t num_images = modules.GetSize();
+    for (size_t idx = 0; idx < num_images; ++idx) {
+      ModuleSP module_sp(modules.GetModuleAtIndex(idx));
+      if (module_sp && module_sp->GetObjectFile()) {
+        entry_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
+        if (entry_addr.IsValid()) {
+          // Clear out any old error messages from the original
+          // main-executable-binary search; one of the other modules
+          // was able to provide an address.
+          err.Clear();
+          break;
+        }
+      }
+    }
+  }
+
+  return entry_addr;
+}
+
+
 lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr,
                                             AddressClass addr_class) const {
   auto arch_plugin = GetArchitecturePlugin();

Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=366493&r1=366492&r2=366493&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Thu Jul 18 13:55:24 2019
@@ -65,38 +65,17 @@ bool ThreadPlanCallFunction::Constructor
     return false;
   }
 
-  Module *exe_module = GetTarget().GetExecutableModulePointer();
+  m_start_addr = GetTarget().GetEntryPointAddress(error);
 
-  if (exe_module == nullptr) {
-    m_constructor_errors.Printf(
-        "Can't execute code without an executable module.");
-    if (log)
-      log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this),
-                  m_constructor_errors.GetData());
+  if (log && error.Fail()) {
+    m_constructor_errors.Printf("%s", error.AsCString());
+    log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this),
+                 m_constructor_errors.GetData());
     return false;
-  } else {
-    ObjectFile *objectFile = exe_module->GetObjectFile();
-    if (!objectFile) {
-      m_constructor_errors.Printf(
-          "Could not find object file for module \"%s\".",
-          exe_module->GetFileSpec().GetFilename().AsCString());
-
-      if (log)
-        log->Printf("ThreadPlanCallFunction(%p): %s.",
-                    static_cast<void *>(this), m_constructor_errors.GetData());
-      return false;
-    }
+  }
 
-    m_start_addr = objectFile->GetEntryPointAddress();
-    if (!m_start_addr.IsValid()) {
-      m_constructor_errors.Printf(
-          "Could not find entry point address for executable module \"%s\".",
-          exe_module->GetFileSpec().GetFilename().AsCString());
-      if (log)
-        log->Printf("ThreadPlanCallFunction(%p): %s.",
-                    static_cast<void *>(this), m_constructor_errors.GetData());
-      return false;
-    }
+  if (!m_start_addr.IsValid()) {
+    return false;
   }
 
   start_load_addr = m_start_addr.GetLoadAddress(&GetTarget());




More information about the lldb-commits mailing list