PageRenderTime 37ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

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

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