Index: include/lldb/API/SBTarget.h =================================================================== --- include/lldb/API/SBTarget.h +++ include/lldb/API/SBTarget.h @@ -914,6 +914,9 @@ void SetSP (const lldb::TargetSP& target_sp); + static lldb::ProcessSP + AttachToProcess (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Target &target, SBListener &listener, lldb_private::Error &error); + private: //------------------------------------------------------------------ Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -613,7 +613,6 @@ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) @@ -622,72 +621,35 @@ if (target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) + ProcessAttachInfo &attach_info = sb_attach_info.ref(); + if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid()) { - state = process_sp->GetState(); - - if (process_sp->IsAlive() && state != eStateConnected) + PlatformSP platform_sp = target_sp->GetPlatform(); + // See if we can pre-verify if a process exists or not + if (platform_sp && platform_sp->IsConnected()) { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); + lldb::pid_t attach_pid = attach_info.GetProcessID(); + ProcessInstanceInfo instance_info; + if (platform_sp->GetProcessInfo(attach_pid, instance_info)) + { + attach_info.SetUserID(instance_info.GetEffectiveUserID()); + } else - error.SetErrorString ("a process is already being debugged"); - if (log) - log->Printf ("SBTarget(%p)::Attach (...) => error %s", - static_cast(target_sp.get()), - error.GetCString()); - return sb_process; - } - } - - if (state != eStateConnected) - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - - if (process_sp) - { - ProcessAttachInfo &attach_info = sb_attach_info.ref(); - if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid()) - { - PlatformSP platform_sp = target_sp->GetPlatform(); - // See if we can pre-verify if a process exists or not - if (platform_sp && platform_sp->IsConnected()) { - lldb::pid_t attach_pid = attach_info.GetProcessID(); - ProcessInstanceInfo instance_info; - if (platform_sp->GetProcessInfo(attach_pid, instance_info)) + error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid); + if (log) { - attach_info.SetUserID(instance_info.GetEffectiveUserID()); - } - else - { - error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid); - if (log) - { - log->Printf ("SBTarget(%p)::Attach (...) => error %s", - static_cast(target_sp.get()), error.GetCString()); - } - return sb_process; + log->Printf ("SBTarget(%p)::Attach (...) => error %s", + static_cast(target_sp.get()), error.GetCString()); } + return sb_process; } } - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - sb_process.SetSP (process_sp); - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); } + SBListener noop_listener; + const auto process_sp = AttachToProcess (attach_info, *target_sp, noop_listener, error.ref()); + if (error.Success () && process_sp) + sb_process.SetSP (process_sp); } else { @@ -697,7 +659,7 @@ if (log) log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)", static_cast(target_sp.get()), - static_cast(process_sp.get())); + static_cast(sb_process.GetSP().get())); return sb_process; } @@ -726,87 +688,37 @@ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...", - static_cast(target_sp.get()), pid); + log->Printf ("SBTarget(%p)::%s (listener, pid=%" PRId64 ", error)...", + static_cast(target_sp.get()), + __FUNCTION__, + pid); if (target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) - { - state = process_sp->GetState(); + ProcessAttachInfo attach_info; + attach_info.SetProcessID (pid); + if (listener.IsValid()) + attach_info.SetListener(listener.GetSP()); - if (process_sp->IsAlive() && state != eStateConnected) - { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); - else - error.SetErrorString ("a process is already being debugged"); - return sb_process; - } - } + ProcessInstanceInfo instance_info; + if (target_sp->GetPlatform ()->GetProcessInfo (pid, instance_info)) + attach_info.SetUserID (instance_info.GetEffectiveUserID ()); + const auto process_sp = AttachToProcess (attach_info, *target_sp, listener, error.ref()); - if (state == eStateConnected) - { - // If we are already connected, then we have already specified the - // listener, so if a valid listener is supplied, we need to error out - // to let the client know. - if (listener.IsValid()) - { - error.SetErrorString ("process is connected and already has a listener, pass empty listener"); - return sb_process; - } - } - else - { - if (listener.IsValid()) - process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL); - else - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - } - if (process_sp) - { + if (error.Success () && process_sp) sb_process.SetSP (process_sp); - - ProcessAttachInfo attach_info; - attach_info.SetProcessID (pid); - - PlatformSP platform_sp = target_sp->GetPlatform(); - ProcessInstanceInfo instance_info; - if (platform_sp->GetProcessInfo(pid, instance_info)) - { - attach_info.SetUserID(instance_info.GetEffectiveUserID()); - } - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } } else - { error.SetErrorString ("SBTarget is invalid"); - } if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)", - static_cast(target_sp.get()), - static_cast(process_sp.get())); + log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)", + static_cast(target_sp.get ()), + __FUNCTION__, + static_cast(sb_process.GetSP().get ())); return sb_process; } @@ -822,82 +734,35 @@ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...", - static_cast(target_sp.get()), name, + log->Printf ("SBTarget(%p)::%s (listener, name=%s, wait_for=%s, error)...", + static_cast(target_sp.get()), + __FUNCTION__, + name, wait_for ? "true" : "false"); if (name && target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) - { - state = process_sp->GetState(); - - if (process_sp->IsAlive() && state != eStateConnected) - { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); - else - error.SetErrorString ("a process is already being debugged"); - return sb_process; - } - } - - if (state == eStateConnected) - { - // If we are already connected, then we have already specified the - // listener, so if a valid listener is supplied, we need to error out - // to let the client know. - if (listener.IsValid()) - { - error.SetErrorString ("process is connected and already has a listener, pass empty listener"); - return sb_process; - } - } - else - { - if (listener.IsValid()) - process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL); - else - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - } + ProcessAttachInfo attach_info; + attach_info.GetExecutableFile().SetFile(name, false); + attach_info.SetWaitForLaunch(wait_for); + if (listener.IsValid()) + attach_info.SetListener(listener.GetSP()); - if (process_sp) - { + const auto process_sp = AttachToProcess (attach_info, *target_sp, listener, error.ref()); + if (error.Success () && process_sp) sb_process.SetSP (process_sp); - ProcessAttachInfo attach_info; - attach_info.GetExecutableFile().SetFile(name, false); - attach_info.SetWaitForLaunch(wait_for); - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } } else - { error.SetErrorString ("SBTarget is invalid"); - } if (log) - log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)", + log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)", static_cast(target_sp.get()), - static_cast(process_sp.get())); + __FUNCTION__, + static_cast(sb_process.GetSP().get())); return sb_process; } @@ -2679,3 +2544,81 @@ return 0; } +ProcessSP +SBTarget::AttachToProcess (ProcessAttachInfo &attach_info, Target &target, SBListener &listener, Error &error) +{ + error.Clear(); + + Mutex::Locker api_locker (target.GetAPIMutex ()); + + StateType state = eStateInvalid; + auto process_sp = target.GetProcessSP (); + if (process_sp) + { + state = process_sp->GetState (); + + if (process_sp->IsAlive () && state != eStateConnected) + { + if (state == eStateAttaching) + error.SetErrorString ("process attach is in progress"); + else + error.SetErrorString ("a process is already being debugged"); + return process_sp; + } + } + + ListenerSP hijack_listener_sp (new Listener ("lldb.SBTarget.AttachToProcess.attach.hijack")); + attach_info.SetHijackListener (hijack_listener_sp); + + if (state == eStateConnected) + { + // If we are already connected, then we have already specified the + // listener, so if a valid listener is supplied, we need to error out + // to let the client know. + if (listener.IsValid ()) + { + error.SetErrorString ("process is connected and already has a listener, pass empty listener"); + return process_sp; + } + error = process_sp->Attach (attach_info); + } + else + { + const auto platform_sp = target.GetPlatform (); + if (platform_sp != nullptr && platform_sp->CanDebugProcess ()) + { + process_sp = platform_sp->Attach (attach_info, target.GetDebugger (), &target, error); + } + else + { + process_sp = target.CreateProcess ( + (listener.IsValid ()) ? listener.ref () : target.GetDebugger ().GetListener (), nullptr, nullptr); + if (process_sp) + { + process_sp->HijackProcessEvents (hijack_listener_sp.get()); + error = process_sp->Attach (attach_info); + } + else + error.SetErrorString ("failed to create lldb_private::Process"); + } + } + + if (error.Success () && process_sp) + { + StreamString stream; + StateType state = process_sp->WaitForProcessToStop (nullptr, nullptr, false, attach_info.GetHijackListener ().get (), &stream); + + process_sp->RestoreProcessEvents (); + + if (state != eStateStopped) + { + const char *exit_desc = process_sp->GetExitDescription (); + if (exit_desc) + error.SetErrorStringWithFormat ("attach failed: %s", exit_desc); + else + error.SetErrorStringWithFormat ("attach failed: process did not stop (no such process or permission problem?)"); + process_sp->Destroy (); + } + } + return process_sp; +} Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -1448,6 +1448,7 @@ else if (m_is_platform) { pid = m_process_launch_info.GetProcessID (); + m_process_launch_info.Clear (); } else return SendUnimplementedResponse (packet.GetStringRef ().c_str ());