forked from OSchip/llvm-project
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:
parent
3a6cc51cb9
commit
c0c838516d
|
@ -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 ();
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue