This patch allows LLDB to use the $qXfer:Libraries: packet.

Differential Revision: http://reviews.llvm.org/D9471

llvm-svn: 236817
This commit is contained in:
Aidan Dodds 2015-05-08 09:36:31 +00:00
parent 3a6cc51cb9
commit c0c838516d
5 changed files with 411 additions and 14 deletions

View File

@ -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 ();

View File

@ -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::ComputeLoadOffset()
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())

View File

@ -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::BuildDynamicRegisterInfo (bool force)
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 char *msg, ...)
// 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
{

View File

@ -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

View File

@ -1057,13 +1057,24 @@ Target::IgnoreWatchpointByID (lldb::watch_id_t watch_id, uint32_t ignore_count)
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