Sorry for the delayed response Greg.

I have been working on a proof of concept which adds a new dynamic loader for gdb-remote as you suggest, and perhaps when I get it working with the behavior I'm expecting, I can post it for review and we can have a look at how best to integrate something like this with upstream LLDB. Perhaps
it can indeed by integrated cleanly with the posixDYLD.

There is one issue that has emerged while I have been working on this, with regard to how LLDB regards the target executable as the first module loaded. Since the first and potentially only module that I can give to LLDB is a shared library it doesn't seem to make sense to regard it as the executable module.

My thoughts were to change the way the target handles this, so that LLDB instead looks for the first executable module loaded, which would exclude shared object.
I changed it to be something like this:

ModuleSP
Target::GetExecutableModule ()
{
    for ( uint32_t i = 0; i < (uint32_t)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;
    }
    return ModuleSP();
}

Module*
Target::GetExecutableModulePointer ()
{
    return GetExecutableModule().get();
}


This problem surfaced when I noticed the posixDYLD (which I was using at the time) takes the executable (module index 0), and forcefully sets its load address based on the entry point of the program. In the case of my shared library this is the incorrect address.

Does anyone have thoughts or opinions on this?

On 24/04/2015 18:31, Greg Clayton wrote:
A few things to check on:

lldb_private::Process already has:

     //------------------------------------------------------------------
     // Returns AUXV structure found in many ELF-based environments.
     //
     // The default action is to return an empty data buffer.
     //
     // @return
     //    A data buffer containing the contents of the AUXV data.
     //------------------------------------------------------------------
     virtual const lldb::DataBufferSP
     GetAuxvData();

Would this help?

What dynamic loader is currently being selected when you debug? 
PluginDynamicLoaderPosixDYLD? If so, maybe PluginDynamicLoaderPosixDYLD can 
just use Process::GetAuxvData()? It would be nice to abstract this through 
lldb_private::Process if PluginDynamicLoaderPosixDYLD just needs a bit of help 
to get started as I would prefer to keep using PluginDynamicLoaderPosixDYLD or 
its subclasses if possible so that we don't have to create 
DynamicLoaderGDBRemote if we don't need to.

Greg


On Apr 24, 2015, at 10:21 AM, Aidan Dodds <ai...@codeplay.com> wrote:

Thanks for the quick response Greg.

Its an interesting point you raise when it comes to knowing how any 
DynamicLoaderGDBRemote would detect newly loaded
modules.  Since my target is Linux based the standard approach of hooking the 
rendezvous address should still work.
Presumably since I will have the full list of loaded modules and their 
locations, I would be able to find ld-linux.so,
and I additionally have access to the auxvector via the $qXfer:auxv packet.  
Perhaps these will provide enough data for me
to locate the dyld rendezvous address.

Perhaps lldbPluginDynamicLoaderPosixDYLD would serve as a suitable base class 
for DynamicLoaderGDBRemote.

I'll mull over your suggestions this weekend and get back to you with something 
more concrete on Monday.
In the mean time, if anyone else also has ideas or suggestions I'm all ears.

Thanks again,
Aidan


On 24/04/2015 17:45, Greg Clayton wrote:
Actually scratch this last approach.

A better approach would be to make a new DynamicLoader subclass called 
DynamicLoaderGDBRemote. This plug-in would only be created if the process' name is 
"gdb-remote" and if the ProcessGDBRemote supports the qXfer:libraries:read 
command. Then the DynamicLoaderGDBRemote can cast the abstract lldb_private::Process to a 
ProcessGDBRemote and use any special functions in ProcessGDBRemote to get this info and 
make the shared libraries get loaded correctly.

We try to make our GDB server binaries and simple as possible and we don't vend 
shared library info from them. In this case we want to use the correct 
DynamicLoader plug-ins for the current process. It also allows us to use the 
DynamicLoader plug-ins with multiple processes. For example, 
DynamicLoaderDarwinKernel can either be used with ProcessGDBRemote or 
ProcessKDP. It just uses generic process calls on lldb_private::Process to do 
its thing so these plug-ins can work with any lldb_private::Process. In this 
case we have a case where the DynamicLoaderGDBRemote would only work with 
ProcessGDBRemote. In the static class function you would need to check the 
process plug-in name:

DynamicLoader *
DynamicLoaderGDBRemote::CreateInstance (Process* process, bool force)
{
     if (process->GetPluginName() == ProcessGDBRemote::GetPluginNameStatic())
     {
        ProcessGDBRemote* gdb_process = (ProcessGDBRemote*)process;
         if (gdb_process->Supports_qXfer_libraries())
         {
             // Create a new instance of DynamicLoaderGDBRemote and return it
         }
     }
     return NULL;
}

Then the question becomes how do shared library loaded notifications come in 
when a shared library is loaded dynamically?

Greg Clayton


On Apr 24, 2015, at 9:28 AM, Greg Clayton <gclay...@apple.com> wrote:

This if fine. We will want to make these changes as a virtual call in 
lldb_private::Process where we ask the process if it can help discover loaded shared 
libraries. The dynamic loader plug-ins will need to be modified to take advantage of this 
as they get an abstract "lldb_private::Process*" when they are created. Then 
the dynamic loader plug-ins can ask the process if they can supply the module loaded 
info, and take advantage of this if needed.

Maybe something like:

namespace lldb_private {
class Process {
...
    virtual Error GetLoadedSharedLibraries(std::vector<LoadedModuleInfo> 
&loaded_modules)
    {
        Error error;
        loaded_modules.clear();
        error.SetErrorString("unimplemented");
        return error;
    }


I don't believe qModuleInfo if the correct call to be using. I believe this is 
a platform packet only that allows you to ask about what a remote file 
contains. It answers with the info on each contained file that is contained 
within a file and returns the architecture, file offset, and file size for each 
different slice. Most files only have one item inside them, so they would 
return info on that single file. This isn't designed to be tied to a process 
nor is it designed to pass along any module load info for a specific process.

I would just use the qXfer:libraries:read command and implement this as a new call in 
"lldb_private::Process *" that returns an error in the default implementation, 
and the ProcessGDBRemote will have a override version of this function that can give us 
the info we need.

Let me know if you need any help in making this happen.

Greg

On Apr 24, 2015, at 7:06 AM, Aidan Dodds <ai...@codeplay.com> wrote:

Hi,

I would like to improve support for the case where LLDB is debugging a remote 
target (via gdbserver)
yet doesn't have access to the target executable, and only has access to a 
shared object already
loaded by the target.

This is supported from GDB, as I can connect to a remote GDBServer without 
specifying any executable,
and after issuing 'set solib-search-paths' it will resolve all of the loaded 
shared objects correctly, while
still being blind to the target executable.

I feel like LLDB should be able to connect to a remote target, and then after 
issuing a 'target modules add'
command be able to resolve its load address automatically.  I believe LLDB can 
already do this to some extent
via the 'qModuleInfo' RSP packet.

The 'qXfer:libraries:read' packet is provided by GDBServer, and will return an 
XML document containing
all of the shared objects loaded by the target and their load addresses.  It is 
possible to parse this now using the
recent libxml2 support in LLDB.

GDBRemoteCommunicationClient::GetModuleInfo() could be extended to try and gain 
information about a
loaded module via the 'qXfer:libraries:read' packet if 'qModuleInfo' fails or 
is not supported.

I would be interested to hear what others think, or get some feedback if I have 
perhaps misunderstood something.

Thanks,
Aidan Dodds

_______________________________________________
lldb-dev mailing list
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
_______________________________________________
lldb-dev mailing list
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

_______________________________________________
lldb-dev mailing list
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to