Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -617,7 +617,11 @@ Error Launch (ProcessLaunchInfo &launch_info, - Stream *stream); // Optional stream to receive first stop info + Stream *stream); // Optional stream to receive first stop info + + Error + Attach (ProcessAttachInfo &attach_info, + Stream *stream); // Optional stream to receive first stop info //------------------------------------------------------------------ // This part handles the breakpoints. Index: source/API/SBTarget.cpp =================================================================== --- source/API/SBTarget.cpp +++ source/API/SBTarget.cpp @@ -291,6 +291,32 @@ m_opaque_sp->SetListener(listener.GetSP()); } +namespace { + +Error +AttachToProcess (ProcessAttachInfo &attach_info, Target &target) +{ + Mutex::Locker api_locker (target.GetAPIMutex ()); + + auto process_sp = target.GetProcessSP (); + if (process_sp) + { + const auto state = process_sp->GetState (); + if (process_sp->IsAlive () && 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 (attach_info.GetListener ()) + return Error ("process is connected and already has a listener, pass empty listener"); + } + } + + return target.Attach (attach_info, nullptr); +} + +} // namespace + //---------------------------------------------------------------------- // SBTarget constructor //---------------------------------------------------------------------- @@ -613,7 +639,6 @@ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) @@ -622,72 +647,34 @@ 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"); } + error.SetError(AttachToProcess(attach_info, *target_sp)); + if (error.Success()) + sb_process.SetSP(target_sp->GetProcessSP()); } else { @@ -697,7 +684,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 +713,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(); - - 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); - } - if (process_sp) - { - sb_process.SetSP (process_sp); + ProcessAttachInfo attach_info; + attach_info.SetProcessID (pid); + if (listener.IsValid()) + attach_info.SetListener(listener.GetSP()); - ProcessAttachInfo attach_info; - attach_info.SetProcessID (pid); + ProcessInstanceInfo instance_info; + if (target_sp->GetPlatform ()->GetProcessInfo (pid, instance_info)) + attach_info.SetUserID (instance_info.GetEffectiveUserID ()); - 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"); - } + error.SetError (AttachToProcess (attach_info, *target_sp)); + if (error.Success ()) + sb_process.SetSP (target_sp->GetProcessSP ()); } 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 +759,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) - { - 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"); - } + error.SetError (AttachToProcess (attach_info, *target_sp)); + if (error.Success ()) + sb_process.SetSP (target_sp->GetProcessSP ()); } 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; } @@ -2678,4 +2568,3 @@ } return 0; } - Index: source/Commands/CommandObjectProcess.cpp =================================================================== --- source/Commands/CommandObjectProcess.cpp +++ source/Commands/CommandObjectProcess.cpp @@ -529,8 +529,6 @@ ModuleSP old_exec_module_sp = target->GetExecutableModule(); ArchSpec old_arch_spec = target->GetArchitecture(); - ProcessSP process_sp; - Error error; if (command.GetArgumentCount()) { result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); @@ -539,70 +537,21 @@ } m_interpreter.UpdateExecutionContext(nullptr); - ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack")); - m_options.attach_info.SetHijackListener(listener_sp); - - // If no process info was specified, then use the target executable - // name as the process to attach to by default - if (!m_options.attach_info.ProcessInfoSpecified ()) - { - if (old_exec_module_sp) - m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename(); - - if (!m_options.attach_info.ProcessInfoSpecified ()) - { - error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option"); - } - } - + StreamString stream; + const auto error = target->Attach(m_options.attach_info, &stream); if (error.Success()) { - if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess()) - { - target->SetPlatform(platform_sp); - process = platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), target, error).get(); - } - else - { - if (state != eStateConnected) - { - const char *plugin_name = m_options.attach_info.GetProcessPluginName(); - process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, nullptr).get(); - if (process == nullptr) - error.SetErrorStringWithFormat("failed to create process using plugin %s", plugin_name); - } - if (process) - { - process->HijackProcessEvents(listener_sp.get()); - error = process->Attach(m_options.attach_info); - } - } - } - - if (error.Success() && process != nullptr) - { - result.SetStatus (eReturnStatusSuccessContinuingNoResult); - StreamString stream; - StateType state = process->WaitForProcessToStop (nullptr, nullptr, false, listener_sp.get(), &stream); - - process->RestoreProcessEvents(); - result.SetDidChangeProcessState (true); - - if (stream.GetData()) - result.AppendMessage(stream.GetData()); - - if (state == eStateStopped) + ProcessSP process_sp (target->GetProcessSP()); + if (process_sp) { + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetStatus (eReturnStatusSuccessFinishNoResult); + result.SetDidChangeProcessState (true); } else { - const char *exit_desc = process->GetExitDescription(); - if (exit_desc) - result.AppendErrorWithFormat ("attach failed: %s", exit_desc); - else - result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); - process->Destroy(); + result.AppendError("no error returned from Target::Attach, and target has no process"); result.SetStatus (eReturnStatusFailed); } } Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -2594,6 +2594,83 @@ } return error; } + +Error +Target::Attach (ProcessAttachInfo &attach_info, Stream *stream) +{ + auto state = eStateInvalid; + auto process_sp = GetProcessSP (); + if (process_sp) + { + state = process_sp->GetState (); + if (process_sp->IsAlive () && state != eStateConnected) + { + if (state == eStateAttaching) + return Error ("process attach is in progress"); + return Error ("a process is already being debugged"); + } + } + + ListenerSP hijack_listener_sp (new Listener ("lldb.Target.Attach.attach.hijack")); + attach_info.SetHijackListener (hijack_listener_sp); + + const ModuleSP old_exec_module_sp = GetExecutableModule (); + + // If no process info was specified, then use the target executable + // name as the process to attach to by default + if (!attach_info.ProcessInfoSpecified ()) + { + if (old_exec_module_sp) + attach_info.GetExecutableFile ().GetFilename () = old_exec_module_sp->GetPlatformFileSpec ().GetFilename (); + + if (!attach_info.ProcessInfoSpecified ()) + { + return Error ("no process specified, create a target with a file, or specify the --pid or --name"); + } + } + + const auto platform_sp = GetDebugger ().GetPlatformList ().GetSelectedPlatform (); + + Error error; + if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess ()) + { + SetPlatform (platform_sp); + process_sp = platform_sp->Attach (attach_info, GetDebugger (), this, error); + } + else + { + if (state != eStateConnected) + { + const char *plugin_name = attach_info.GetProcessPluginName (); + process_sp = CreateProcess (attach_info.GetListenerForProcess (GetDebugger ()), plugin_name, nullptr); + if (process_sp == nullptr) + { + error.SetErrorStringWithFormat ("failed to create process using plugin %s", (plugin_name) ? plugin_name : "null"); + return error; + } + } + process_sp->HijackProcessEvents (hijack_listener_sp.get ()); + error = process_sp->Attach (attach_info); + } + + if (error.Success () && process_sp) + { + 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.SetErrorString ("attach failed: process did not stop (no such process or permission problem?)"); + process_sp->Destroy (); + } + } + return error; +} + //-------------------------------------------------------------- // Target::StopHook //--------------------------------------------------------------