in src/OpenDebugAD7/AD7DebugSession.cs [1120:1305]
protected override void HandleAttachRequestAsync(IRequestResponder<AttachArguments> responder)
{
const string telemetryEventName = DebuggerTelemetry.TelemetryAttachEventName;
// ProcessId can be either a string or an int. We attempt to parse as int, if that does not exist we attempt to parse as a string.
string processId = responder.Arguments.ConfigurationProperties.GetValueAsInt("processId")?.ToString(CultureInfo.InvariantCulture) ?? responder.Arguments.ConfigurationProperties.GetValueAsString("processId");
string miDebuggerServerAddress = responder.Arguments.ConfigurationProperties.GetValueAsString("miDebuggerServerAddress");
DateTime attachStartTime = DateTime.Now;
JObject pipeTransport = responder.Arguments.ConfigurationProperties.GetValueAsObject("pipeTransport");
bool isPipeTransport = (pipeTransport != null);
bool isLocal = string.IsNullOrEmpty(miDebuggerServerAddress) && !isPipeTransport;
string mimode = responder.Arguments.ConfigurationProperties.GetValueAsString("MIMode");
bool useExtendedRemote = responder.Arguments.ConfigurationProperties.GetValueAsBool("useExtendedRemote").GetValueOrDefault(false);
if (isLocal)
{
if (string.IsNullOrEmpty(processId))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1001, "attach: property 'processId' needs to be specified"));
return;
}
}
else
{
string propertyCausingRemote = !string.IsNullOrEmpty(miDebuggerServerAddress) ? "miDebuggerServerAddress" : "pipeTransport";
if (!string.IsNullOrEmpty(miDebuggerServerAddress) && !string.IsNullOrEmpty(processId) && !useExtendedRemote)
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1002, "attach: 'useExtendedRemote' needs to be set to true when 'processId' is used with " + propertyCausingRemote));
return;
}
else if (isPipeTransport && (string.IsNullOrEmpty(processId) || string.IsNullOrEmpty(pipeTransport.GetValueAsString("debuggerPath"))))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1001, "attach: properties 'processId' and 'debuggerPath' needs to be specified with " + propertyCausingRemote));
return;
}
}
int pid = 0;
ProtocolException protocolException = isLocal ? VerifyLocalProcessId(processId, telemetryEventName, out pid) : VerifyProcessId(processId, telemetryEventName, out pid);
if (protocolException != null)
{
responder.SetError(protocolException);
return;
}
SetCommonDebugSettings(responder.Arguments.ConfigurationProperties);
string program = responder.Arguments.ConfigurationProperties.GetValueAsString("program");
string executable = null;
bool success = false;
try
{
lock (m_lock)
{
Debug.Assert(m_currentLaunchState == null, "Concurrent launches??");
m_currentLaunchState = new CurrentLaunchState();
}
var eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_Attach);
if (isPipeTransport)
{
if (string.IsNullOrEmpty(pipeTransport.GetValueAsString("debuggerPath")))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1011, "debuggerPath is required for attachTransport."));
return;
}
if (string.IsNullOrEmpty(program))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1009, "attach: property 'program' is missing or empty"));
return;
}
else
{
executable = program;
}
m_isAttach = true;
}
else
{
if (string.IsNullOrEmpty(program))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1009, "attach: property 'program' is missing or empty"));
return;
}
if (!ValidateProgramPath(ref program, mimode))
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1010, String.Format(CultureInfo.CurrentCulture, "attach: program path '{0}' does not exist", program)));
return;
}
executable = program;
m_isAttach = true;
}
if (int.TryParse(processId, NumberStyles.None, CultureInfo.InvariantCulture, out m_processId))
{
m_processId = Constants.InvalidProcessId;
}
m_processName = program ?? string.Empty;
SetCommonMISettings(responder.Arguments.ConfigurationProperties);
string launchJson = JsonConvert.SerializeObject(responder.Arguments.ConfigurationProperties);
// attach
int hr = m_engineLaunch.LaunchSuspended(null, m_port, executable, null, null, null, launchJson, 0, 0, 0, 0, this, out m_process);
if (hr != HRConstants.S_OK)
{
// If the engine raised a message via an error event, fire that instead
if (hr == HRConstants.E_ABORT)
{
string message;
lock (m_lock)
{
message = m_currentLaunchState?.CurrentError?.Item2;
m_currentLaunchState = null;
}
if (message != null)
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1012, message));
return;
}
}
eb.ThrowHR(hr);
}
hr = m_engineLaunch.ResumeProcess(m_process);
if (hr < 0)
{
// try to terminate the process if we can
try
{
m_engineLaunch.TerminateProcess(m_process);
}
catch
{
// Ignore failures since we are already dealing with an error
}
eb.ThrowHR(hr);
}
var properties = new Dictionary<string, object>(StringComparer.Ordinal);
properties.Add(DebuggerTelemetry.TelemetryMIMode, mimode);
properties.Add(DebuggerTelemetry.TelemetryFrameworkVersion, GetFrameworkVersionAttributeValue());
DebuggerTelemetry.ReportTimedEvent(telemetryEventName, DateTime.Now - attachStartTime, properties);
success = true;
responder.SetResponse(new AttachResponse());
}
catch (Exception e)
{
responder.SetError(CreateProtocolExceptionAndLogTelemetry(telemetryEventName, 1007, string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_ExceptionOccured, e.InnerException?.ToString() ?? e.ToString())));
}
finally
{
// Clear _currentLaunchState
CurrentLaunchState currentLaunchState;
lock (m_lock)
{
currentLaunchState = m_currentLaunchState;
m_currentLaunchState = null;
}
// If we had an error event that we didn't wind up returning as an exception, raise it as an event
Tuple<MessagePrefix, string> currentError = currentLaunchState?.CurrentError;
if (currentError != null)
{
SendMessageEvent(currentError.Item1, currentError.Item2);
}
if (!success)
{
m_process = null;
this.Protocol.Stop();
}
}
}