PageRenderTime 107ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

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