Index: include/lldb/Core/LoadedModuleInfoList.h =================================================================== --- /dev/null +++ include/lldb/Core/LoadedModuleInfoList.h @@ -0,0 +1,152 @@ +//===-- LoadedModuleInfoList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LoadedModuleInfoList_h_ +#define liblldb_LoadedModuleInfoList_h_ + +// C Includes + +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/lldb-private-forward.h" + +namespace lldb_private { +class LoadedModuleInfoList +{ +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_base_is_offset (bool is_offset) + { + m_base_is_offset = is_offset; + } + bool get_base_is_offset(bool & out) const + { + out = m_base_is_offset; + 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) const + { + assert (datum < e_num); + return m_has[datum]; + } + + bool + operator == (LoadedModuleInfo const &rhs) const + { + if (e_num != rhs.e_num) + return false; + + for (size_t i = 0; i < e_num; ++i) + { + if (m_has[i] != rhs.m_has[i]) + return false; + } + + return (m_base == rhs.m_base) && + (m_link_map == rhs.m_link_map) && + (m_dynamic == rhs.m_dynamic) && + (m_name == rhs.m_name); + } + protected: + + bool m_has[e_num]; + std::string m_name; + lldb::addr_t m_link_map; + lldb::addr_t m_base; + bool m_base_is_offset; + lldb::addr_t m_dynamic; + }; + + LoadedModuleInfoList () + : 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; +}; +} // namespace lldb_private + +#endif // liblldb_LoadedModuleInfoList_h_ Index: include/lldb/Target/Process.h =================================================================== --- include/lldb/Target/Process.h +++ include/lldb/Target/Process.h @@ -30,6 +30,7 @@ #include "lldb/Core/Communication.h" #include "lldb/Core/Error.h" #include "lldb/Core/Event.h" +#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Core/ThreadSafeValue.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/StructuredData.h" @@ -1152,6 +1153,12 @@ return 0; } + virtual size_t + LoadModules (LoadedModuleInfoList &) + { + return 0; + } + protected: virtual JITLoaderList & GetJITLoaders (); Index: source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -20,6 +20,10 @@ #include "lldb/lldb-types.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Core/LoadedModuleInfoList.h" + +using lldb_private::LoadedModuleInfoList; + namespace lldb_private { class Process; } @@ -201,6 +205,9 @@ Rendezvous m_current; Rendezvous m_previous; + /// List of currently loaded SO modules + LoadedModuleInfoList m_loaded_modules; + /// List of SOEntry objects corresponding to the current link map state. SOEntryList m_soentries; @@ -240,13 +247,29 @@ /// Updates the current set of SOEntries, the set of added entries, and the /// set of removed entries. bool - UpdateSOEntries(); + UpdateSOEntries(bool fromRemote = false); + + bool + FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, + SOEntry &entry); + + bool + SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list); bool - UpdateSOEntriesForAddition(); + AddSOEntriesFromRemote(LoadedModuleInfoList &module_list); bool - UpdateSOEntriesForDeletion(); + RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list); + + bool + AddSOEntries(); + + bool + RemoveSOEntries(); + + void + UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path); bool SOEntryIsMainExecutable(const SOEntry &entry); Index: source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -107,6 +107,7 @@ m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), m_previous(), + m_loaded_modules(), m_soentries(), m_added_soentries(), m_removed_soentries() @@ -181,6 +182,9 @@ m_previous = m_current; m_current = info; + if (UpdateSOEntries (true)) + return true; + return UpdateSOEntries(); } @@ -191,18 +195,23 @@ } bool -DYLDRendezvous::UpdateSOEntries() +DYLDRendezvous::UpdateSOEntries(bool fromRemote) { SOEntry entry; + LoadedModuleInfoList module_list; - if (m_current.map_addr == 0) + // If we can't get the SO info from the remote, return failure. + if (fromRemote && m_process->LoadModules (module_list) == 0) + return false; + + if (!fromRemote && m_current.map_addr == 0) return false; // When the previous and current states are consistent this is the first // time we have been asked to update. Just take a snapshot of the currently // loaded modules. - if (m_previous.state == eConsistent && m_current.state == eConsistent) - return TakeSnapshot(m_soentries); + if (m_previous.state == eConsistent && m_current.state == eConsistent) + return fromRemote ? SaveSOEntriesFromRemote(module_list) : TakeSnapshot(m_soentries); // If we are about to add or remove a shared object clear out the current // state and take a snapshot of the currently loaded images. @@ -215,6 +224,9 @@ return false; m_soentries.clear(); + if (fromRemote) + return SaveSOEntriesFromRemote(module_list); + m_added_soentries.clear(); m_removed_soentries.clear(); return TakeSnapshot(m_soentries); @@ -224,15 +236,133 @@ // Otherwise check the previous state to determine what to expect and update // accordingly. if (m_previous.state == eAdd) - return UpdateSOEntriesForAddition(); + return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries(); else if (m_previous.state == eDelete) - return UpdateSOEntriesForDeletion(); + return fromRemote ? RemoveSOEntriesFromRemote(module_list) : RemoveSOEntries(); return false; } - + bool -DYLDRendezvous::UpdateSOEntriesForAddition() +DYLDRendezvous::FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, + SOEntry &entry) +{ + addr_t link_map_addr; + addr_t base_addr; + addr_t dyn_addr; + std::string name; + + if (!modInfo.get_link_map (link_map_addr) || + !modInfo.get_base (base_addr) || + !modInfo.get_dynamic (dyn_addr) || + !modInfo.get_name (name)) + return false; + + entry.link_addr = link_map_addr; + entry.base_addr = base_addr; + entry.dyn_addr = dyn_addr; + + entry.file_spec.SetFile(name, false); + + UpdateBaseAddrIfNecessary(entry, name); + + // not needed if we're using ModuleInfos + entry.next = 0; + entry.prev = 0; + entry.path_addr = 0; + + return true; +} + +bool +DYLDRendezvous::SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & modInfo : module_list.m_list) + { + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } + + m_loaded_modules = module_list; + return true; + +} + +bool +DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & modInfo : module_list.m_list) + { + bool found = false; + for (auto const & existing : m_loaded_modules.m_list) + { + if (modInfo == existing) + { + found = true; + break; + } + } + + if (found) + continue; + + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } + + m_loaded_modules = module_list; + return true; +} + +bool +DYLDRendezvous::RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list) +{ + for (auto const & existing : m_loaded_modules.m_list) + { + bool found = false; + for (auto const & modInfo : module_list.m_list) + { + if (modInfo == existing) + { + found = true; + break; + } + } + + if (found) + continue; + + SOEntry entry; + if (!FillSOEntryFromModuleInfo(existing, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + { + iterator pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + return false; + + m_soentries.erase(pos); + } + } + + m_loaded_modules = module_list; + return true; +} + +bool +DYLDRendezvous::AddSOEntries() { SOEntry entry; iterator pos; @@ -263,7 +393,7 @@ } bool -DYLDRendezvous::UpdateSOEntriesForDeletion() +DYLDRendezvous::RemoveSOEntries() { SOEntryList entry_list; iterator pos; @@ -291,7 +421,8 @@ // FreeBSD and on Android it is the full path to the executable. auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); - switch (triple.getOS()) { + switch (triple.getOS()) + { case llvm::Triple::FreeBSD: return entry.file_spec == m_exe_file_spec; case llvm::Triple::Linux: @@ -386,6 +517,21 @@ return false; } +void +DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path) +{ + // If the load bias reported by the linker is incorrect then fetch the load address of the file + // from the proc file system. + if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) + { + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + bool is_loaded = false; + Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); + if (error.Success() && is_loaded) + entry.base_addr = load_addr; + } +} + bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { @@ -427,16 +573,7 @@ std::string file_path = ReadStringFromMemory(entry.path_addr); entry.file_spec.SetFile(file_path, false); - // If the load bias reported by the linker is incorrect then fetch the load address of the file - // from the proc file system. - if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) - { - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - bool is_loaded = false; - Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); - if (error.Success() && is_loaded) - entry.base_addr = load_addr; - } + UpdateBaseAddrIfNecessary(entry, file_path); return true; } Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -27,6 +27,7 @@ #include "lldb/Core/StringList.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Core/LoadedModuleInfoList.h" #include "lldb/Host/HostThread.h" #include "lldb/lldb-private-forward.h" #include "lldb/Utility/StringExtractor.h" @@ -245,6 +246,9 @@ uint32_t &update) override; size_t + LoadModules(LoadedModuleInfoList &module_list) override; + + size_t LoadModules() override; Error @@ -261,8 +265,6 @@ friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; - class GDBLoadedModuleInfoList; - //------------------------------------------------------------------ /// Broadcaster event bits definitions. //------------------------------------------------------------------ @@ -461,7 +463,7 @@ // Query remote GDBServer for a detailed loaded library list Error - GetLoadedModuleList (GDBLoadedModuleInfoList &); + GetLoadedModuleList (LoadedModuleInfoList &); lldb::ModuleSP LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr, bool value_is_offset); Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -173,118 +173,6 @@ } // 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_base_is_offset (bool is_offset) - { - m_base_is_offset = is_offset; - } - bool get_base_is_offset(bool & out) const - { - out = m_base_is_offset; - 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; - bool m_base_is_offset; - 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. @@ -3051,7 +2939,7 @@ // the loaded module list can also provides a link map address if (addr == LLDB_INVALID_ADDRESS) { - GDBLoadedModuleInfoList list; + LoadedModuleInfoList list; if (GetLoadedModuleList (list).Success()) addr = list.m_link_map; } @@ -4703,7 +4591,7 @@ } Error -ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list) +ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list) { // Make sure LLDB has an XML parser it can use first if (!XMLDocument::XMLEnabled()) @@ -4747,7 +4635,7 @@ root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - GDBLoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { @@ -4817,7 +4705,7 @@ return Error(); root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { - GDBLoadedModuleInfoList::LoadedModuleInfo module; + LoadedModuleInfoList::LoadedModuleInfo module; llvm::StringRef name = library.GetAttributeValue("name"); module.set_name(name.str()); @@ -4879,19 +4767,18 @@ } size_t -ProcessGDBRemote::LoadModules () +ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list) { 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) + for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) { std::string mod_name; lldb::addr_t mod_base; @@ -4942,6 +4829,14 @@ } return new_modules.GetSize(); + +} + +size_t +ProcessGDBRemote::LoadModules () +{ + LoadedModuleInfoList module_list; + return LoadModules (module_list); } Error