use MOONLIGHT symbol
[mcs.git] / tools / pdb2mdb / PdbFile.cs
blobe07e9fc1b8d7cb257e48b2b8e524d9c1f2431e9e
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;
12 namespace Microsoft.Cci.Pdb {
13 internal class PdbFile {
14 private PdbFile() // This class can't be instantiated.
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);
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
35 if (ver != 20000404) {
36 throw new PdbDebugException("Unsupported PDB Stream version {0}", ver);
39 // Read string buffer.
40 int buf;
41 bits.ReadInt32(out buf); // 28..31 Bytes of Strings
43 int beg = bits.Position;
44 int nxt = bits.Position + buf;
46 bits.Position = nxt;
48 // Read map index.
49 int cnt; // n+0..3 hash size.
50 int max; // n+4..7 maximum ni.
52 bits.ReadInt32(out cnt);
53 bits.ReadInt32(out max);
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.");
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);
69 string name;
70 int saved = bits.Position;
71 bits.Position = beg + ns;
72 bits.ReadCString(out name);
73 bits.Position = saved;
75 result.Add(name, ni);
76 j++;
79 if (j != cnt) {
80 throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt);
82 return result;
85 static IntHashTable LoadNameStream(BitAccess bits) {
86 IntHashTable ht = new IntHashTable();
88 uint sig;
89 int ver;
90 bits.ReadUInt32(out sig); // 0..3 Signature
91 bits.ReadInt32(out ver); // 4..7 Version
93 // Read (or skip) string buffer.
94 int buf;
95 bits.ReadInt32(out buf); // 8..11 Bytes of Strings
97 if (sig != 0xeffeeffe || ver != 1) {
98 throw new PdbDebugException("Unsupported Name Stream version. "+
99 "(sig={0:x8}, ver={1})",
100 sig, ver);
102 int beg = bits.Position;
103 int nxt = bits.Position + buf;
104 bits.Position = nxt;
106 // Read hash table.
107 int siz;
108 bits.ReadInt32(out siz); // n+0..3 Number of hash buckets.
109 nxt = bits.Position;
111 for (int i = 0; i < siz; i++) {
112 int ni;
113 string name;
115 bits.ReadInt32(out ni);
117 if (ni != 0) {
118 int saved = bits.Position;
119 bits.Position = beg + ni;
120 bits.ReadCString(out name);
121 bits.Position = saved;
123 ht.Add(ni, name);
126 bits.Position = nxt;
128 return ht;
131 private static PdbFunction match = new PdbFunction();
133 private static PdbFunction FindFunction(PdbFunction[] funcs, ushort sec, uint off) {
134 match.segment = sec;
135 match.address = off;
137 int item = Array.BinarySearch(funcs, match, PdbFunction.byAddress);
138 if (item >= 0) {
139 return funcs[item];
141 return null;
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();
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;
164 switch ((DEBUG_S_SUBSECTION)sig) {
165 case DEBUG_S_SUBSECTION.FILECHKSMS:
166 while (bits.Position < endSym) {
167 CV_FileCheckSum chk;
169 int ni = bits.Position - place;
170 bits.ReadUInt32(out chk.name);
171 bits.ReadUInt8(out chk.len);
172 bits.ReadUInt8(out chk.type);
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);
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);
190 bits.Position = endSym;
191 break;
193 default:
194 bits.Position = endSym;
195 break;
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;
208 switch ((DEBUG_S_SUBSECTION)sig) {
209 case DEBUG_S_SUBSECTION.LINES: {
210 CV_LineSection sec;
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;
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++;
232 func.lines = new PdbLines[blocks];
233 int block = 0;
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.
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;
247 int plin = bits.Position;
248 int pcol = bits.Position + 8 * (int)file.count;
250 for (int i = 0; i < file.count; i++) {
251 CV_Line line;
252 CV_Column column = new CV_Column();
254 bits.Position = plin + 8 * i;
255 bits.ReadUInt32(out line.offset);
256 bits.ReadUInt32(out line.flags);
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);
267 lines[i] = new PdbLine(line.offset,
268 lineBegin,
269 column.offColumnStart,
270 lineBegin+delta,
271 column.offColumnEnd);
274 break;
277 bits.Position = endSym;
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;
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);
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));
308 for (int i = 0; i < funcs.Length; i++) {
309 funcList.Add(funcs[i]);
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();
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);
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);
333 if (bits.Position != end) {
334 throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}",
335 bits.Position, end);
338 if (modList.Count > 0) {
339 modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo));
340 } else {
341 modules = null;
344 // Skip the Section Contribution substream.
345 bits.Position += dh.secconSize;
347 // Skip the Section Map substream.
348 bits.Position += dh.secmapSize;
350 // Skip the File Info substream.
351 bits.Position += dh.filinfSize;
353 // Skip the TSM substream.
354 bits.Position += dh.tsmapSize;
356 // Skip the EC substream.
357 bits.Position += dh.ecinfoSize;
359 // Read the optional header.
360 end = bits.Position + dh.dbghdrSize;
361 if (dh.dbghdrSize > 0) {
362 header = new DbiDbgHdr(bits);
364 bits.Position = end;
367 internal static PdbFunction[] LoadFunctions(Stream read, bool readAllStrings) {
368 BitAccess bits = new BitAccess(512 * 1024);
369 return LoadFunctions(read, bits, readAllStrings);
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;
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");
386 dir.streams[nameStream].Read(reader, bits);
387 IntHashTable names = LoadNameStream(bits);
389 dir.streams[3].Read(reader, bits);
390 LoadDbiStream(bits, out modules, out header, readAllStrings);
392 ArrayList funcList = new ArrayList();
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);
404 PdbFunction[] funcs = (PdbFunction[])funcList.ToArray(typeof(PdbFunction));
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);
412 foreach (PdbFunction func in funcs) {
413 func.token = 0x06000000 | ridMap[func.token & 0xffffff];
418 Array.Sort(funcs, PdbFunction.byAddress);
419 //Array.Sort(funcs, PdbFunction.byToken);
420 return funcs;