public static DkmProcess GetDebuggedProcess(Debugger debugger) { DkmProcess[] procs = DkmProcess.GetProcesses(); if (procs.Length == 1) { return procs[0]; } else if (procs.Length > 1) { foreach (DkmProcess proc in procs) { if (proc.Path == debugger.CurrentProcess.Name) return proc; } } return null; }
private static DkmProcess GetDebuggedProcess(Debugger debugger) { DkmProcess[] procs = DkmProcess.GetProcesses(); if (procs.Length == 1) { return(procs[0]); } else if (procs.Length > 1) { foreach (DkmProcess proc in procs) { if (proc.Path == debugger.CurrentProcess.Name) { return(proc); } } } return(null); }
// https://stackoverflow.com/questions/45570027/retrieving-data-from-arbitrary-memory-addresses-using-vsix // https://social.msdn.microsoft.com/Forums/en-US/030cef1c-ee79-46e9-8e40-bfc59f14cc34/how-can-i-send-a-custom-debug-event-to-my-idebugeventcallback2-handler?forum=vsdebug // https://macropolygon.wordpress.com/2012/12/16/evaluating-debugged-process-memory-in-a-visual-studio-extension/ private static DkmProcess GetDebuggedProcess(Debugger debugger) { /* * // EnvDTE90a * StackFrame2 currentFrame2 = debugger.CurrentStackFrame as StackFrame2; * if (currentFrame2 != null) * { * uint currentFrameDepth = currentFrame2.Depth - 1; * } */ /* * DkmStackFrame dkmFrame = DkmStackFrame.ExtractFromDTEObject(debugger.CurrentStackFrame); * if (dkmFrame != null) * { * var dkmThread = dkmFrame.Thread; * var dkmProcess = dkmFrame.Process; * } */ /* * DkmStackFrame frame = DkmStackFrame.ExtractFromDTEObject(debugger.CurrentStackFrame); * if (frame == null) * return null; * return frame.Process; */ DkmProcess[] procs = DkmProcess.GetProcesses(); if (procs.Length == 1) { return(procs[0]); } else if (procs.Length > 1) { foreach (DkmProcess proc in procs) { if (proc.Path == debugger.CurrentProcess.Name) { return(proc); } } } return(null); }
private static DkmClrModuleInstance FindClrModuleInstance(Guid mvid) { foreach (var process in DkmProcess.GetProcesses()) { foreach (var runtimeInstance in process.GetRuntimeInstances()) { if (runtimeInstance.TagValue == DkmRuntimeInstance.Tag.ClrRuntimeInstance) { foreach (var moduleInstance in runtimeInstance.GetModuleInstances()) { if (moduleInstance.TagValue == DkmModuleInstance.Tag.ClrModuleInstance && moduleInstance is DkmClrModuleInstance clrModuleInstance && clrModuleInstance.Mvid == mvid) { return(clrModuleInstance); } } } } } return(null); }
/// <summary> /// Retrieves active statements from the debuggee process. /// Shall only be called while in debug mode. /// Can be invoked on any thread. /// </summary> public Task <ImmutableArray <ActiveStatementDebugInfo> > GetActiveStatementsAsync(CancellationToken cancellationToken) { using (DebuggerComponent.ManagedEditAndContinueService()) { // TODO: return empty outside of debug session. // https://github.com/dotnet/roslyn/issues/24325 int unexpectedError = 0; var completion = new TaskCompletionSource <ImmutableArray <ActiveStatementDebugInfo> >(); var builders = default(ArrayBuilder <ArrayBuilder <ActiveStatementDebugInfo> >); int pendingRuntimes = 0; int runtimeCount = 0; var workList = DkmWorkList.Create(CompletionRoutine: _ => { completion.TrySetException(new InvalidOperationException($"Unexpected error enumerating active statements: 0x{unexpectedError:X8}")); }); void CancelWork() { if (builders != null) { FreeBuilders(builders); builders = null; // TODO: DkmWorkList.Cancel doesn't currently work when invoked on the completion callback. // We continue execute all the queued callbacks -- they will be no-ops. // See https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems/edit/562781. // // workList.Cancel(); // make sure we cancel with the token we received from the caller: completion.TrySetCanceled(cancellationToken); } } foreach (var process in DkmProcess.GetProcesses()) { foreach (var runtimeInstance in process.GetRuntimeInstances()) { if (runtimeInstance.TagValue == DkmRuntimeInstance.Tag.ClrRuntimeInstance) { var clrRuntimeInstance = (DkmClrRuntimeInstance)runtimeInstance; int runtimeIndex = runtimeCount; runtimeCount++; clrRuntimeInstance.GetActiveStatements(workList, activeStatementsResult => { if (cancellationToken.IsCancellationRequested) { CancelWork(); return; } if (activeStatementsResult.ErrorCode != 0) { unexpectedError = activeStatementsResult.ErrorCode; return; } // group active statement by instruction and aggregate flags and threads: var instructionMap = PooledDictionary <ActiveInstructionId, (DkmInstructionSymbol Symbol, ArrayBuilder <Guid> Threads, int Index, ActiveStatementFlags Flags)> .GetInstance(); GroupActiveStatementsByInstructionId(instructionMap, activeStatementsResult.ActiveStatements); int pendingStatements = instructionMap.Count; builders[runtimeIndex] = ArrayBuilder <ActiveStatementDebugInfo> .GetInstance(pendingStatements); builders[runtimeIndex].Count = pendingStatements; foreach (var(instructionId, (symbol, threads, index, flags)) in instructionMap) { var immutableThreads = threads.ToImmutableAndFree(); symbol.GetSourcePosition(workList, DkmSourcePositionFlags.None, InspectionSession: null, sourcePositionResult => { if (cancellationToken.IsCancellationRequested) { CancelWork(); return; } int errorCode = sourcePositionResult.ErrorCode; if (errorCode != 0) { unexpectedError = errorCode; } DkmSourcePosition position; string documentNameOpt; LinePositionSpan span; if (errorCode == 0 && (position = sourcePositionResult.SourcePosition) != null) { documentNameOpt = position.DocumentName; span = ToLinePositionSpan(position.TextSpan); } else { // The debugger can't determine source location for the active statement. // The PDB might not be available or the statement is in a method that doesn't have debug information. documentNameOpt = null; span = default; } builders[runtimeIndex][index] = new ActiveStatementDebugInfo( instructionId, documentNameOpt, span, immutableThreads, flags); // the last active statement of the current runtime has been processed: if (Interlocked.Decrement(ref pendingStatements) == 0) { // the last active statement of the last runtime has been processed: if (Interlocked.Decrement(ref pendingRuntimes) == 0) { completion.TrySetResult(builders.ToFlattenedImmutableArrayAndFree()); } } }); } instructionMap.Free(); });
private static DkmProcess GetProcess(uint processId) { return(DkmProcess.GetProcesses()[(int)processId]); }
/// <summary> /// Retrieves active statements from the debuggee process. /// Shall only be called while in debug mode. /// Can be invoked on any thread. /// </summary> public Task <ImmutableArray <ActiveStatementDebugInfo> > GetActiveStatementsAsync(CancellationToken cancellationToken) { using (DebuggerComponent.ManagedEditAndContinueService()) { // TODO: return empty outside of debug session. // https://github.com/dotnet/roslyn/issues/24325 var completion = new TaskCompletionSource <ImmutableArray <ActiveStatementDebugInfo> >(); var builders = default(ArrayBuilder <ArrayBuilder <ActiveStatementDebugInfo> >); int pendingRuntimes = 0; int runtimeCount = 0; // No exception should be thrown in case of errors on the debugger side. // The debugger is responsible to provide telemetry for error cases. // The callback should not be called, but it's there to guarantee that the task completes and a hang is avoided. var workList = DkmWorkList.Create(_ => { completion.TrySetResult(ImmutableArray <ActiveStatementDebugInfo> .Empty); }); void CancelWork() { if (builders != null) { FreeBuilders(builders); builders = null; workList.Cancel(blockOnCompletion: false); // make sure we cancel with the token we received from the caller: completion.TrySetCanceled(cancellationToken); } } foreach (var process in DkmProcess.GetProcesses()) { foreach (var runtimeInstance in process.GetRuntimeInstances()) { if (runtimeInstance.TagValue == DkmRuntimeInstance.Tag.ClrRuntimeInstance) { var clrRuntimeInstance = (DkmClrRuntimeInstance)runtimeInstance; int runtimeIndex = runtimeCount; runtimeCount++; clrRuntimeInstance.GetActiveStatements(workList, activeStatementsResult => { try { if (cancellationToken.IsCancellationRequested) { CancelWork(); return; } var localBuilders = builders; if (localBuilders == null) // e.g. cancelled { return; } if (activeStatementsResult.ErrorCode != 0) { localBuilders[runtimeIndex] = ArrayBuilder <ActiveStatementDebugInfo> .GetInstance(0); // the last active statement of the last runtime has been processed: if (Interlocked.Decrement(ref pendingRuntimes) == 0) { completion.TrySetResult(localBuilders.ToFlattenedImmutableArrayAndFree()); } return; } // group active statement by instruction and aggregate flags and threads: var instructionMap = PooledDictionary <ActiveInstructionId, (DkmInstructionSymbol Symbol, ArrayBuilder <Guid> Threads, int Index, ActiveStatementFlags Flags)> .GetInstance(); GroupActiveStatementsByInstructionId(instructionMap, activeStatementsResult.ActiveStatements); int pendingStatements = instructionMap.Count; localBuilders[runtimeIndex] = ArrayBuilder <ActiveStatementDebugInfo> .GetInstance(pendingStatements); localBuilders[runtimeIndex].Count = pendingStatements; if (instructionMap.Count == 0) { if (Interlocked.Decrement(ref pendingRuntimes) == 0) { completion.TrySetResult(localBuilders.ToFlattenedImmutableArrayAndFree()); } return; } foreach (var(instructionId, (symbol, threads, index, flags)) in instructionMap) { var immutableThreads = threads.ToImmutableAndFree(); symbol.GetSourcePosition(workList, DkmSourcePositionFlags.None, InspectionSession: null, sourcePositionResult => { try { if (cancellationToken.IsCancellationRequested) { CancelWork(); return; } DkmSourcePosition position; string documentNameOpt; LinePositionSpan span; if (sourcePositionResult.ErrorCode == 0 && (position = sourcePositionResult.SourcePosition) != null) { documentNameOpt = position.DocumentName; span = ToLinePositionSpan(position.TextSpan); } else { // The debugger can't determine source location for the active statement. // The PDB might not be available or the statement is in a method that doesn't have debug information. documentNameOpt = null; span = default; } localBuilders[runtimeIndex][index] = new ActiveStatementDebugInfo( instructionId, documentNameOpt, span, immutableThreads, flags); // the last active statement of the current runtime has been processed: if (Interlocked.Decrement(ref pendingStatements) == 0) { // the last active statement of the last runtime has been processed: if (Interlocked.Decrement(ref pendingRuntimes) == 0) { completion.TrySetResult(localBuilders.ToFlattenedImmutableArrayAndFree()); } } } catch (Exception e) { completion.TrySetException(e); } }); } instructionMap.Free(); }