1 //
2 // Copyright (c) 2010-2022 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.IO;
10 using Antmicro.Renode.Utilities;
11 using Xwt;
12 using System.Text;
13 using System.Linq;
14 using System.Threading;
15 
16 namespace Antmicro.Renode.UI
17 {
18     public class CrashHandler
19     {
HandleCrash(Exception e)20         public static void HandleCrash(Exception e)
21         {
22             var message = GetFullStackTrace(e);
23             SaveErrorToFile(TemporaryFilesManager.Instance.EmulatorTemporaryPath + TemporaryFilesManager.CrashSuffix, message);
24             ShowErrorInConsole(message);
25             try
26             {
27                 ApplicationExtensions.InvokeInUIThreadAndWait(() => ShowErrorWindow(message));
28             }
29             catch(Exception)
30             {
31                 // there is nothing to do here
32             }
33         }
34 
ShowErrorWindow(string message)35         private static void ShowErrorWindow(string message)
36         {
37             var dialog = new Dialog();
38             dialog.Title = "Fatal error";
39             var markdown = new MarkdownView();
40             markdown.Markdown = message.Split(new [] { '\n' }).Select(x => "\t" + x).Aggregate((x, y) => x + "\n" + y);
41 
42             var copyButton = new Button("Copy to clipboard");
43             copyButton.Clicked += (sender, ev) => Clipboard.SetText(message);
44 
45             var box = new VBox();
46 
47             box.PackStart(new Label("Got unhandled exception") { Font = global::Xwt.Drawing.Font.SystemFont.WithSize(15).WithWeight(Xwt.Drawing.FontWeight.Bold) });
48             box.PackStart(new ScrollView(markdown), true, true);
49             box.PackStart(copyButton);
50 
51             dialog.Content = box;
52 
53             dialog.Buttons.Add(new DialogButton(Command.Ok));
54             dialog.Width = 350;
55             dialog.Height = 300;
56 
57             dialog.Run();
58             dialog.Dispose();
59         }
60 
SaveErrorToFile(string location, string message)61         private static void SaveErrorToFile(string location, string message)
62         {
63             Directory.CreateDirectory(location);
64             var filename = CustomDateTime.Now.ToString("yyyyMMddHHmmssfff");
65             File.AppendAllText(Path.Combine(location, filename), message);
66         }
67 
ShowErrorInConsole(string message)68         private static void ShowErrorInConsole(string message)
69         {
70             Console.ForegroundColor = ConsoleColor.Red;
71             Console.Error.WriteLine("Fatal error:");
72             Console.Error.WriteLine(message);
73             Console.ResetColor();
74         }
75 
GetFullStackTrace(Exception e)76         private static string GetFullStackTrace(Exception e)
77         {
78             var result = new StringBuilder();
79             var current = e;
80             while(current != null)
81             {
82                 result.AppendLine(current.Message);
83                 result.AppendLine(current.StackTrace);
84                 current = current.InnerException;
85                 if(current != null)
86                 {
87                     result.AppendLine("Inner exception:");
88                 }
89             }
90             return result.ToString();
91         }
92     }
93 }
94 
95