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