[mono-symbolicate] Fix crash while overwriting symbols
[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
16                 public SymbolManager (string msymDir) {
17                         this.msymDir = msymDir;
18                 }
19
20                 internal bool TryResolveLocation (StackFrameData sfData, string mvid, string aotid)
21                 {
22                         if (mvid == null)
23                                 return false;
24
25                         var assemblyLocProvider = GetOrCreateAssemblyLocationProvider (mvid);
26                         if (assemblyLocProvider == null)
27                                 return false;
28
29                         SeqPointInfo seqPointInfo = null;
30                         if (!sfData.IsILOffset && aotid != null)
31                                 seqPointInfo = GetOrCreateSeqPointInfo (aotid);
32
33                         return assemblyLocProvider.TryResolveLocation (sfData, seqPointInfo);
34                 }
35
36                 Dictionary<string, AssemblyLocationProvider> assemblies = new Dictionary<string, AssemblyLocationProvider> ();
37
38                 private AssemblyLocationProvider GetOrCreateAssemblyLocationProvider (string mvid)
39                 {
40                         if (assemblies.ContainsKey (mvid))
41                                 return assemblies[mvid];
42
43                         var mvidDir = Path.Combine (msymDir, mvid);
44                         if (!Directory.Exists (mvidDir)) {
45                                 Console.Error.WriteLine ("MVID directory does not exist: {0}", mvidDir);
46                                 return  null;
47                         }
48
49                         string assemblyPath = null;
50                         var exeFiles = Directory.GetFiles (mvidDir, "*.exe");
51                         var dllFiles = Directory.GetFiles (mvidDir, "*.dll");
52
53                         if (exeFiles.Length + dllFiles.Length != 1)
54                                 throw new Exception (string.Format ("MVID directory should include one assembly: {0}", mvidDir));
55
56                         assemblyPath = (exeFiles.Length > 0)? exeFiles[0] : dllFiles[0];
57
58                         var locProvider = new AssemblyLocationProvider (assemblyPath);
59
60                         assemblies.Add (mvid, locProvider);
61
62                         return locProvider;
63                 }
64
65                 Dictionary<string, SeqPointInfo> seqPointInfos = new Dictionary<string, SeqPointInfo> ();
66
67                 private SeqPointInfo GetOrCreateSeqPointInfo (string aotid)
68                 {
69                         if (seqPointInfos.ContainsKey (aotid))
70                                 return seqPointInfos[aotid];
71
72                         var aotidDir = Path.Combine (msymDir, aotid);
73                         if (!Directory.Exists (aotidDir))
74                                 throw new Exception (string.Format("AOTID directory does not exist: {0}", aotidDir));
75
76                         string msymFile = null;
77                         var msymFiles = Directory.GetFiles(aotidDir, "*.msym");
78                         msymFile = msymFiles[0];
79
80                         var seqPointInfo = SeqPointInfo.Read (msymFile);
81
82                         seqPointInfos.Add (aotid, seqPointInfo);
83
84                         return seqPointInfo;
85                 }
86
87                 public void StoreSymbols (params string[] lookupDirs)
88                 {
89                         foreach (var dir in lookupDirs) {
90                                 var exeFiles = Directory.GetFiles (dir, "*.exe");
91                                 var dllFiles = Directory.GetFiles (dir, "*.dll");
92                                 var assemblies = exeFiles.Concat (dllFiles);
93                                 foreach (var assemblyPath in assemblies) {
94                                         var mdbPath = assemblyPath + ".mdb";
95                                         if (!File.Exists (mdbPath)) {
96                                                 // assemblies without mdb files are useless
97                                                 continue;
98                                         }
99
100                                         var assembly = AssemblyDefinition.ReadAssembly (assemblyPath);
101
102                                         var mvid = assembly.MainModule.Mvid.ToString ("N");
103                                         var mvidDir = Path.Combine (msymDir, mvid);
104
105                                         if (Directory.Exists (mvidDir))
106                                                 Directory.Delete (mvidDir, true);
107
108                                         Directory.CreateDirectory (mvidDir);
109
110                                         var mvidAssemblyPath = Path.Combine (mvidDir, Path.GetFileName (assemblyPath));
111                                         File.Copy (assemblyPath, mvidAssemblyPath);
112
113                                         var mvidMdbPath = Path.Combine (mvidDir, Path.GetFileName (mdbPath));
114                                         File.Copy (mdbPath, mvidMdbPath);
115
116                                         // TODO create MVID dir for non main modules with links to main module MVID
117                                 }
118                         }
119                 }
120         }
121 }