[Lldb-commits] [lldb] r236817 - This patch allows LLDB to use the $qXfer:Libraries: packet.
Aidan Dodds
aidan at codeplay.com
Fri May 8 02:36:38 PDT 2015
Author: aidandodds
Date: Fri May 8 04:36:31 2015
New Revision: 236817
URL: http://llvm.org/viewvc/llvm-project?rev=236817&view=rev
Log:
This patch allows LLDB to use the $qXfer:Libraries: packet.
Differential Revision: http://reviews.llvm.org/D9471
Modified:
lldb/trunk/include/lldb/Target/Process.h
lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/trunk/source/Target/Target.cpp
Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=236817&r1=236816&r2=236817&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Fri May 8 04:36:31 2015
@@ -1121,6 +1121,22 @@ public:
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 ();
Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp?rev=236817&r1=236816&r2=236817&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp Fri May 8 04:36:31 2015
@@ -120,15 +120,45 @@ DynamicLoaderPOSIXDYLD::DidAttach()
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 () : "<null executable>", 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 @@ DynamicLoaderPOSIXDYLD::ComputeLoadOffse
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())
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=236817&r1=236816&r2=236817&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Fri May 8 04:36:31 2015
@@ -174,6 +174,107 @@ namespace {
} // 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<LoadedModuleInfo> 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 @@ ProcessGDBRemote::BuildDynamicRegisterIn
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 @@ ProcessGDBRemote::IsAlive ()
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 @@ libxml2NullErrorFunc (void *ctx, const c
// 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 @@ ProcessGDBRemote::GetGDBServerInfo ()
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 @@ ProcessGDBRemote::GetGDBServerInfo ()
#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
{
Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=236817&r1=236816&r2=236817&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Fri May 8 04:36:31 2015
@@ -241,15 +241,16 @@ public:
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 @@ protected:
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
Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=236817&r1=236816&r2=236817&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Fri May 8 04:36:31 2015
@@ -1057,13 +1057,24 @@ Target::IgnoreWatchpointByID (lldb::watc
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
More information about the lldb-commits
mailing list