PageRenderTime 71ms CodeModel.GetById 15ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

http://github.com/icsharpcode/ILSpy
C# | 872 lines | 657 code | 115 blank | 100 comment | 172 complexity | 8ddc8102376ea45717afc2eccadc49d7 MD5 | raw file
  1// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
  2// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
  3using System;
  4using System.ComponentModel.Composition;
  5using System.Diagnostics;
  6using System.Linq;
  7using System.Runtime.InteropServices;
  8using System.Text;
  9using System.Windows;
 10using System.Windows.Media;
 11
 12using Debugger;
 13using Debugger.Interop.CorPublish;
 14using Debugger.MetaData;
 15using ICSharpCode.Decompiler;
 16using ICSharpCode.ILSpy.Bookmarks;
 17using ICSharpCode.ILSpy.Debugger.Bookmarks;
 18using ICSharpCode.ILSpy.Debugger.Models.TreeModel;
 19using ICSharpCode.ILSpy.Debugger.Services.Debugger;
 20using ICSharpCode.ILSpy.Debugger.Tooltips;
 21using ICSharpCode.NRefactory;
 22using ICSharpCode.NRefactory.CSharp;
 23using ICSharpCode.NRefactory.Visitors;
 24using Mono.Cecil;
 25using CorDbg = Debugger;
 26using Process = Debugger.Process;
 27using StackFrame = Debugger.StackFrame;
 28
 29namespace ICSharpCode.ILSpy.Debugger.Services
 30{
 31	[Export(typeof(IDebugger))]
 32	public class WindowsDebugger : IDebugger
 33	{
 34		enum StopAttachedProcessDialogResult {
 35			Detach = 0,
 36			Terminate = 1,
 37			Cancel = 2
 38		}
 39		
 40		bool attached;
 41		NDebugger debugger;
 42		ICorPublish corPublish;
 43		Process debuggedProcess;
 44		
 45		//DynamicTreeDebuggerRow currentTooltipRow;
 46		//Expression             currentTooltipExpression;
 47		
 48		public event EventHandler<ProcessEventArgs> ProcessSelected;
 49		
 50		public NDebugger DebuggerCore {
 51			get {
 52				return debugger;
 53			}
 54		}
 55		
 56		public Process DebuggedProcess {
 57			get {
 58				return debuggedProcess;
 59			}
 60		}
 61		
 62		public static Process CurrentProcess {
 63			get {
 64				WindowsDebugger dbgr = DebuggerService.CurrentDebugger as WindowsDebugger;
 65				if (dbgr != null && dbgr.DebuggedProcess != null) {
 66					return dbgr.DebuggedProcess;
 67				} else {
 68					return null;
 69				}
 70			}
 71		}
 72		
 73		/// <inheritdoc/>
 74		public bool BreakAtBeginning {
 75			get;
 76			set;
 77		}
 78		
 79		protected virtual void OnProcessSelected(ProcessEventArgs e)
 80		{
 81			if (ProcessSelected != null) {
 82				ProcessSelected(this, e);
 83			}
 84		}
 85		
 86		public bool ServiceInitialized {
 87			get {
 88				return debugger != null;
 89			}
 90		}
 91		
 92		public WindowsDebugger()
 93		{
 94			
 95		}
 96		
 97		#region IDebugger Members
 98		
 99		string errorDebugging      = "Error.Debugging";
100		string errorNotDebugging   = "Error.NotDebugging";
101		string errorProcessRunning = "Error.ProcessRunning";
102		string errorProcessPaused  = "Error.ProcessPaused";
103		string errorCannotStepNoActiveFunction = "Threads.CannotStepNoActiveFunction";
104		
105		public bool IsDebugging {
106			get {
107				return ServiceInitialized && debuggedProcess != null;
108			}
109		}
110		
111		public bool IsAttached {
112			get {
113				return ServiceInitialized && attached;
114			}
115		}
116		
117		public bool IsProcessRunning {
118			get {
119				return IsDebugging && debuggedProcess.IsRunning;
120			}
121		}
122		
123		public void Start(ProcessStartInfo processStartInfo)
124		{
125			if (IsDebugging) {
126				MessageBox.Show(errorDebugging);
127				return;
128			}
129			if (!ServiceInitialized) {
130				InitializeService();
131			}
132
133			string version = debugger.GetProgramVersion(processStartInfo.FileName);
134			
135			if (version.StartsWith("v1.0")) {
136				MessageBox.Show("Net10NotSupported");
137			} else if (version.StartsWith("v1.1")) {
138				MessageBox.Show("Net1.1NotSupported");
139//					} else if (string.IsNullOrEmpty(version)) {
140//					// Not a managed assembly
141//					MessageBox.Show(".Error.BadAssembly}");
142			} else if (debugger.IsKernelDebuggerEnabled) {
143				MessageBox.Show("KernelDebuggerEnabled");
144			} else {
145				attached = false;
146				if (DebugStarting != null)
147					DebugStarting(this, EventArgs.Empty);
148				
149				try {
150					// set the JIT flag for evaluating optimized code
151					Process.DebugMode = DebugModeFlag.Debug;
152					
153					Process process = debugger.Start(processStartInfo.FileName,
154					                                 processStartInfo.WorkingDirectory,
155					                                 processStartInfo.Arguments);
156					SelectProcess(process);
157				} catch (System.Exception e) {
158					// COMException: The request is not supported. (Exception from HRESULT: 0x80070032)
159					// COMException: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x800736B1)
160					// COMException: The requested operation requires elevation. (Exception from HRESULT: 0x800702E4)
161					// COMException: The directory name is invalid. (Exception from HRESULT: 0x8007010B)
162					// BadImageFormatException:  is not a valid Win32 application. (Exception from HRESULT: 0x800700C1)
163					// UnauthorizedAccessException: ???????? ? ???????. (?????????? ?? HRESULT: 0x80070005 (E_ACCESSDENIED))
164					if (e is COMException || e is BadImageFormatException || e is UnauthorizedAccessException) {
165						string msg = "CannotStartProcess";
166						msg += " " + e.Message;
167						// TODO: Remove
168						if (e is COMException && ((uint)((COMException)e).ErrorCode == 0x80070032)) {
169							msg += Environment.NewLine + Environment.NewLine;
170							msg += "64-bit debugging is not supported.  Please set Project -> Project Options... -> Compiling -> Target CPU to 32bit.";
171						}
172						MessageBox.Show(msg);
173						
174						if (DebugStopped != null)
175							DebugStopped(this, EventArgs.Empty);
176					} else {
177						throw;
178					}
179				}
180			}
181		}
182		
183		public void Attach(System.Diagnostics.Process existingProcess)
184		{
185			if (existingProcess == null)
186				return;
187			
188			if (IsDebugging) {
189				MessageBox.Show(errorDebugging);
190				return;
191			}
192			if (!ServiceInitialized) {
193				InitializeService();
194			}
195			
196			string version = debugger.GetProgramVersion(existingProcess.MainModule.FileName);
197			if (version.StartsWith("v1.0")) {
198				MessageBox.Show("Net10NotSupported");
199			} else {
200				if (DebugStarting != null)
201					DebugStarting(this, EventArgs.Empty);
202				
203				try {
204					// set the JIT flag for evaluating optimized code
205					Process.DebugMode = DebugModeFlag.Debug;
206					
207					Process process = debugger.Attach(existingProcess);
208					attached = true;
209					SelectProcess(process);
210				} catch (System.Exception e) {
211					// CORDBG_E_DEBUGGER_ALREADY_ATTACHED
212					if (e is COMException || e is UnauthorizedAccessException) {
213						string msg = "CannotAttachToProcess";
214						MessageBox.Show(msg + " " + e.Message);
215						
216						if (DebugStopped != null)
217							DebugStopped(this, EventArgs.Empty);
218					} else {
219						throw;
220					}
221				}
222			}
223		}
224
225		public void Detach()
226		{
227			if (debuggedProcess == null)
228				return;
229			
230			debugger.Detach();
231		}
232		
233		public void StartWithoutDebugging(ProcessStartInfo processStartInfo)
234		{
235			System.Diagnostics.Process.Start(processStartInfo);
236		}
237		
238		public void Stop()
239		{
240			if (!IsDebugging) {
241				MessageBox.Show(errorNotDebugging, "Stop");
242				return;
243			}
244			if (IsAttached) {
245				Detach();
246			} else {
247				debuggedProcess.Terminate();
248			}
249		}
250		
251		// ExecutionControl:
252		
253		public void Break()
254		{
255			if (!IsDebugging) {
256				MessageBox.Show(errorNotDebugging, "Break");
257				return;
258			}
259			if (!IsProcessRunning) {
260				MessageBox.Show(errorProcessPaused, "Break");
261				return;
262			}
263			debuggedProcess.Break();
264		}
265		
266		public void Continue()
267		{
268			if (!IsDebugging) {
269				MessageBox.Show(errorNotDebugging, "Continue");
270				return;
271			}
272			if (IsProcessRunning) {
273				MessageBox.Show(errorProcessRunning, "Continue");
274				return;
275			}
276			debuggedProcess.AsyncContinue();
277		}
278		
279		// Stepping:
280		
281		SourceCodeMapping GetCurrentCodeMapping(out StackFrame frame, out bool isMatch)
282		{
283			isMatch = false;
284			frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
285			int key = frame.MethodInfo.MetadataToken;
286			
287			// get the mapped instruction from the current line marker or the next one
288			if (DebugInformation.CodeMappings == null || !DebugInformation.CodeMappings.ContainsKey(key))
289				return null;
290			
291			return DebugInformation.CodeMappings[key].GetInstructionByTokenAndOffset(frame.IP, out isMatch);
292		}
293		
294		StackFrame GetStackFrame()
295		{
296			bool isMatch;
297			StackFrame frame;
298			var map = GetCurrentCodeMapping(out frame, out isMatch);
299			if (map == null) {
300				frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
301				frame.ILRanges = new [] { 0, 1 };
302			} else {
303				//var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
304				frame.SourceCodeLine = map.StartLocation.Line;
305				frame.ILRanges = map.ToArray(isMatch);
306			}
307			
308			return frame;
309		}
310		
311		public void StepInto()
312		{
313			if (!IsDebugging) {
314				MessageBox.Show(errorNotDebugging, "StepInto");
315				return;
316			}
317			
318			// use most recent stack frame because we don't have the symbols
319			if (debuggedProcess.SelectedThread == null ||
320			    debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
321			    debuggedProcess.IsRunning) {
322				MessageBox.Show(errorCannotStepNoActiveFunction, "StepInto");
323			} else {
324				var frame = GetStackFrame();
325				if (frame != null)
326					frame.AsyncStepInto();
327			}
328		}
329		
330		public void StepOver()
331		{
332			if (!IsDebugging) {
333				MessageBox.Show(errorNotDebugging, "StepOver");
334				return;
335				
336			}
337			// use most recent stack frame because we don't have the symbols
338			if (debuggedProcess.SelectedThread == null ||
339			    debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
340			    debuggedProcess.IsRunning) {
341				MessageBox.Show(errorCannotStepNoActiveFunction, "StepOver");
342			} else {
343				var frame = GetStackFrame();
344				if (frame != null) {
345					frame.AsyncStepOver();
346					//Utils.DoEvents(frame.Process);
347				}
348			}
349		}
350		
351		public void StepOut()
352		{
353			if (!IsDebugging) {
354				MessageBox.Show(errorNotDebugging, "StepOut");
355				return;
356			}
357			
358			// use most recent stack frame because we don't have the symbols
359			if (debuggedProcess.SelectedThread == null ||
360			    debuggedProcess.SelectedThread.MostRecentStackFrame == null ||
361			    debuggedProcess.IsRunning) {
362				MessageBox.Show(errorCannotStepNoActiveFunction, "StepOut");
363			} else {
364				var frame = GetStackFrame();
365				if (frame != null)
366					frame.AsyncStepOut();
367			}
368		}
369		
370		public event EventHandler DebugStarting;
371		public event EventHandler DebugStarted;
372		public event EventHandler DebugStopped;
373		public event EventHandler IsProcessRunningChanged;
374		
375		protected virtual void OnIsProcessRunningChanged(EventArgs e)
376		{
377			if (IsProcessRunningChanged != null) {
378				IsProcessRunningChanged(this, e);
379			}
380		}
381		
382		/// <summary>
383		/// Gets variable of given name.
384		/// Returns null if unsuccessful. Can throw GetValueException.
385		/// <exception cref="GetValueException">Thrown when evaluation fails. Exception message explains reason.</exception>
386		/// </summary>
387		public Value GetValueFromName(string variableName)
388		{
389			if (!CanEvaluate) {
390				return null;
391			}
392			return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, debuggedProcess.SelectedThread.MostRecentStackFrame);
393		}
394		
395		/// <summary>
396		/// Gets Expression for given variable. Can throw GetValueException.
397		/// <exception cref="GetValueException">Thrown when getting expression fails. Exception message explains reason.</exception>
398		/// </summary>
399		public ICSharpCode.NRefactory.CSharp.Expression GetExpression(string variableName)
400		{
401			if (!CanEvaluate) {
402				throw new GetValueException("Cannot evaluate now - debugged process is either null or running or has no selected stack frame");
403			}
404			return ExpressionEvaluator.ParseExpression(variableName, SupportedLanguage.CSharp);
405		}
406		
407		public bool IsManaged(int processId)
408		{
409			corPublish = new CorpubPublishClass();
410			CorDbg.Interop.TrackedComObjects.Track(corPublish);
411			
412			ICorPublishProcess process = corPublish.GetProcess((uint)processId);
413			if (process != null) {
414				return process.IsManaged() != 0;
415			}
416			return false;
417		}
418		
419		/// <summary>
420		/// Gets the current value of the variable as string that can be displayed in tooltips.
421		/// Returns null if unsuccessful.
422		/// </summary>
423		public string GetValueAsString(string variableName)
424		{
425			try {
426				Value val = GetValueFromName(variableName);
427				if (val == null) return null;
428				return val.AsString();
429			} catch (GetValueException) {
430				return null;
431			}
432		}
433		
434		/// <inheritdoc/>
435		public bool CanEvaluate
436		{
437			get {
438				return debuggedProcess != null &&
439					!debuggedProcess.IsRunning &&
440					debuggedProcess.SelectedThread != null &&
441					debuggedProcess.SelectedThread.MostRecentStackFrame != null;
442			}
443		}
444		
445		/// <summary>
446		/// Gets the tooltip control that shows the value of given variable.
447		/// Return null if no tooltip is available.
448		/// </summary>
449		public object GetTooltipControl(TextLocation logicalPosition, string variableName)
450		{
451			try {
452				var tooltipExpression = GetExpression(variableName);
453				if (tooltipExpression == null) return null;
454				
455				string imageName;
456				var image = ExpressionNode.GetImageForLocalVariable(out imageName);
457				ExpressionNode expressionNode = new ExpressionNode(image, variableName, tooltipExpression);
458				expressionNode.ImageName = imageName;
459				
460				return new DebuggerTooltipControl(logicalPosition, expressionNode);
461			} catch (GetValueException) {
462				return null;
463			}
464		}
465		
466		internal ITreeNode GetNode(string variable, string currentImageName = null)
467		{
468			try {
469				var expression = GetExpression(variable);
470				string imageName;
471				ImageSource image;
472				if (string.IsNullOrEmpty(currentImageName)) {
473					image = ExpressionNode.GetImageForLocalVariable(out imageName);
474				}
475				else {
476					image = ImageService.GetImage(currentImageName);
477					imageName = currentImageName;
478				}
479				ExpressionNode expressionNode = new ExpressionNode(image, variable, expression);
480				expressionNode.ImageName = imageName;
481				return expressionNode;
482			} catch (GetValueException) {
483				return null;
484			}
485		}
486		
487		public bool CanSetInstructionPointer(string filename, int line, int column)
488		{
489			if (debuggedProcess != null && debuggedProcess.IsPaused &&
490			    debuggedProcess.SelectedThread != null && debuggedProcess.SelectedThread.MostRecentStackFrame != null) {
491				SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.CanSetIP(filename, line, column);
492				return seg != null;
493			} else {
494				return false;
495			}
496		}
497		
498		public bool SetInstructionPointer(string filename, int line, int column)
499		{
500			if (CanSetInstructionPointer(filename, line, column)) {
501				SourcecodeSegment seg = debuggedProcess.SelectedThread.MostRecentStackFrame.SetIP(filename, line, column);
502				return seg != null;
503			} else {
504				return false;
505			}
506		}
507		
508		public void Dispose()
509		{
510			Stop();
511		}
512		
513		#endregion
514		
515		public event EventHandler Initialize;
516		
517		public void InitializeService()
518		{
519			debugger = new NDebugger();
520			
521			//debugger.Options = DebuggingOptions.Instance;
522			
523			debugger.DebuggerTraceMessage    += debugger_TraceMessage;
524			debugger.Processes.Added         += debugger_ProcessStarted;
525			debugger.Processes.Removed       += debugger_ProcessExited;
526			
527			DebuggerService.BreakPointAdded  += delegate (object sender, BreakpointBookmarkEventArgs e) {
528				AddBreakpoint(e.BreakpointBookmark);
529			};
530			
531			foreach (BreakpointBookmark b in DebuggerService.Breakpoints) {
532				AddBreakpoint(b);
533			}
534			
535			if (Initialize != null) {
536				Initialize(this, null);
537			}
538		}
539		
540		bool Compare(byte[] a, byte[] b)
541		{
542			if (a.Length != b.Length) return false;
543			for(int i = 0; i < a.Length; i++) {
544				if (a[i] != b[i]) return false;
545			}
546			return true;
547		}
548		
549		void AddBreakpoint(BreakpointBookmark bookmark)
550		{
551			Breakpoint breakpoint = null;
552			
553			breakpoint = new ILBreakpoint(
554				debugger,
555				bookmark.MemberReference.DeclaringType.FullName,
556				bookmark.LineNumber,
557				bookmark.FunctionToken,
558				bookmark.ILRange.From,
559				bookmark.IsEnabled);
560			
561			debugger.Breakpoints.Add(breakpoint);
562//			Action setBookmarkColor = delegate {
563//				if (debugger.Processes.Count == 0) {
564//					bookmark.IsHealthy = true;
565//					bookmark.Tooltip = null;
566//				} else if (!breakpoint.IsSet) {
567//					bookmark.IsHealthy = false;
568//					bookmark.Tooltip = "Breakpoint was not found in any loaded modules";
569//				} else if (breakpoint.OriginalLocation.CheckSum == null) {
570//					bookmark.IsHealthy = true;
571//					bookmark.Tooltip = null;
572//				} else {
573//					byte[] fileMD5;
574//					IEditable file = FileService.GetOpenFile(bookmark.FileName) as IEditable;
575//					if (file != null) {
576//						byte[] fileContent = Encoding.UTF8.GetBytesWithPreamble(file.Text);
577//						fileMD5 = new MD5CryptoServiceProvider().ComputeHash(fileContent);
578//					} else {
579//						fileMD5 = new MD5CryptoServiceProvider().ComputeHash(File.ReadAllBytes(bookmark.FileName));
580//					}
581//					if (Compare(fileMD5, breakpoint.OriginalLocation.CheckSum)) {
582//						bookmark.IsHealthy = true;
583//						bookmark.Tooltip = null;
584//					} else {
585//						bookmark.IsHealthy = false;
586//						bookmark.Tooltip = "Check sum or file does not match to the original";
587//					}
588//				}
589//			};
590			
591			// event handlers on bookmark and breakpoint don't need deregistration
592			bookmark.IsEnabledChanged += delegate {
593				breakpoint.Enabled = bookmark.IsEnabled;
594			};
595			breakpoint.Set += delegate {
596				//setBookmarkColor();
597			};
598			
599			//setBookmarkColor();
600			
601			EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessStarted = (sender, e) => {
602				//setBookmarkColor();
603				// User can change line number by inserting or deleting lines
604				breakpoint.Line = bookmark.LineNumber;
605			};
606			EventHandler<CollectionItemEventArgs<Process>> bp_debugger_ProcessExited = (sender, e) => {
607				//setBookmarkColor();
608			};
609			
610			EventHandler<BreakpointEventArgs> bp_debugger_BreakpointHit =
611				new EventHandler<BreakpointEventArgs>(
612					delegate(object sender, BreakpointEventArgs e)
613					{
614						//LoggingService.Debug(bookmark.Action + " " + bookmark.ScriptLanguage + " " + bookmark.Condition);
615						
616						switch (bookmark.Action) {
617							case BreakpointAction.Break:
618								break;
619							case BreakpointAction.Condition:
620//								if (Evaluate(bookmark.Condition, bookmark.ScriptLanguage))
621//									DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAtBecause}") + "\n", bookmark.LineNumber, bookmark.FileName, bookmark.Condition));
622//								else
623//									this.debuggedProcess.AsyncContinue();
624								break;
625							case BreakpointAction.Trace:
626								//DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAt}") + "\n", bookmark.LineNumber, bookmark.FileName));
627								break;
628						}
629					});
630			
631			BookmarkEventHandler bp_bookmarkManager_Removed = null;
632			bp_bookmarkManager_Removed = (sender, e) => {
633				if (bookmark == e.Bookmark) {
634					debugger.Breakpoints.Remove(breakpoint);
635					
636					// unregister the events
637					debugger.Processes.Added -= bp_debugger_ProcessStarted;
638					debugger.Processes.Removed -= bp_debugger_ProcessExited;
639					breakpoint.Hit -= bp_debugger_BreakpointHit;
640					BookmarkManager.Removed -= bp_bookmarkManager_Removed;
641				}
642			};
643			// register the events
644			debugger.Processes.Added += bp_debugger_ProcessStarted;
645			debugger.Processes.Removed += bp_debugger_ProcessExited;
646			breakpoint.Hit += bp_debugger_BreakpointHit;
647			BookmarkManager.Removed += bp_bookmarkManager_Removed;
648		}
649		
650		bool Evaluate(string code, string language)
651		{
652			try {
653				SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true);
654				Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, debuggedProcess.SelectedThread.MostRecentStackFrame);
655				
656				if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
657					return (bool)val.PrimitiveValue;
658				else
659					return false;
660			} catch (GetValueException e) {
661				string errorMessage = "Error while evaluating breakpoint condition " + code + ":\n" + e.Message + "\n";
662				//DebuggerService.PrintDebugMessage(errorMessage);
663				//WorkbenchSingleton.SafeThreadAsyncCall(MessageService.ShowWarning, errorMessage);
664				return true;
665			}
666		}
667		
668		void LogMessage(object sender, MessageEventArgs e)
669		{
670			//DebuggerService.PrintDebugMessage(e.Message);
671		}
672		
673		void debugger_TraceMessage(object sender, MessageEventArgs e)
674		{
675			//LoggingService.Debug("Debugger: " + e.Message);
676		}
677		
678		void debugger_ProcessStarted(object sender, CollectionItemEventArgs<Process> e)
679		{
680			if (debugger.Processes.Count == 1) {
681				if (DebugStarted != null) {
682					DebugStarted(this, EventArgs.Empty);
683				}
684			}
685			e.Item.LogMessage += LogMessage;
686		}
687		
688		void debugger_ProcessExited(object sender, CollectionItemEventArgs<Process> e)
689		{
690			if (debugger.Processes.Count == 0) {
691				if (DebugStopped != null) {
692					DebugStopped(this, e);
693				}
694				SelectProcess(null);
695			} else {
696				SelectProcess(debugger.Processes[0]);
697			}
698		}
699		
700		public void SelectProcess(Process process)
701		{
702			if (debuggedProcess != null) {
703				debuggedProcess.Paused          -= debuggedProcess_DebuggingPaused;
704				debuggedProcess.ExceptionThrown -= debuggedProcess_ExceptionThrown;
705				debuggedProcess.Resumed         -= debuggedProcess_DebuggingResumed;
706				debuggedProcess.ModulesAdded 	-= debuggedProcess_ModulesAdded;
707			}
708			debuggedProcess = process;
709			if (debuggedProcess != null) {
710				debuggedProcess.Paused          += debuggedProcess_DebuggingPaused;
711				debuggedProcess.ExceptionThrown += debuggedProcess_ExceptionThrown;
712				debuggedProcess.Resumed         += debuggedProcess_DebuggingResumed;
713				debuggedProcess.ModulesAdded 	+= debuggedProcess_ModulesAdded;
714				
715				debuggedProcess.BreakAtBeginning = BreakAtBeginning;
716			}
717			// reset
718			BreakAtBeginning = false;
719			
720			//JumpToCurrentLine();
721			OnProcessSelected(new ProcessEventArgs(process));
722		}
723
724		void debuggedProcess_ModulesAdded(object sender, ModuleEventArgs e)
725		{
726			var currentModuleTypes = e.Module.GetNamesOfDefinedTypes();
727			foreach (var bookmark in DebuggerService.Breakpoints) {
728				var breakpoint =
729					debugger.Breakpoints.FirstOrDefault(
730						b => b.Line == bookmark.LineNumber && (b as ILBreakpoint).MetadataToken == bookmark.MemberReference.MetadataToken.ToInt32());
731				if (breakpoint == null)
732					continue;
733				// set the breakpoint only if the module contains the type
734				if (!currentModuleTypes.Contains(breakpoint.TypeName))
735					continue;
736				
737				breakpoint.SetBreakpoint(e.Module);
738			}
739		}
740		
741		void debuggedProcess_DebuggingPaused(object sender, ProcessEventArgs e)
742		{
743			JumpToCurrentLine();
744			OnIsProcessRunningChanged(EventArgs.Empty);
745		}
746		
747		void debuggedProcess_DebuggingResumed(object sender, CorDbg.ProcessEventArgs e)
748		{
749			OnIsProcessRunningChanged(EventArgs.Empty);
750			DebuggerService.RemoveCurrentLineMarker();
751		}
752		
753		void debuggedProcess_ExceptionThrown(object sender, CorDbg.ExceptionEventArgs e)
754		{
755			if (!e.IsUnhandled) {
756				// Ignore the exception
757				e.Process.AsyncContinue();
758				return;
759			}
760			
761			//JumpToCurrentLine();
762			
763			StringBuilder stacktraceBuilder = new StringBuilder();
764			
765			// Need to intercept now so that we can evaluate properties
766			if (e.Process.SelectedThread.InterceptCurrentException()) {
767				stacktraceBuilder.AppendLine(e.Exception.ToString());
768				string stackTrace;
769				try {
770					stackTrace = e.Exception.GetStackTrace("--- End of inner exception stack trace ---");
771				} catch (GetValueException) {
772					stackTrace = e.Process.SelectedThread.GetStackTrace("at {0} in {1}:line {2}", "at {0}");
773				}
774				stacktraceBuilder.Append(stackTrace);
775			} else {
776				// For example, happens on stack overflow
777				stacktraceBuilder.AppendLine("CannotInterceptException");
778				stacktraceBuilder.AppendLine(e.Exception.ToString());
779				stacktraceBuilder.Append(e.Process.SelectedThread.GetStackTrace("at {0} in {1}:line {2}", "at {0}"));
780			}
781			
782			string title = e.IsUnhandled ? "Unhandled" : "Handled";
783			string message = string.Format("Message {0} {1}", e.Exception.Type, e.Exception.Message);
784			
785			MessageBox.Show(message + stacktraceBuilder.ToString(), title);
786		}
787		
788		public void JumpToCurrentLine()
789		{
790			if (debuggedProcess != null &&  debuggedProcess.SelectedThread != null) {
791
792				MainWindow.Instance.Activate();
793
794				// use most recent stack frame because we don't have the symbols
795				var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
796				
797				if (frame == null)
798					return;
799				
800				int token = frame.MethodInfo.MetadataToken;
801				int ilOffset = frame.IP;
802				int line;
803				MemberReference memberReference;
804				
805				if (DebugInformation.CodeMappings != null && 
806				    DebugInformation.CodeMappings.ContainsKey(token) &&
807				    DebugInformation.CodeMappings[token].GetInstructionByTokenAndOffset(ilOffset, out memberReference, out line)) {
808					DebugInformation.DebugStepInformation = null; // we do not need to step into/out
809					DebuggerService.RemoveCurrentLineMarker();
810					DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0, ilOffset);
811				}
812				else {
813					StepIntoUnknownFrame(frame);
814				}
815			}
816		}
817
818		void StepIntoUnknownFrame(StackFrame frame)
819		{
820			string debuggeeVersion = frame.MethodInfo.DebugModule.Process.DebuggeeVersion.Substring(1, 3); // should retrieve 2.0, 3.0, 4.0
821			var debugType = (DebugType)frame.MethodInfo.DeclaringType;
822			int token = frame.MethodInfo.MetadataToken;
823			int ilOffset = frame.IP;
824			string fullName = debugType.FullNameWithoutGenericArguments;
825			
826			DebugInformation.LoadedAssemblies =  MainWindow.Instance.CurrentAssemblyList.GetAssemblies().Select(a => a.AssemblyDefinition);
827			
828			if (DebugInformation.LoadedAssemblies == null)
829				throw new NullReferenceException("No DebugData assemblies!");
830			else {
831				// search for type in the current assembly list
832				TypeDefinition typeDef = null;
833				TypeDefinition nestedTypeDef = null;
834				
835				foreach (var assembly in DebugInformation.LoadedAssemblies) {
836					if (null == assembly)
837						continue;
838					if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) &&
839					    !assembly.Name.Version.ToString().StartsWith(debuggeeVersion))
840						continue;
841					
842					foreach (var module in assembly.Modules) {
843						var localType = module.GetType(fullName);
844						if (localType != null) {
845							if (localType.DeclaringType == null) {
846								typeDef = localType;
847							} else {
848								nestedTypeDef = localType;
849								typeDef = localType.DeclaringType;
850							}
851							break;
852						}
853					}
854					if (typeDef != null)
855						break;
856				}
857				
858				if (typeDef != null) {
859					TypeDefinition type = nestedTypeDef ?? typeDef;
860					DebugInformation.DebugStepInformation = Tuple.Create(token, ilOffset, type.GetMemberByToken(token));
861				} else {
862					Debug.Assert(typeDef != null, "No type was found!");
863				}
864			}
865		}
866		
867		public void ShowAttachDialog()
868		{
869			throw new NotImplementedException();
870		}
871	}
872}