[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