1 //-----------------------------------------------------------------------------
3 // Copyright (C) Microsoft Corporation. All Rights Reserved.
5 //-----------------------------------------------------------------------------
7 using System.Collections;
8 using System.Collections.Generic;
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>();
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.
41 bits.ReadInt32(out buf); // 28..31 Bytes of Strings
43 int beg = bits.Position;
44 int nxt = bits.Position + buf;
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.");
62 for (int i = 0; i < max; i++) {
63 if (present.IsSet(i)) {
66 bits.ReadInt32(out ns);
67 bits.ReadInt32(out ni);
70 int saved = bits.Position;
71 bits.Position = beg + ns;
72 bits.ReadCString(out name);
73 bits.Position = saved;
80 throw new PdbDebugException("Count mismatch. ({0} != {1})", j, cnt);
85 static IntHashTable LoadNameStream(BitAccess bits) {
86 IntHashTable ht = new IntHashTable();
90 bits.ReadUInt32(out sig); // 0..3 Signature
91 bits.ReadInt32(out ver); // 4..7 Version
93 // Read (or skip) string buffer.
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})",
102 int beg = bits.Position;
103 int nxt = bits.Position + buf;
108 bits.ReadInt32(out siz); // n+0..3 Number of hash buckets.
111 for (int i = 0; i < siz; i++) {
115 bits.ReadInt32(out ni);
118 int saved = bits.Position;
119 bits.Position = beg + ni;
120 bits.ReadCString(out name);
121 bits.Position = saved;
131 private static PdbFunction match = new PdbFunction();
133 private static PdbFunction FindFunction(PdbFunction[] funcs, ushort sec, uint off) {
137 int item = Array.BinarySearch(funcs, match, PdbFunction.byAddress);
144 static void LoadManagedLines(PdbFunction[] funcs,
148 Dictionary<string, int> nameIndex,
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) {
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) {
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];
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);
187 bits.Position += chk.len;
190 bits.Position = endSym;
194 bits.Position = endSym;
199 // Read the lines next.
200 bits.Position = begin;
201 while (bits.Position < limit) {
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: {
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;
222 while (bits.Position < endSym) {
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;
232 func.lines = new PdbLines[blocks];
235 bits.Position = begSym;
236 while (bits.Position < endSym) {
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++) {
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,
269 column.offColumnStart,
271 column.offColumnEnd);
277 bits.Position = endSym;
281 static void LoadFuncsFromDbiModule(BitAccess bits,
287 Dictionary<string, int> nameIndex,
289 PdbFunction[] funcs = null;
293 bits.ReadInt32(out sig);
295 throw new PdbDebugException("Invalid signature. (sig={0})", sig);
299 // Console.WriteLine("{0}:", info.moduleName);
300 funcs = PdbFunction.LoadManagedFunctions(info.moduleName,
301 bits, (uint)info.cbSyms,
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,
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}",
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);
333 if (bits.Position != end) {
334 throw new PdbDebugException("Error reading DBI stream, pos={0} != {1}",
338 if (modList.Count > 0) {
339 modules = (DbiModuleInfo[])modList.ToArray(typeof(DbiModuleInfo));
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);
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;
379 dir.streams[1].Read(reader, bits);
380 Dictionary<string, int> nameIndex = LoadNameIndex(bits);
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);