Index: lldb/trunk/include/lldb/Target/Target.h =================================================================== --- lldb/trunk/include/lldb/Target/Target.h +++ lldb/trunk/include/lldb/Target/Target.h @@ -1116,6 +1116,24 @@ 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: Index: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h =================================================================== --- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -73,6 +73,8 @@ bool IsExecutable() const override; + bool IsDynamicLoader() const; + uint32_t GetAddressByteSize() const override; lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; Index: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1144,6 +1144,10 @@ 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 @@ // 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 @@ 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: Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -2448,6 +2448,44 @@ 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(); Index: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp =================================================================== --- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp +++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp @@ -65,38 +65,17 @@ 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(this), - m_constructor_errors.GetData()); + if (log && error.Fail()) { + m_constructor_errors.Printf("%s", error.AsCString()); + log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast(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(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(this), m_constructor_errors.GetData()); - return false; - } + if (!m_start_addr.IsValid()) { + return false; } start_load_addr = m_start_addr.GetLoadAddress(&GetTarget());