[msvc] Update csproj files (#4284)
[mono.git] / mcs / tools / pdb2mdb / PdbFile.cs
1 //-----------------------------------------------------------------------------
2 //
3 // Copyright (C) Microsoft Corporation.  All Rights Reserved.
4 //
5 //-----------------------------------------------------------------------------
6 using System;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.IO;
10 using System.Diagnostics.SymbolStore;
11
12 namespace Microsoft.Cci.Pdb {
13   internal class PdbFile {
14     private PdbFile()   // This class can't be instantiated.
15     {
16     }
17
18     static void LoadGuidStream(BitAccess bits, out Guid doctype, out Guid language, out Guid vendor) {
19       bits.ReadGuid(out language);
20       bits.ReadGuid(out vendor);
21       bits.ReadGuid(out doctype);
22     }
23
24     static Dictionary<string,int> LoadNameIndex(BitAccess bits) {
25       Dictionary<string, int> result = new Dictionary<string, int>();
26       int ver;
27       int sig;
28       int age;
29       Guid guid;
30       bits.ReadInt32(out ver);    //  0..3  Version
31       bits.ReadInt32(out sig);    //  4..7  Signature
32       bits.ReadInt32(out age);    //  8..11 Age
33       bits.ReadGuid(out guid);       // 12..27 GUID
34
35       if (ver != 20000404) {
36         throw new PdbDebugException("Unsupported PDB Stream version {0}", ver);
37       }
38
39       // Read string buffer.
40       int buf;
41       bits.ReadInt32(out buf);    // 28..31 Bytes of Strings
42
43       int beg = bits.Position;
44       int nxt = bits.Position + buf;
45
46       bits.Position = nxt;
47
48       // Read map index.
49       int cnt;        // n+0..3 hash size.
50       int max;        // n+4..7 maximum ni.
51
52       bits.ReadInt32(out cnt);
53       bits.ReadInt32(out max);
54
55       BitSet present = new BitSet(bits);
56       BitSet deleted = new BitSet(bits);
57       if (!deleted.IsEmpty) {
58         throw new PdbDebugException("Unsupported PDB deleted bitset is not empty.");
59       }
60
61       int j = 0;
62       for (int i = 0; i < max; i++) {
63         if (present.IsSet(i)) {
64           int ns;
65           int ni;
66           bits.ReadInt32(out ns);
67           bits.ReadInt32(out ni);
68
69           string name;
70           int saved = bits.Position;
71           bits.Position = beg + ns;
72           bits.ReadCString(out name);
73           bits.Position = saved;
74
75           result.Add(name, ni);
76           j++;
77         }
78       }
79       if (j != cnt) {
80         throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt);
81       }
82       return result;
83     }
84
85     static IntHashTable LoadNameStream(BitAccess bits) {
86       IntHashTable ht = new IntHashTable();
87
88       uint sig;
89       int ver;
90       bits.ReadUInt32(out sig);   //  0..3  Signature
91       bits.ReadInt32(out ver);    //  4..7  Version
92
93       // Read (or skip) string buffer.
94       int buf;
95       bits.ReadInt32(out buf);    //  8..11 Bytes of Strings
96
97       if (sig != 0xeffeeffe || ver != 1) {
98         throw new PdbDebugException("Unsupported Name Stream version. "+
99                                             "(sig={0:x8}, ver={1})",
100                                     sig, ver);
101       }
102       int beg = bits.Position;
103       int nxt = bits.Position + buf;
104       bits.Position = nxt;
105
106       // Read hash table.
107       int siz;
108       bits.ReadInt32(out siz);    // n+0..3 Number of hash buckets.
109       nxt = bits.Position;
110
111       for (int i = 0; i < siz; i++) {
112         int ni;
113         string name;
114
115         bits.ReadInt32(out ni);
116
117         if (ni != 0) {
118           int saved = bits.Position;
119           bits.Position = beg + ni;
120           bits.ReadCString(out name);
121           bits.Position = saved;
122
123           ht.Add(ni, name);
124         }
125       }
126       bits.Position = nxt;
127
128       return ht;
129     }
130
131     private static PdbFunction match = new PdbFunction();
132
133     private static PdbFunction FindFunction(PdbFunction[] funcs, ushort sec, uint off) {
134       match.segment = sec;
135       match.address = off;
136
137       int item = Array.BinarySearch(funcs, match, PdbFunction.byAddress);
138       if (item >= 0) {
139         return funcs[item];
140       }
141       return null;
142     }
143
144     static void LoadManagedLines(PdbFunction[] funcs,
145                                  IntHashTable names,
146                                  BitAccess bits,
147                                  MsfDirectory dir,
148                                  Dictionary<string, int> nameIndex,
149                                  PdbReader reader,
150                                  uint limit) {
151       Array.Sort(funcs, PdbFunction.byAddress);
152       IntHashTable checks = new IntHashTable();
153
154       // Read the files first
155       int begin = bits.Position;
156       while (bits.Position < limit) {
157         int sig;
158         int siz;
159         bits.ReadInt32(out sig);
160         bits.ReadInt32(out siz);
161         int place = bits.Position;
162         int endSym = bits.Position + siz;
163
164         switch ((DEBUG_S_SUBSECTION)sig) {
165           case DEBUG_S_SUBSECTION.FILECHKSMS:
166             while (bits.Position < endSym) {
167               CV_FileCheckSum chk;
168
169               int ni = bits.Position - place;
170               bits.ReadUInt32(out chk.name);
171               bits.ReadUInt8(out chk.len);
172               bits.ReadUInt8(out chk.type);
173
174               string name = (string)names[(int)chk.name];
175               int guidStream;
176               Guid doctypeGuid = SymDocumentType.Text;
177               Guid languageGuid = SymLanguageType.CSharp;
178               Guid vendorGuid = SymLanguageVendor.Microsoft;
179               if (nameIndex.TryGetValue("/src/files/"+name, out guidStream)) {
180                 var guidBits = new BitAccess(0x100);
181                 dir.streams[guidStream].Read(reader, guidBits);
182                 LoadGuidStream(guidBits, out doctypeGuid, out languageGuid, out vendorGuid);
183               }
184
185               PdbSource src = new PdbSource((uint)ni, name, doctypeGuid, languageGuid, vendorGuid);
186               checks.Add(ni, src);
187               bits.Position += chk.len;
188               bits.Align(4);
189             }
190             bits.Position = endSym;
191             break;
192
193           default:
194             bits.Position = endSym;
195             break;
196         }
197       }
198
199       // Read the lines next.
200       bits.Position = begin;
201       while (bits.Position < limit) {
202         int sig;
203         int siz;
204         bits.ReadInt32(out sig);
205         bits.ReadInt32(out siz);
206         int endSym = bits.Position + siz;
207
208         switch ((DEBUG_S_SUBSECTION)sig) {
209           case DEBUG_S_SUBSECTION.LINES: {
210               CV_LineSection sec;
211
212               bits.ReadUInt32(out sec.off);
213               bits.ReadUInt16(out sec.sec);
214               bits.ReadUInt16(out sec.flags);
215               bits.ReadUInt32(out sec.cod);
216               PdbFunction func = FindFunction(funcs, sec.sec, sec.off);
217               if (func == null) break;
218
219               // Count the line blocks.
220               int begSym = bits.Position;
221               int blocks = 0;
222               while (bits.Position < endSym) {
223                 CV_SourceFile file;
224                 bits.ReadUInt32(out file.index);
225                 bits.ReadUInt32(out file.count);
226                 bits.ReadUInt32(out file.linsiz);   // Size of payload.
227                 int linsiz = (int)file.count * (8 + ((sec.flags & 1) != 0 ? 4 : 0));
228                 bits.Position += linsiz;
229                 blocks++;
230               }
231
232               func.lines = new PdbLines[blocks];
233               int block = 0;
234
235               bits.Position = begSym;
236               while (bits.Position < endSym) {
237                 CV_SourceFile file;
238                 bits.ReadUInt32(out file.index);
239                 bits.ReadUInt32(out file.count);
240                 bits.ReadUInt32(out file.linsiz);   // Size of payload.
241
242                 PdbSource src = (PdbSource)checks[(int)file.index];
243                 PdbLines tmp = new PdbLines(src, file.count);
244                 func.lines[block++] = tmp;
245                 PdbLine[] lines = tmp.lines;
246
247                 int plin = bits.Position;
248                 int pcol = bits.Position + 8 * (int)file.count;
249
250                 for (int i = 0; i < file.count; i++) {
251                   CV_Line line;
252                   CV_Column column = new CV_Column();
253
254                   bits.Position = plin + 8 * i;
255                   bits.ReadUInt32(out line.offset);
256                   bits.ReadUInt32(out line.flags);
257
258                   uint lineBegin = line.flags & (uint)CV_Line_Flags.linenumStart;
259                   uint delta = (line.flags & (uint)CV_Line_Flags.deltaLineEnd) >> 24;
260                   bool statement = ((line.flags & (uint)CV_Line_Flags.fStatement) == 0);
261                   if ((sec.flags & 1) != 0) {
262                     bits.Position = pcol + 4 * i;
263                     bits.ReadUInt16(out column.offColumnStart);
264                     bits.ReadUInt16(out column.offColumnEnd);
265                   }
266
267                   lines[i] = new PdbLine(line.offset,
268                                          lineBegin,
269                                          column.offColumnStart,
270                                          lineBegin+delta,
271                                          column.offColumnEnd);
272                 }
273               }
274               break;
275             }
276         }
277         bits.Position = endSym;
278       }
279     }
280
281     static void LoadFuncsFromDbiModule(BitAccess bits,
282                                        DbiModuleInfo info,
283                                        IntHashTable names,
284                                        ArrayList funcList,
285                                        bool readStrings,
286                                        MsfDirectory dir,
287                                        Dictionary<string, int> nameIndex,
288                                        PdbReader reader) {
289       PdbFunction[] funcs = null;
290
291       bits.Position = 0;
292       int sig;
293       bits.ReadInt32(out sig);
294       if (sig != 4) {
295         throw new PdbDebugException("Invalid signature. (sig={0})", sig);
296       }
297
298       bits.Position = 4;
299       // Console.WriteLine("{0}:", info.moduleName);
300       funcs = PdbFunction.LoadManagedFunctions(info.moduleName,
301                                                bits, (uint)info.cbSyms,
302                                                readStrings);
303       if (funcs != null) {
304         bits.Position = info.cbSyms + info.cbOldLines;
305         LoadManagedLines(funcs, names, bits, dir, nameIndex, reader,
306                          (uint)(info.cbSyms + info.cbOldLines + info.cbLines));
307
308         for (int i = 0; i < funcs.Length; i++) {
309           funcList.Add(funcs[i]);
310         }
311       }
312     }
313
314     static void LoadDbiStream(BitAccess bits,
315                               out DbiModuleInfo[] modules,
316                               out DbiDbgHdr header,
317                               bool readStrings) {
318       DbiHeader dh = new DbiHeader(bits);
319       header = new DbiDbgHdr();
320
321       if (dh.sig != -1 || dh.ver != 19990903) {
322         throw new PdbException("Unsupported DBI Stream version, sig={0}, ver={1}",
323                                dh.sig, dh.ver);
324       }
325
326       // Read gpmod section.
327       ArrayList modList = new ArrayList();
328       int end = bits.Position + dh.gpmodiSize;
329       while (bits.Position < end) {
330         DbiModuleInfo mod = new DbiModuleInfo(bits, readStrings);
331         modList.Add(mod);
332       }
333       if (bits.Position != end) {
334         throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}",
335                                     bits.Position, end);
336       }
337
338       if (modList.Count > 0) {
339         modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo));
340       } else {
341         modules = null;
342       }
343
344       // Skip the Section Contribution substream.
345       bits.Position += dh.secconSize;
346
347       // Skip the Section Map substream.
348       bits.Position += dh.secmapSize;
349
350       // Skip the File Info substream.
351       bits.Position += dh.filinfSize;
352
353       // Skip the TSM substream.
354       bits.Position += dh.tsmapSize;
355
356       // Skip the EC substream.
357       bits.Position += dh.ecinfoSize;
358
359       // Read the optional header.
360       end = bits.Position + dh.dbghdrSize;
361       if (dh.dbghdrSize > 0) {
362         header = new DbiDbgHdr(bits);
363       }
364       bits.Position = end;
365     }
366
367     internal static PdbFunction[] LoadFunctions(Stream read, bool readAllStrings) {
368       BitAccess bits = new BitAccess(512 * 1024);
369       return LoadFunctions(read, bits, readAllStrings);
370     }
371
372     internal static PdbFunction[] LoadFunctions(Stream read, BitAccess bits, bool readAllStrings) {
373       PdbFileHeader head = new PdbFileHeader(read, bits);
374       PdbReader reader = new PdbReader(read, head.pageSize);
375       MsfDirectory dir = new MsfDirectory(reader, head, bits);
376       DbiModuleInfo[] modules = null;
377       DbiDbgHdr header;
378
379       dir.streams[1].Read(reader, bits);
380       Dictionary<string, int> nameIndex = LoadNameIndex(bits);
381       int nameStream;
382       if (!nameIndex.TryGetValue("/names", out nameStream)) {
383         throw new PdbException("No `name' stream");
384       }
385
386       dir.streams[nameStream].Read(reader, bits);
387       IntHashTable names = LoadNameStream(bits);
388
389       dir.streams[3].Read(reader, bits);
390       LoadDbiStream(bits, out modules, out header, readAllStrings);
391
392       ArrayList funcList = new ArrayList();
393
394       if (modules != null) {
395         for (int m = 0; m < modules.Length; m++) {
396           if (modules[m].stream > 0) {
397             dir.streams[modules[m].stream].Read(reader, bits);
398             LoadFuncsFromDbiModule(bits, modules[m], names, funcList,
399                                    readAllStrings, dir, nameIndex, reader);
400           }
401         }
402       }
403
404       PdbFunction[] funcs = (PdbFunction[])funcList.ToArray(typeof(PdbFunction));
405
406       // After reading the functions, apply the token remapping table if it exists.
407       if (header.snTokenRidMap != 0 && header.snTokenRidMap != 0xffff) {
408         dir.streams[header.snTokenRidMap].Read(reader, bits);
409         uint[] ridMap = new uint[dir.streams[header.snTokenRidMap].Length / 4];
410         bits.ReadUInt32(ridMap);
411
412         foreach (PdbFunction func in funcs) {
413           func.token = 0x06000000 | ridMap[func.token & 0xffffff];
414         }
415       }
416
417       //
418       Array.Sort(funcs, PdbFunction.byAddress);
419       //Array.Sort(funcs, PdbFunction.byToken);
420       return funcs;
421     }
422   }
423 }