Index: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -172,6 +172,10 @@ void ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Resolve modules using library list from GDB Server + void + ResolveViaGDBServerLibraryList( ); + private: DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); }; Index: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -23,6 +23,8 @@ #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" + #include "AuxVector.h" #include "DynamicLoaderPOSIXDYLD.h" @@ -110,6 +112,63 @@ } void +DynamicLoaderPOSIXDYLD::ResolveViaGDBServerLibraryList() +{ + using lldb_private::process_gdb_remote::ProcessGDBRemote; + using lldb_private::process_gdb_remote::GDBLoadedModuleInfoList; + + if (m_process == nullptr) + return; + if (m_process->GetPluginName() != ConstString ("gdb-remote")) + return; + ProcessGDBRemote *gdbremote = static_cast(m_process); + + // get a list of all the modules + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + GDBLoadedModuleInfoList list; + if (gdbremote->GetLoadedModuleList (list).Success()) + { + ModuleList new_modules; + + for (uint32_t i = 0; i < list.m_list.size(); i++) + { + GDBLoadedModuleInfoList::LoadedModuleInfo modInfo = list.m_list[i]; + + std::string mod_name; + lldb::addr_t mod_base; + lldb::addr_t mod_link; + + bool valid = true; + valid &= modInfo.get_name (mod_name); + valid &= modInfo.get_base (mod_base); + valid &= modInfo.get_link_map (mod_link); + 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); + ModuleSP module_sp = LoadModuleAtAddress (file, mod_link, mod_base); + + if (module_sp.get()) + { + loaded_modules.AppendIfNeeded (module_sp); + new_modules.Append (module_sp); + } + } + + if (new_modules.GetSize() > 0) + m_process->GetTarget().ModulesDidLoad (new_modules); + } +} + +void DynamicLoaderPOSIXDYLD::DidAttach() { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); @@ -123,12 +182,44 @@ ModuleSP executable_sp = GetTargetExecutable(); ResolveExecutableModule(executable_sp); + // try to resolve library load addresses via gdbremote packets + ResolveViaGDBServerLibraryList( ); + + // 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); + + bool rebase_exec = true; + // if we dont have a load address we cant re-base + if ( load_offset == LLDB_INVALID_ADDRESS ) + rebase_exec = false; + // 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 (executable_sp && load_offset != LLDB_INVALID_ADDRESS) + // if the target executable should be re-based + if (rebase_exec) { ModuleList module_list; @@ -537,6 +628,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: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -39,6 +39,97 @@ class ThreadGDBRemote; +class 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; + }; + + void add (const LoadedModuleInfo & mod) + { + m_list.push_back (mod); + } + + std::vector m_list; + lldb::addr_t m_link_map; +}; + class ProcessGDBRemote : public Process { public: @@ -241,9 +332,9 @@ const ArchSpec& arch, ModuleSpec &module_spec) override; - // query remote gdbserver for information - bool - GetGDBServerInfo ( ); + // Query remote GDBServer for a detailed loaded library list + Error + GetLoadedModuleList (GDBLoadedModuleInfoList & modules); protected: friend class ThreadGDBRemote; @@ -396,6 +487,10 @@ DynamicLoader * GetDynamicLoader () override; + // Query remote GDBServer for register information + bool + GetGDBServerRegisterInfo (); + private: //------------------------------------------------------------------ // For ProcessGDBRemote only Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -575,7 +575,7 @@ if (reg_num == 0) { // try to extract information from servers target.xml - if ( GetGDBServerInfo( ) ) + if ( GetGDBServerRegisterInfo () ) return; FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); @@ -3855,7 +3855,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 +3928,138 @@ return true; } +Error +ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & modules) +{ + 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); + + // 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 + 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 val32 = std::stoul (val.c_str()+2, 0, 16); + modules.m_link_map = val32; + } + } + + // 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 val32 = std::stoul (val.c_str()+2, 0, 16); + module.set_link_map (val32); + } + } + + // 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 val32 = std::stoul (val.c_str()+2, 0, 16); + module.set_base (val32); + } + } + + // 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 val32 = std::stoul (val.c_str()+2, 0, 16); + module.set_dynamic (val32); + } + } + } + + 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()); + } + + modules.add (module); + } + + if (log) + log->Printf ("found %" PRId32 " modules in total", (int) modules.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; Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -1057,13 +1057,25 @@ 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 modsp = m_images.GetModuleAtIndex( i ); + lldb_private::ObjectFile * obj = modsp->GetObjectFile( ); + if ( obj == nullptr ) + continue; + ObjectFile::Type type = obj->GetType( ); + if ( type == ObjectFile::Type::eTypeExecutable ) + return modsp; + } + // 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