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);