Index: lldb/trunk/include/lldb/Target/Process.h =================================================================== --- lldb/trunk/include/lldb/Target/Process.h +++ lldb/trunk/include/lldb/Target/Process.h @@ -1121,6 +1121,22 @@ virtual const lldb::DataBufferSP GetAuxvData(); + //------------------------------------------------------------------ + /// Sometimes processes know how to retrieve and load shared libraries. + /// This is normally done by DynamicLoader plug-ins, but sometimes the + /// connection to the process allows retrieving this information. The + /// dynamic loader plug-ins can use this function if they can't + /// determine the current shared library load state. + /// + /// @return + /// The number of shared libraries that were loaded + //------------------------------------------------------------------ + virtual size_t + LoadModules () + { + return 0; + } + protected: virtual JITLoaderList & GetJITLoaders (); Index: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp =================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -120,15 +120,45 @@ if (log) log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - ModuleSP executable_sp = GetTargetExecutable(); - ResolveExecutableModule(executable_sp); + // ask the process if it can load any of its own modules + m_process->LoadModules (); - addr_t load_offset = ComputeLoadOffset(); + ModuleSP executable_sp = GetTargetExecutable (); + ResolveExecutableModule (executable_sp); + + // find the main process load offset + addr_t load_offset = ComputeLoadOffset (); if (log) log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " executable '%s', load_offset 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, executable_sp ? executable_sp->GetFileSpec().GetPath().c_str () : "", load_offset); + // if we dont have a load address we cant re-base + bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; - if (executable_sp && load_offset != LLDB_INVALID_ADDRESS) + // if we have a valid executable + if (executable_sp.get()) + { + lldb_private::ObjectFile * obj = executable_sp->GetObjectFile(); + if (obj) + { + // don't rebase if the module is not an executable + if (obj->GetType() != ObjectFile::Type::eTypeExecutable) + rebase_exec = false; + + // don't rebase if the module already has a load address + Target & target = m_process->GetTarget (); + Address addr = obj->GetImageInfoAddress (&target); + if (addr.GetLoadAddress (&target) != LLDB_INVALID_ADDRESS) + rebase_exec = false; + } + } + else + { + // no executable, nothing to re-base + rebase_exec = false; + } + + // if the target executable should be re-based + if (rebase_exec) { ModuleList module_list; @@ -537,6 +567,9 @@ if (!exe) return LLDB_INVALID_ADDRESS; + if (exe->GetType() != ObjectFile::Type::eTypeExecutable) + return LLDB_INVALID_ADDRESS; + Address file_entry = exe->GetEntryPointAddress(); if (!file_entry.IsValid()) Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -241,15 +241,16 @@ const ArchSpec& arch, ModuleSpec &module_spec) override; - // query remote gdbserver for information - bool - GetGDBServerInfo ( ); + virtual size_t + LoadModules () override; protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; + class GDBLoadedModuleInfoList; + //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- @@ -396,6 +397,17 @@ DynamicLoader * GetDynamicLoader () override; + // Query remote GDBServer for register information + bool + GetGDBServerRegisterInfo (); + + // Query remote GDBServer for a detailed loaded library list + Error + GetLoadedModuleList (GDBLoadedModuleInfoList &); + + lldb::ModuleSP + LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr); + private: //------------------------------------------------------------------ // For ProcessGDBRemote only Index: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -174,6 +174,107 @@ } // anonymous namespace end +class ProcessGDBRemote::GDBLoadedModuleInfoList +{ +public: + + class LoadedModuleInfo + { + public: + + enum e_data_point + { + e_has_name = 0, + e_has_base , + e_has_dynamic , + e_has_link_map , + e_num + }; + + LoadedModuleInfo () + { + for (uint32_t i = 0; i < e_num; ++i) + m_has[i] = false; + }; + + void set_name (const std::string & name) + { + m_name = name; + m_has[e_has_name] = true; + } + bool get_name (std::string & out) const + { + out = m_name; + return m_has[e_has_name]; + } + + void set_base (const lldb::addr_t base) + { + m_base = base; + m_has[e_has_base] = true; + } + bool get_base (lldb::addr_t & out) const + { + out = m_base; + return m_has[e_has_base]; + } + + void set_link_map (const lldb::addr_t addr) + { + m_link_map = addr; + m_has[e_has_link_map] = true; + } + bool get_link_map (lldb::addr_t & out) const + { + out = m_link_map; + return m_has[e_has_link_map]; + } + + void set_dynamic (const lldb::addr_t addr) + { + m_dynamic = addr; + m_has[e_has_dynamic] = true; + } + bool get_dynamic (lldb::addr_t & out) const + { + out = m_dynamic; + return m_has[e_has_dynamic]; + } + + bool has_info (e_data_point datum) + { + assert (datum < e_num); + return m_has[datum]; + } + + protected: + + bool m_has[e_num]; + std::string m_name; + lldb::addr_t m_link_map; + lldb::addr_t m_base; + lldb::addr_t m_dynamic; + }; + + GDBLoadedModuleInfoList () + : m_list () + , m_link_map (LLDB_INVALID_ADDRESS) + {} + + void add (const LoadedModuleInfo & mod) + { + m_list.push_back (mod); + } + + void clear () + { + m_list.clear (); + } + + std::vector m_list; + lldb::addr_t m_link_map; +}; + // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. @@ -575,7 +676,7 @@ if (reg_num == 0) { // try to extract information from servers target.xml - if ( GetGDBServerInfo( ) ) + if (GetGDBServerRegisterInfo ()) return; FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); @@ -2281,7 +2382,18 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() { - return m_gdb_comm.GetShlibInfoAddr(); + // request the link map address via the $qShlibInfoAddr packet + lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); + + // the loaded module list can also provides a link map address + if (addr == LLDB_INVALID_ADDRESS) + { + GDBLoadedModuleInfoList list; + if (GetLoadedModuleList (list).Success()) + addr = list.m_link_map; + } + + return addr; } //------------------------------------------------------------------ @@ -3855,7 +3967,7 @@ // return: 'true' on success // 'false' on failure bool -ProcessGDBRemote::GetGDBServerInfo () +ProcessGDBRemote::GetGDBServerRegisterInfo () { // redirect libxml2's error handler since the default prints to stdout @@ -3928,12 +4040,140 @@ return true; } +Error +ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) +{ + Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS); + if (log) + log->Printf ("ProcessGDBRemote::%s", __FUNCTION__); + + // redirect libxml2's error handler since the default prints to stdout + xmlGenericErrorFunc func = libxml2NullErrorFunc; + initGenericErrorDefaultFunc (&func); + + GDBRemoteCommunicationClient & comm = m_gdb_comm; + GDBRemoteDynamicRegisterInfo & regInfo = m_register_info; + + // check that we have extended feature read support + if (!comm.GetQXferLibrariesSVR4ReadSupported ()) + return Error (0, ErrorType::eErrorTypeGeneric); + + list.clear (); + + // request the loaded library list + std::string raw; + lldb_private::Error lldberr; + if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) + return Error (0, ErrorType::eErrorTypeGeneric); + + // parse the xml file in memory + if (log) + log->Printf ("parsing: %s", raw.c_str()); + xmlDocPtr doc = xmlReadMemory (raw.c_str(), raw.size(), "noname.xml", nullptr, 0); + if (doc == nullptr) + return Error (0, ErrorType::eErrorTypeGeneric); + + xmlNodePtr elm = xmlExFindElement (doc->children, {"library-list-svr4"}); + if (!elm) + return Error(); + + // main link map structure + xmlAttr * attr = xmlExFindAttribute (elm, "main-lm"); + if (attr) + { + std::string val = xmlExGetTextContent (attr); + if (val.length() > 2) + { + uint32_t process_lm = std::stoul (val.c_str()+2, 0, 16); + list.m_link_map = process_lm; + } + } + + // parse individual library entries + for (xmlNode * child = elm->children; child; child=child->next) + { + if (!child->name) + continue; + + if (strcmp ((char*)child->name, "library") != 0) + continue; + + GDBLoadedModuleInfoList::LoadedModuleInfo module; + + for (xmlAttrPtr prop = child->properties; prop; prop=prop->next) + { + if (strcmp ((char*)prop->name, "name") == 0) + module.set_name (xmlExGetTextContent (prop)); + + // the address of the link_map struct. + if (strcmp ((char*)prop->name, "lm") == 0) + { + std::string val = xmlExGetTextContent (prop); + if (val.length() > 2) + { + uint32_t module_lm = std::stoul (val.c_str()+2, 0, 16); + module.set_link_map (module_lm); + } + } + + // the displacement as read from the field 'l_addr' of the link_map struct. + if (strcmp ((char*)prop->name, "l_addr") == 0) + { + std::string val = xmlExGetTextContent (prop); + if (val.length() > 2) + { + uint32_t module_base = std::stoul (val.c_str()+2, 0, 16); + module.set_base (module_base); + } + } + + // the memory address of the libraries PT_DYAMIC section. + if (strcmp ((char*)prop->name, "l_ld") == 0) + { + std::string val = xmlExGetTextContent (prop); + if (val.length() > 2) + { + uint32_t module_dyn = std::stoul (val.c_str()+2, 0, 16); + module.set_dynamic (module_dyn); + } + } + } + + if (log) + { + std::string name (""); + lldb::addr_t lm=0, base=0, ld=0; + + module.get_name (name); + module.get_link_map (lm); + module.get_base (base); + module.get_dynamic (ld); + + log->Printf ("found (link_map:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str()); + } + + list.add (module); + } + + if (log) + log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); + + return Error(); +} + #else // if defined( LIBXML2_DEFINED ) -using namespace lldb_private::process_gdb_remote; +Error +ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList &) +{ + // stub (libxml2 not present) + Error err; + err.SetError (0, ErrorType::eErrorTypeGeneric); + return err; +} bool -ProcessGDBRemote::GetGDBServerInfo () +ProcessGDBRemote::GetGDBServerRegisterInfo () { // stub (libxml2 not present) return false; @@ -3941,6 +4181,91 @@ #endif // if defined( LIBXML2_DEFINED ) +lldb::ModuleSP +ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + ModuleList &modules = target.GetImages(); + ModuleSP module_sp; + + bool changed = false; + + ModuleSpec module_spec (file, target.GetArchitecture()); + if ((module_sp = modules.FindFirstModule (module_spec))) + { + module_sp->SetLoadAddress (target, base_addr, true, changed); + } + else if ((module_sp = target.GetSharedModule (module_spec))) + { + module_sp->SetLoadAddress (target, base_addr, true, changed); + } + + return module_sp; +} + +size_t +ProcessGDBRemote::LoadModules () +{ + using lldb_private::process_gdb_remote::ProcessGDBRemote; + + // request a list of loaded libraries from GDBServer + GDBLoadedModuleInfoList module_list; + if (GetLoadedModuleList (module_list).Fail()) + return 0; + + // get a list of all the modules + ModuleList new_modules; + + for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) + { + std::string mod_name; + lldb::addr_t mod_base; + + bool valid = true; + valid &= modInfo.get_name (mod_name); + valid &= modInfo.get_base (mod_base); + if (!valid) + continue; + + // hack (cleaner way to get file name only?) (win/unix compat?) + int marker = mod_name.rfind ('/'); + if (marker == std::string::npos) + marker = 0; + else + marker += 1; + + FileSpec file (mod_name.c_str()+marker, true); + lldb::ModuleSP module_sp = LoadModuleAtAddress (file, mod_base); + + if (module_sp.get()) + new_modules.Append (module_sp); + } + + if (new_modules.GetSize() > 0) + { + Target & target = m_target; + + new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool + { + lldb_private::ObjectFile * obj = module_sp->GetObjectFile (); + if (!obj) + return true; + + if (obj->GetType () != ObjectFile::Type::eTypeExecutable) + return true; + + lldb::ModuleSP module_copy_sp = module_sp; + target.SetExecutableModule (module_copy_sp, false); + return false; + }); + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + loaded_modules.AppendIfNeeded (new_modules); + m_process->GetTarget().ModulesDidLoad (new_modules); + } + + return new_modules.GetSize(); +} class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { Index: lldb/trunk/source/Target/Target.cpp =================================================================== --- lldb/trunk/source/Target/Target.cpp +++ lldb/trunk/source/Target/Target.cpp @@ -1057,13 +1057,24 @@ ModuleSP Target::GetExecutableModule () { - return m_images.GetModuleAtIndex(0); + // search for the first executable in the module list + for (size_t i = 0; i < m_images.GetSize(); ++i) + { + ModuleSP module_sp = m_images.GetModuleAtIndex (i); + lldb_private::ObjectFile * obj = module_sp->GetObjectFile(); + if (obj == nullptr) + continue; + if (obj->GetType() == ObjectFile::Type::eTypeExecutable) + return module_sp; + } + // as fall back return the first module loaded + return m_images.GetModuleAtIndex (0); } Module* Target::GetExecutableModulePointer () { - return m_images.GetModulePointerAtIndex(0); + return GetExecutableModule().get(); } static void