Merge pull request #4840 from kumpera/unaligned-access
[mono.git] / mcs / tools / mono-symbolicate / SymbolManager.cs
1 using System;
2 using System.IO;
3 using System.Linq;
4 using System.Text;
5 using System.Collections.Generic;
6 using Mono.Cecil;
7 using Mono.Cecil.Cil;
8 using Mono.Collections.Generic;
9
10 namespace Mono
11 {
12         public class SymbolManager
13         {
14                 string msymDir;
15                 Logger logger;
16
17                 public SymbolManager (string msymDir, Logger logger) {
18                         this.msymDir = msymDir;
19                         this.logger = logger;
20                 }
21
22                 internal bool TryResolveLocation (StackFrameData sfData)
23                 {
24                         if (sfData.Mvid == null)
25                                 return false;
26
27                         var assemblyLocProvider = GetOrCreateAssemblyLocationProvider (sfData.Mvid);
28                         if (assemblyLocProvider == null)
29                                 return false;
30
31                         SeqPointInfo seqPointInfo = null;
32                         if (!sfData.IsILOffset && sfData.Aotid != null)
33                                 seqPointInfo = GetOrCreateSeqPointInfo (sfData.Aotid);
34
35                         return assemblyLocProvider.TryResolveLocation (sfData, seqPointInfo);
36                 }
37
38                 Dictionary<string, AssemblyLocationProvider> assemblies = new Dictionary<string, AssemblyLocationProvider> ();
39
40                 private AssemblyLocationProvider GetOrCreateAssemblyLocationProvider (string mvid)
41                 {
42                         if (assemblies.ContainsKey (mvid))
43                                 return assemblies[mvid];
44
45                         var mvidDir = Path.Combine (msymDir, mvid);
46                         if (!Directory.Exists (mvidDir)) {
47                                 logger.LogWarning ("MVID directory does not exist: {0}", mvidDir);
48                                 return  null;
49                         }
50
51                         string assemblyPath = null;
52                         var exeFiles = Directory.GetFiles (mvidDir, "*.exe");
53                         var dllFiles = Directory.GetFiles (mvidDir, "*.dll");
54
55                         if (exeFiles.Length + dllFiles.Length != 1) {
56                                 logger.LogError ("MVID directory should include one assembly: {0}", mvidDir);
57                                 return null;
58                         }
59
60                         assemblyPath = exeFiles.Length > 0 ? exeFiles[0] : dllFiles[0];
61
62                         var locProvider = new AssemblyLocationProvider (assemblyPath, logger);
63
64                         assemblies.Add (mvid, locProvider);
65
66                         return locProvider;
67                 }
68
69                 Dictionary<string, SeqPointInfo> seqPointInfos = new Dictionary<string, SeqPointInfo> ();
70
71                 private SeqPointInfo GetOrCreateSeqPointInfo (string aotid)
72                 {
73                         if (seqPointInfos.ContainsKey (aotid))
74                                 return seqPointInfos[aotid];
75
76                         var aotidDir = Path.Combine (msymDir, aotid);
77                         if (!Directory.Exists (aotidDir)) {
78                                 logger.LogError ("AOTID directory does not exist: {0}", aotidDir);
79                                 return null;
80                         }
81
82                         string msymFile = null;
83                         var msymFiles = Directory.GetFiles(aotidDir, "*.msym");
84                         msymFile = msymFiles[0];
85
86                         var seqPointInfo = SeqPointInfo.Read (msymFile);
87
88                         seqPointInfos.Add (aotid, seqPointInfo);
89
90                         return seqPointInfo;
91                 }
92
93                 public void StoreSymbols (params string[] lookupDirs)
94                 {
95                         foreach (var dir in lookupDirs) {
96                                 var exeFiles = Directory.GetFiles (dir, "*.exe");
97                                 var dllFiles = Directory.GetFiles (dir, "*.dll");
98                                 var assemblies = exeFiles.Concat (dllFiles);
99                                 foreach (var assemblyPath in assemblies) {
100
101                                         // TODO: Ignore embedded pdb
102                                         var symbolFile = GetSymbolFile (assemblyPath);
103
104                                         if (symbolFile == null) {
105                                                 logger.LogWarning ("Directory {0} contains {1} but no debug symbols file was found.", dir, Path.GetFileName (assemblyPath));
106                                                 // assemblies without debug symbols are useless
107                                                 continue;
108                                         }
109
110                                         string mvidDir;
111                                         using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) {
112                                                 var mvid = assembly.MainModule.Mvid.ToString ("N");
113                                                 mvidDir = Path.Combine (msymDir, mvid);
114                                         }
115
116                                         if (Directory.Exists (mvidDir)) {
117                                                 try {
118                                                         Directory.Delete (mvidDir, true);
119                                                 } catch (DirectoryNotFoundException) {}
120                                         }
121
122                                         Directory.CreateDirectory (mvidDir);
123
124                                         var mvidAssemblyPath = Path.Combine (mvidDir, Path.GetFileName (assemblyPath));
125                                         File.Copy (assemblyPath, mvidAssemblyPath);
126
127                                         var mvidDebugPath = Path.Combine (mvidDir, Path.GetFileName (symbolFile));
128                                         File.Copy (symbolFile, mvidDebugPath);
129
130                                         // TODO create MVID dir for non main modules with links to main module MVID
131                                 }
132                         }
133                 }
134
135                 static string GetSymbolFile (string assembly)
136                 {
137                         var pdbName = Path.ChangeExtension (assembly, "pdb");
138                         if (File.Exists (pdbName))
139                                 return pdbName;
140                         
141                         var mdbName = assembly + ".mdb";
142
143                         if (File.Exists (mdbName))
144                                 return mdbName;
145
146                         return null;
147                 }
148         }
149 }