Changeset View
Changeset View
Standalone View
Standalone View
lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Show First 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | GetGlobalPluginProperties() | ||||
static ProcessKDPPropertiesSP g_settings_sp; | static ProcessKDPPropertiesSP g_settings_sp; | ||||
if (!g_settings_sp) | if (!g_settings_sp) | ||||
g_settings_sp.reset (new PluginProperties ()); | g_settings_sp.reset (new PluginProperties ()); | ||||
return g_settings_sp; | return g_settings_sp; | ||||
} | } | ||||
} // anonymous namespace end | } // 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 | // 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 | // ephemeral port from the kernel and make sure we reserve it before passing | ||||
// it to debugserver. | // it to debugserver. | ||||
#if defined (__APPLE__) | #if defined (__APPLE__) | ||||
#define LOW_PORT (IPPORT_RESERVED) | #define LOW_PORT (IPPORT_RESERVED) | ||||
#define HIGH_PORT (IPPORT_HIFIRSTAUTO) | #define HIGH_PORT (IPPORT_HIFIRSTAUTO) | ||||
#else | #else | ||||
▲ Show 20 Lines • Show All 385 Lines • ▼ Show 20 Lines | ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) | ||||
{ | { | ||||
GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); | GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); | ||||
} | } | ||||
if (reg_num == 0) | if (reg_num == 0) | ||||
{ | { | ||||
// try to extract information from servers target.xml | // try to extract information from servers target.xml | ||||
if ( GetGDBServerInfo( ) ) | if (GetGDBServerRegisterInfo ()) | ||||
return; | return; | ||||
FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); | FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); | ||||
if (target_definition_fspec) | if (target_definition_fspec) | ||||
{ | { | ||||
// See if we can get register definitions from a python file | // See if we can get register definitions from a python file | ||||
if (ParsePythonTargetDefinition (target_definition_fspec)) | if (ParsePythonTargetDefinition (target_definition_fspec)) | ||||
▲ Show 20 Lines • Show All 1,689 Lines • ▼ Show 20 Lines | |||||
ProcessGDBRemote::IsAlive () | ProcessGDBRemote::IsAlive () | ||||
{ | { | ||||
return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited; | return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited; | ||||
} | } | ||||
addr_t | addr_t | ||||
ProcessGDBRemote::GetImageInfoAddress() | 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; | |||||
} | } | ||||
//------------------------------------------------------------------ | //------------------------------------------------------------------ | ||||
// Process Memory | // Process Memory | ||||
//------------------------------------------------------------------ | //------------------------------------------------------------------ | ||||
size_t | size_t | ||||
ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) | ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,557 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
// do nothing currently | // do nothing currently | ||||
} | } | ||||
// query the target of gdb-remote for extended target information | // query the target of gdb-remote for extended target information | ||||
// return: 'true' on success | // return: 'true' on success | ||||
// 'false' on failure | // 'false' on failure | ||||
bool | bool | ||||
ProcessGDBRemote::GetGDBServerInfo () | ProcessGDBRemote::GetGDBServerRegisterInfo () | ||||
{ | { | ||||
// redirect libxml2's error handler since the default prints to stdout | // redirect libxml2's error handler since the default prints to stdout | ||||
xmlGenericErrorFunc func = libxml2NullErrorFunc; | xmlGenericErrorFunc func = libxml2NullErrorFunc; | ||||
initGenericErrorDefaultFunc( &func ); | initGenericErrorDefaultFunc( &func ); | ||||
GDBRemoteCommunicationClient & comm = m_gdb_comm; | GDBRemoteCommunicationClient & comm = m_gdb_comm; | ||||
GDBRemoteDynamicRegisterInfo & regInfo = m_register_info; | GDBRemoteDynamicRegisterInfo & regInfo = m_register_info; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | ProcessGDBRemote::GetGDBServerRegisterInfo () | ||||
} | } | ||||
// pass all of these registers to lldb | // pass all of these registers to lldb | ||||
BuildRegisters(regList, regInfo); | BuildRegisters(regList, regInfo); | ||||
return true; | 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 ) | #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 | bool | ||||
ProcessGDBRemote::GetGDBServerInfo () | ProcessGDBRemote::GetGDBServerRegisterInfo () | ||||
{ | { | ||||
// stub (libxml2 not present) | // stub (libxml2 not present) | ||||
return false; | return false; | ||||
} | } | ||||
#endif // if defined( LIBXML2_DEFINED ) | #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 | class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed | ||||
{ | { | ||||
private: | private: | ||||
public: | public: | ||||
CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : | CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : | ||||
CommandObjectParsed (interpreter, | CommandObjectParsed (interpreter, | ||||
▲ Show 20 Lines • Show All 237 Lines • Show Last 20 Lines |