[ci] Another Python 3 fix in babysitter
[mono.git] / mcs / tools / mono-symbolicate / symbolicate.cs
1 using System;
2 using System.IO;
3 using System.Text;
4 using System.Linq;
5 using System.Collections.Generic;
6 using System.Globalization;
7 using Mono.Options;
8
9 namespace Mono
10 {
11         public class Symbolicate
12         {
13                 class Command {
14                         public readonly int MinArgCount;
15                         public readonly int MaxArgCount;
16                         public readonly Action<List<string>> Action;
17
18                         public Command (Action<List<string>> action, int minArgCount = 0, int maxArgCount = int.MaxValue)
19                         {
20                                 Action = action;
21                                 MinArgCount = minArgCount;
22                                 MaxArgCount = maxArgCount;
23                         }
24                 }
25
26                 static Logger logger;
27
28                 public static int Main (String[] args)
29                 {
30                         var showHelp = false;
31                         List<string> extra = null;
32
33                         Command cmd = null;
34
35                         var logLevel = Logger.Level.Warning;
36
37                         var options = new OptionSet {
38                                 { "h|help", "Show this help", v => showHelp = true },
39                                 { "q", "Quiet, warnings are not displayed", v => logLevel = Logger.Level.Error },
40                                 { "v", "Verbose, log debug messages", v => logLevel = Logger.Level.Debug },
41                         };
42
43                         try {
44                                 extra = options.Parse (args);
45                         } catch (OptionException e) {
46                                 Console.WriteLine ("Option error: {0}", e.Message);
47                                 showHelp = true;
48                         }
49
50                         if (extra.Count > 0 && extra[0] == "store-symbols")
51                                 cmd = new Command (StoreSymbolsAction, 2);
52
53                         if (cmd != null) {
54                                 extra.RemoveAt (0);
55                         } else {
56                                 cmd = new Command (SymbolicateAction, 2, 2);
57                         }
58
59                         if (showHelp || extra == null || extra.Count < cmd.MinArgCount || extra.Count > cmd.MaxArgCount) {
60                                 Console.Error.WriteLine ("Usage: symbolicate [options] <msym dir> <input file>");
61                                 Console.Error.WriteLine ("       symbolicate [options] store-symbols <msym dir> [<dir>]+");
62                                 Console.WriteLine ();
63                                 Console.WriteLine ("Available options:");
64                                 options.WriteOptionDescriptions (Console.Out);
65                                 return 1;
66                         }
67
68                         logger = new Logger (logLevel, msg => Console.Error.WriteLine (msg));
69
70                         cmd.Action (extra);
71
72                         return 0;
73                 }
74
75                 private static void SymbolicateAction (List<string> args)
76                 {
77                         var msymDir = args [0];
78                         var inputFile = args [1];
79
80                         var symbolManager = new SymbolManager (msymDir, logger);
81
82                         using (StreamReader r = new StreamReader (inputFile)) {
83                                 var sb = Process (r, symbolManager);
84                                 Console.Write (sb.ToString ());
85                         }
86                 }
87
88                 private static void StoreSymbolsAction (List<string> args)
89                 {
90                         var msymDir = args[0];
91                         var lookupDirs = args.Skip (1).ToArray ();
92
93                         var symbolManager = new SymbolManager (msymDir, logger);
94
95                         symbolManager.StoreSymbols (lookupDirs);
96                 }
97
98                 public static StringBuilder Process (StreamReader reader, SymbolManager symbolManager)
99                 {
100                         List<StackFrameData> stackFrames = new List<StackFrameData>();
101                         List<StackTraceMetadata> metadata = new List<StackTraceMetadata>();
102                         StringBuilder sb = new StringBuilder ();
103                         bool linesEnded = false;
104
105                         for (var line = reader.ReadLine (); line != null; line = reader.ReadLine ()) {
106                                 StackFrameData sfData;
107                                 if (!linesEnded && StackFrameData.TryParse (line, out sfData)) {
108                                         stackFrames.Add (sfData);
109                                         continue;
110                                 }
111
112                                 if (stackFrames.Count > 0) {
113                                         linesEnded = true;
114
115                                         StackTraceMetadata stMetadata;
116                                         if (StackTraceMetadata.TryParse (line, out stMetadata)) {
117                                                 metadata.Add (stMetadata);
118                                                 continue;
119                                         }
120
121                                         DumpStackTrace (symbolManager, sb, stackFrames, metadata);
122                 
123                                         // Clear lists for next stack trace
124                                         stackFrames.Clear ();
125                                         metadata.Clear ();
126                                 }
127
128                                 linesEnded = false;
129
130                                 // Append last line
131                                 sb.AppendLine (line);
132                         }
133
134                         if (stackFrames.Count > 0)
135                                 DumpStackTrace (symbolManager, sb, stackFrames, metadata);
136
137                         return sb;
138                 }
139
140                 private static void DumpStackTrace (SymbolManager symbolManager, StringBuilder sb, List<StackFrameData> stackFrames, List<StackTraceMetadata> metadata)
141                 {
142                         string aotid = null;
143                         var aotidMetadata = metadata.FirstOrDefault ( m => m.Id == "AOTID" );
144                         if (aotidMetadata != null)
145                                 aotid = aotidMetadata.Value;
146
147                         var linesMvid = ProcessLinesMVID (metadata);
148                         var lineNumber = -1;
149                         foreach (var sfData in stackFrames) {
150                                 string mvid = null;
151                                 lineNumber++;
152                                 if (!sfData.IsValid)
153                                         continue;
154                                 if (linesMvid.ContainsKey (lineNumber))
155                                         mvid = linesMvid [lineNumber];
156
157                                 symbolManager.TryResolveLocation (sfData, mvid, aotid);
158
159                                 sb.AppendLine (sfData.ToString ());
160                         }
161
162                         foreach (var m in metadata)
163                                 sb.AppendLine (m.Line);
164                 }
165
166                 private static Dictionary<int, string> ProcessLinesMVID (List<StackTraceMetadata> metadata)
167                 {
168                         var linesMvid = new Dictionary<int, string> ();
169                         var mvidData = metadata.Where ( m => m.Id == "MVID" ).Select ( m => m.Value );
170                         foreach (var m in mvidData) {
171                                 var s1 = m.Split (new char[] {' '}, 2);
172                                 var mvid = s1 [0];
173                                 var lines = s1 [1].Split (',');
174                                 foreach (var line in lines)
175                                         linesMvid.Add (int.Parse (line), mvid);
176                         }
177
178                         return linesMvid;
179                 }
180         }
181 }