Add "vAttachOrWait" to debugserver, so you can implement "attach to the process if it exists OR wait for it" without race conditions. Use that in lldb.

llvm-svn: 160578
This commit is contained in:
Jim Ingham 2012-07-20 21:37:13 +00:00
parent 5e4fe00e64
commit cd16df9154
14 changed files with 159 additions and 114 deletions

View File

@ -152,6 +152,12 @@ public:
void
SetWaitForLaunch (bool b);
bool
GetIgnoreExisting ();
void
SetIgnoreExisting (bool b);
uint32_t
GetResumeCount ();

View File

@ -836,6 +836,7 @@ public:
m_plugin_name (),
m_resume_count (0),
m_wait_for_launch (false),
m_ignore_existing (true),
m_continue_once_attached (false)
{
}
@ -845,6 +846,7 @@ public:
m_plugin_name (),
m_resume_count (0),
m_wait_for_launch (false),
m_ignore_existing (true),
m_continue_once_attached (false)
{
ProcessInfo::operator= (launch_info);
@ -864,6 +866,18 @@ public:
m_wait_for_launch = b;
}
bool
GetIgnoreExisting () const
{
return m_ignore_existing;
}
void
SetIgnoreExisting (bool b)
{
m_ignore_existing = b;
}
bool
GetContinueOnceAttached () const
{
@ -912,6 +926,8 @@ public:
m_plugin_name.clear();
m_resume_count = 0;
m_wait_for_launch = false;
m_ignore_existing = true;
m_continue_once_attached = false;
}
bool
@ -929,6 +945,7 @@ protected:
std::string m_plugin_name;
uint32_t m_resume_count; // How many times do we resume after launching
bool m_wait_for_launch;
bool m_ignore_existing;
bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached.
};

View File

@ -125,6 +125,12 @@ public:
void
SetWaitForLaunch (bool b);
bool
GetIgnoreExisting ();
void
SetIgnoreExisting (bool b);
uint32_t
GetResumeCount ();

View File

@ -369,6 +369,18 @@ SBAttachInfo::SetWaitForLaunch (bool b)
m_opaque_sp->SetWaitForLaunch (b);
}
bool
SBAttachInfo::GetIgnoreExisting ()
{
return m_opaque_sp->GetIgnoreExisting();
}
void
SBAttachInfo::SetIgnoreExisting (bool b)
{
m_opaque_sp->SetIgnoreExisting (b);
}
uint32_t
SBAttachInfo::GetUserID()
{

View File

@ -350,6 +350,10 @@ public:
case 'w':
attach_info.SetWaitForLaunch(true);
break;
case 'i':
attach_info.SetIgnoreExisting(false);
break;
default:
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
@ -618,11 +622,12 @@ protected:
OptionDefinition
CommandObjectProcessAttach::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "continue",'c', no_argument, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
{ LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
{ LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
{ LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
{ LLDB_OPT_SET_ALL, false, "continue",'c', no_argument, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
{ LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
{ LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
{ LLDB_OPT_SET_2, false, "include-existing", 'i', no_argument, NULL, 0, eArgTypeNone, "Include existing processes when doing attach -w."},
{ LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};

View File

@ -50,6 +50,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_watchpoint_support_info (eLazyBoolCalculate),
m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
m_attach_or_wait_reply(eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
@ -133,6 +134,26 @@ GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()
}
}
bool
GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()
{
if (m_attach_or_wait_reply == eLazyBoolCalculate)
{
m_attach_or_wait_reply = eLazyBoolNo;
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false))
{
if (response.IsOKResponse())
m_attach_or_wait_reply = eLazyBoolYes;
}
}
if (m_attach_or_wait_reply == eLazyBoolYes)
return true;
else
return false;
}
void
GDBRemoteCommunicationClient::ResetDiscoverableSettings()

View File

@ -221,6 +221,9 @@ public:
bool
GetVContSupported (char flavor);
bool
GetVAttachOrWaitSupported ();
void
ResetDiscoverableSettings();
@ -365,7 +368,8 @@ protected:
lldb_private::LazyBool m_supports_memory_region_info;
lldb_private::LazyBool m_supports_watchpoint_support_info;
lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
lldb_private::LazyBool m_attach_or_wait_reply;
bool
m_supports_qProcessInfoPID:1,
m_supports_qfProcessInfo:1,

View File

@ -742,6 +742,7 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
m_gdb_comm.GetListThreadsInStopReplySupported ();
m_gdb_comm.GetHostInfo ();
m_gdb_comm.GetVContSupported ('c');
m_gdb_comm.GetVAttachOrWaitSupported();
size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
for (size_t idx = 0; idx < num_cmds; idx++)
@ -929,7 +930,19 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait
StreamString packet;
if (wait_for_launch)
packet.PutCString("vAttachWait");
{
if (!m_gdb_comm.GetVAttachOrWaitSupported())
{
packet.PutCString ("vAttachWait");
}
else
{
if (attach_info.GetIgnoreExisting())
packet.PutCString("vAttachWait");
else
packet.PutCString ("vAttachOrWait");
}
}
else
packet.PutCString("vAttachName");
packet.PutChar(';');

View File

@ -2709,75 +2709,6 @@ Process::Attach (ProcessAttachInfo &attach_info)
return error;
}
//Error
//Process::Attach (const char *process_name, bool wait_for_launch)
//{
// m_abi_sp.reset();
// m_process_input_reader.reset();
//
// // Find the process and its architecture. Make sure it matches the architecture
// // of the current Target, and if not adjust it.
// Error error;
//
// if (!wait_for_launch)
// {
// ProcessInstanceInfoList process_infos;
// PlatformSP platform_sp (m_target.GetPlatform ());
// assert (platform_sp.get());
//
// if (platform_sp)
// {
// ProcessInstanceInfoMatch match_info;
// match_info.GetProcessInfo().SetName(process_name);
// match_info.SetNameMatchType (eNameMatchEquals);
// platform_sp->FindProcesses (match_info, process_infos);
// if (process_infos.GetSize() > 1)
// {
// error.SetErrorStringWithFormat ("more than one process named %s", process_name);
// }
// else if (process_infos.GetSize() == 0)
// {
// error.SetErrorStringWithFormat ("could not find a process named %s", process_name);
// }
// }
// else
// {
// error.SetErrorString ("invalid platform");
// }
// }
//
// if (error.Success())
// {
// m_dyld_ap.reset();
// m_os_ap.reset();
//
// error = WillAttachToProcessWithName(process_name, wait_for_launch);
// if (error.Success())
// {
// SetPublicState (eStateAttaching);
// error = DoAttachToProcessWithName (process_name, wait_for_launch);
// if (error.Fail())
// {
// if (GetID() != LLDB_INVALID_PROCESS_ID)
// {
// SetID (LLDB_INVALID_PROCESS_ID);
// const char *error_string = error.AsCString();
// if (error_string == NULL)
// error_string = "attach failed";
//
// SetExitStatus(-1, error_string);
// }
// }
// else
// {
// SetNextEventAction(new Process::AttachCompletionHandler(this, 0));
// StartPrivateStateThread();
// }
// }
// }
// return error;
//}
void
Process::CompleteAttach ()
{

View File

@ -499,7 +499,6 @@ GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_
else
{
// We found a matching process, add it to our list
matching_proc_infos.push_back(proc_infos[i]);
}
}
@ -513,6 +512,7 @@ GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_
nub_process_t
DNBProcessAttachWait (const char *waitfor_process_name,
nub_launch_flavor_t launch_flavor,
bool ignore_existing,
struct timespec *timeout_abstime,
useconds_t waitfor_interval,
char *err_str,
@ -536,7 +536,12 @@ DNBProcessAttachWait (const char *waitfor_process_name,
}
if (attach_token == NULL)
num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
{
if (ignore_existing)
num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
else
num_exclude_proc_infos = 0;
}
DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name);

View File

@ -48,7 +48,7 @@ nub_process_t DNBProcessLaunch (const char *path,
nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
// Resume a process with exact instructions on what to do with each thread:
// - If no thread actions are supplied (actions is NULL or num_actions is zero),
// then all threads are continued.

View File

@ -141,6 +141,7 @@ RNBRemote::CreatePacketTable ()
t.push_back (Packet (thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T", "Is thread alive"));
t.push_back (Packet (vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach", "Attach to a new process"));
t.push_back (Packet (vattachwait, &RNBRemote::HandlePacket_v, NULL, "vAttachWait", "Wait for a process to start up then attach to it"));
t.push_back (Packet (vattachorwait, &RNBRemote::HandlePacket_v, NULL, "vAttachOrWait", "Attach to the process or if it doesn't exist, wait for the process to start up then attach to it"));
t.push_back (Packet (vattachname, &RNBRemote::HandlePacket_v, NULL, "vAttachName", "Attach to an existing process by name"));
t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont;", "Verbose resume with thread actions"));
t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont?", "List valid continue-with-thread-actions actions"));
@ -169,6 +170,7 @@ RNBRemote::CreatePacketTable ()
t.push_back (Packet (query_register_info, &RNBRemote::HandlePacket_qRegisterInfo, NULL, "qRegisterInfo", "Dynamically discover remote register context information."));
t.push_back (Packet (query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr,NULL, "qShlibInfoAddr", "Returns the address that contains info needed for getting shared library notifications"));
t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported."));
t.push_back (Packet (query_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported."));
t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
// t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups"));
t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
@ -1301,6 +1303,13 @@ RNBRemote::HandlePacket_qStepPacketSupported (const char *p)
return SendPacket("OK");
}
rnb_err_t
RNBRemote::HandlePacket_qVAttachOrWaitSupported (const char *p)
{
// We support attachOrWait meaning attach if the process exists, otherwise wait to attach.
return SendPacket("OK");
}
rnb_err_t
RNBRemote::HandlePacket_qThreadStopInfo (const char *p)
{
@ -2678,6 +2687,31 @@ RNBRemote::HandlePacket_DeallocateMemory (const char *p)
return SendPacket ("E54");
}
static bool
GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name)
{
bool return_val = true;
while (*p != '\0')
{
char smallbuf[3];
smallbuf[0] = *p;
smallbuf[1] = *(p + 1);
smallbuf[2] = '\0';
errno = 0;
int ch = strtoul (smallbuf, NULL, 16);
if (errno != 0 && ch == 0)
{
return_val = false;
break;
}
attach_name.push_back(ch);
p += 2;
}
return return_val;
}
/*
vAttach;pid
@ -2781,51 +2815,37 @@ RNBRemote::HandlePacket_v (const char *p)
{
nub_process_t attach_pid = INVALID_NUB_PROCESS;
char err_str[1024]={'\0'};
if (strstr (p, "vAttachWait;") == p)
{
p += strlen("vAttachWait;");
std::string attach_name;
while (*p != '\0')
if (!GetProcessNameFrom_vAttach(p, attach_name))
{
char smallbuf[3];
smallbuf[0] = *p;
smallbuf[1] = *(p + 1);
smallbuf[2] = '\0';
errno = 0;
int ch = strtoul (smallbuf, NULL, 16);
if (errno != 0 && ch == 0)
{
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
}
attach_name.push_back(ch);
p += 2;
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
}
const bool ignore_existing = true;
attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
}
else if (strstr (p, "vAttachOrWait;") == p)
{
p += strlen("vAttachOrWait;");
std::string attach_name;
if (!GetProcessNameFrom_vAttach(p, attach_name))
{
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachOrWait' pkt");
}
const bool ignore_existing = false;
attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
}
else if (strstr (p, "vAttachName;") == p)
{
p += strlen("vAttachName;");
std::string attach_name;
while (*p != '\0')
if (!GetProcessNameFrom_vAttach(p, attach_name))
{
char smallbuf[3];
smallbuf[0] = *p;
smallbuf[1] = *(p + 1);
smallbuf[2] = '\0';
errno = 0;
int ch = strtoul (smallbuf, NULL, 16);
if (errno != 0 && ch == 0)
{
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
}
attach_name.push_back(ch);
p += 2;
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt");
}
attach_pid = DNBProcessAttachByName (attach_name.c_str(), NULL, err_str, sizeof(err_str));
@ -2845,7 +2865,9 @@ RNBRemote::HandlePacket_v (const char *p)
}
}
else
{
return HandlePacket_UNIMPLEMENTED(p);
}
if (attach_pid != INVALID_NUB_PROCESS)

View File

@ -63,6 +63,7 @@ public:
thread_alive_p, // 'T'
vattach, // 'vAttach;pid'
vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes
vattachorwait, // 'vAttachOrWait:XX...' where XX is one or more hex encoded process name ASCII bytes
vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes
vcont, // 'vCont'
vcont_list_actions, // 'vCont?'
@ -91,6 +92,7 @@ public:
query_register_info, // 'qRegisterInfo'
query_shlib_notify_info_addr, // 'qShlibInfoAddr'
query_step_packet_supported, // 'qStepPacketSupported'
query_vattachorwait_supported, // 'qVAttachOrWaitSupported'
query_host_info, // 'qHostInfo'
pass_signals_to_inferior, // 'QPassSignals'
start_noack_mode, // 'QStartNoAckMode'
@ -164,6 +166,7 @@ public:
rnb_err_t HandlePacket_qRegisterInfo (const char *p);
rnb_err_t HandlePacket_qShlibInfoAddr (const char *p);
rnb_err_t HandlePacket_qStepPacketSupported (const char *p);
rnb_err_t HandlePacket_qVAttachOrWaitSupported (const char *p);
rnb_err_t HandlePacket_qThreadInfo (const char *p);
rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
rnb_err_t HandlePacket_qThreadStopInfo (const char *p);

View File

@ -105,7 +105,7 @@ RNBRunLoopGetStartModeFromRemote (RNBRemote* remote)
err = remote->HandleReceivedPacket (&type);
// check if we tried to attach to a process
if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
{
if (err == rnb_success)
return eRNBRunLoopModeInferiorExecuting;
@ -1319,8 +1319,8 @@ main (int argc, char *argv[])
}
ctx.SetLaunchFlavor(launch_flavor);
nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
bool ignore_existing = false;
nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
g_pid = pid;
if (pid == INVALID_NUB_PROCESS)