Changeset View
Standalone View
source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Context not available. | |||||
m_waiting_for_attach (false), | m_waiting_for_attach (false), | ||||
m_destroy_tried_resuming (false), | m_destroy_tried_resuming (false), | ||||
m_command_sp (), | m_command_sp (), | ||||
m_breakpoint_pc_offset (0) | m_breakpoint_pc_offset (0), | ||||
m_gdb_loaded_module_info_list() | |||||
clayborg: Don't need this as a member variable right? We will call Process::LoadModules() from the… | |||||
{ | { | ||||
m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); | m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); | ||||
m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); | m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); | ||||
Context not available. | |||||
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 (); | ||||
Context not available. | |||||
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 also provides a link map address | |||||
if ( addr == LLDB_INVALID_ADDRESS ) { | |||||
if (GetLoadedModuleList().Success()) | |||||
addr = m_gdb_loaded_module_info_list.m_link_map; | |||||
} | |||||
return addr; | |||||
} | } | ||||
//------------------------------------------------------------------ | //------------------------------------------------------------------ | ||||
Context not available. | |||||
// 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 | ||||
Not Done ReplyInline ActionsChage this function to use a local copy of GDBLoadedModuleInfoList and do the loading all within this function. You will probably need to set the executable in the target if needed, then add all other modules, then update the load location _after_ changing the executable. When calling Target::SetExecutableModule() it will clear the target module list and if any modules were loaded before this, they will be unloaded (because they are being removed from the target, so we don't want to have section load info for a module that the target doesn't have anymore...). clayborg: Chage this function to use a local copy of GDBLoadedModuleInfoList and do the loading all… | |||||
Context not available. | |||||
return true; | return true; | ||||
} | } | ||||
Error | |||||
ProcessGDBRemote::GetLoadedModuleList () | |||||
{ | |||||
Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS); | |||||
if (log) | |||||
log->Printf ("ProcessGDBRemote::%s", __FUNCTION__); | |||||
// if we have already pulled the info then return | |||||
if ( m_gdb_loaded_module_info_list.m_was_pulled ) | |||||
return Error( ); | |||||
// 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); | |||||
m_gdb_loaded_module_info_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 | |||||
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); | |||||
m_gdb_loaded_module_info_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()); | |||||
} | |||||
m_gdb_loaded_module_info_list.add (module); | |||||
} | |||||
// we have managed to pull the loaded library info | |||||
m_gdb_loaded_module_info_list.m_was_pulled = true; | |||||
if (log) | |||||
log->Printf ("found %" PRId32 " modules in total", (int) m_gdb_loaded_module_info_list.m_list.size()); | |||||
return Error(); | |||||
} | |||||
#else // if defined( LIBXML2_DEFINED ) | #else // if defined( LIBXML2_DEFINED ) | ||||
using namespace lldb_private::process_gdb_remote; | using namespace lldb_private::process_gdb_remote; | ||||
Error | |||||
ProcessGDBRemote::GetLoadedModuleList () | |||||
{ | |||||
// 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; | ||||
Context not available. | |||||
#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 () | |||||
clayborgUnsubmitted Not Done ReplyInline ActionsWe might need to call Target::SetExecutable(..) in here if the executable changes. Take care of that here _before_ you load anything in the target. If you call Target:SetExecutable() after this, all of your load info will get blown away. clayborg: We might need to call Target::SetExecutable(..) in here if the executable changes. Take care of… | |||||
{ | |||||
using lldb_private::process_gdb_remote::ProcessGDBRemote; | |||||
using lldb_private::process_gdb_remote::GDBLoadedModuleInfoList; | |||||
// request a list of loaded libraries from GDBServer | |||||
if (GetLoadedModuleList().Fail()) | |||||
return 0; | |||||
// get a list of all the modules | |||||
ModuleList &loaded_modules = m_process->GetTarget().GetImages(); | |||||
ModuleList new_modules; | |||||
for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : m_gdb_loaded_module_info_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()) | |||||
{ | |||||
loaded_modules.AppendIfNeeded (module_sp); | |||||
new_modules.Append (module_sp); | |||||
} | |||||
} | |||||
if (new_modules.GetSize() > 0) | |||||
m_process->GetTarget().ModulesDidLoad (new_modules); | |||||
return new_modules.GetSize(); | |||||
} | |||||
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed | class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed | ||||
{ | { | ||||
Context not available. | |||||
Not Done ReplyInline ActionsShould this be negated? Why would we check if the file doesn't exist and return it? clayborg: Should this be negated? Why would we check if the file doesn't exist and return it? | |||||
Not Done ReplyInline ActionsPlease add "_sp" suffix to shared pointer variables. So this should be "executable_sp" clayborg: Please add "_sp" suffix to shared pointer variables. So this should be "executable_sp" | |||||
Not Done ReplyInline ActionsYou don't need he ".get()" you can just write: if (!executable_sp) clayborg: You don't need he ".get()" you can just write:
```if (!executable_sp)``` | |||||
Not Done ReplyInline ActionsDoesn't this code need to get the executable from the GDB info? How can we continue to use the wrong executable? What if we do: (lldb) target create a.out Then we attach and the program is "b.out"? We would have a valid executable, but it needs to be changed to "b.out". clayborg: Doesn't this code need to get the executable from the GDB info? How can we continue to use the… | |||||
Not Done ReplyInline ActionsWe need to get the executable from the GDBLoadedModuleInfoList and verify our target has the right executable. Is this being done somewhere that I am missing? See my example above where we create a target with "a.out" then we attach to a program that is "b.out". Make sure that works. clayborg: We need to get the executable from the GDBLoadedModuleInfoList and verify our target has the… |
Don't need this as a member variable right? We will call Process::LoadModules() from the dynamic loader when needed.