summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
authorAidan Dodds <aidan@codeplay.com>2015-05-08 09:36:31 +0000
committerAidan Dodds <aidan@codeplay.com>2015-05-08 09:36:31 +0000
commitc0c838516d9d89330c6498c983b770a7e4ea1e1b (patch)
tree315d5f18ddd29d9e6a937b94e94f8f67101f7179 /lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
parent3a6cc51cb90cba16c4485412b71964c89dcb8cd4 (diff)
downloadbcm5719-llvm-c0c838516d9d89330c6498c983b770a7e4ea1e1b.tar.gz
bcm5719-llvm-c0c838516d9d89330c6498c983b770a7e4ea1e1b.zip
This patch allows LLDB to use the $qXfer:Libraries: packet.
Differential Revision: http://reviews.llvm.org/D9471 llvm-svn: 236817
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp335
1 files changed, 330 insertions, 5 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 3a91e11ae98..bb99d13fa54 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -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
{
OpenPOWER on IntegriCloud