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 { PdbFile()14 private PdbFile() // This class can't be instantiated. 15 { 16 } 17 LoadGuidStream(BitAccess bits, out Guid doctype, out Guid language, out Guid vendor)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 LoadNameIndex(BitAccess bits)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 LoadNameStream(BitAccess bits)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 FindFunction(PdbFunction[] funcs, ushort sec, uint off)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 LoadManagedLines(PdbFunction[] funcs, IntHashTable names, BitAccess bits, MsfDirectory dir, Dictionary<string, int> nameIndex, PdbReader reader, uint limit)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 LoadFuncsFromDbiModule(BitAccess bits, DbiModuleInfo info, IntHashTable names, ArrayList funcList, bool readStrings, MsfDirectory dir, Dictionary<string, int> nameIndex, PdbReader reader)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 LoadDbiStream(BitAccess bits, out DbiModuleInfo[] modules, out DbiDbgHdr header, bool readStrings)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 LoadFunctions(Stream read, bool readAllStrings)367 internal static PdbFunction[] LoadFunctions(Stream read, bool readAllStrings) { 368 BitAccess bits = new BitAccess(512 * 1024); 369 return LoadFunctions(read, bits, readAllStrings); 370 } 371 LoadFunctions(Stream read, BitAccess bits, bool 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; 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 } 424