[pdb2mdb] Detect portable PDB and fail gracefully instead of crashing (#4261)
[mono.git] / mcs / tools / pdb2mdb / PdbScope.cs
1 //-----------------------------------------------------------------------------
2 //
3 // Copyright (C) Microsoft Corporation.  All Rights Reserved.
4 //
5 //-----------------------------------------------------------------------------
6 using System;
7
8 namespace Microsoft.Cci.Pdb {
9   internal class PdbScope {
10     internal PdbConstant[] constants;
11     internal PdbSlot[] slots;
12     internal PdbScope[] scopes;
13     internal string[] usedNamespaces;
14
15     internal uint segment;
16     internal uint address;
17     internal uint length;
18
19         internal PdbScope(uint funcAddress, BlockSym32 block, BitAccess bits, out uint typind) {
20       this.segment = block.seg;
21       this.address = block.off - funcAddress;
22       this.length = block.len;
23       typind = 0;
24
25       int constantCount;
26       int scopeCount;
27       int slotCount;
28       int namespaceCount;
29       PdbFunction.CountScopesAndSlots(bits, block.end, out constantCount, out scopeCount, out slotCount, out namespaceCount);
30       constants = new PdbConstant[constantCount];
31       scopes = new PdbScope[scopeCount];
32       slots = new PdbSlot[slotCount];
33       usedNamespaces = new string[namespaceCount];
34       int constant = 0;
35       int scope = 0;
36       int slot = 0;
37       int usedNs = 0;
38
39       while (bits.Position < block.end) {
40         ushort siz;
41         ushort rec;
42
43         bits.ReadUInt16(out siz);
44         int star = bits.Position;
45         int stop = bits.Position + siz;
46         bits.Position = star;
47         bits.ReadUInt16(out rec);
48
49         switch ((SYM)rec) {
50           case SYM.S_BLOCK32: {
51               BlockSym32 sub = new BlockSym32();
52
53               bits.ReadUInt32(out sub.parent);
54               bits.ReadUInt32(out sub.end);
55               bits.ReadUInt32(out sub.len);
56               bits.ReadUInt32(out sub.off);
57               bits.ReadUInt16(out sub.seg);
58               bits.SkipCString(out sub.name);
59
60               bits.Position = stop;
61               scopes[scope++] = new PdbScope(funcAddress, sub, bits, out typind);
62               break;
63             }
64
65           case SYM.S_MANSLOT:
66             slots[slot++] = new PdbSlot(bits, out typind);
67             bits.Position = stop;
68             break;
69
70           case SYM.S_UNAMESPACE:
71             bits.ReadCString(out usedNamespaces[usedNs++]);
72             bits.Position = stop;
73             break;
74
75           case SYM.S_END:
76             bits.Position = stop;
77             break;
78
79           case SYM.S_MANCONSTANT:
80             constants[constant++] = new PdbConstant(bits);
81             bits.Position = stop;
82             break;
83
84           default:
85             throw new PdbException("Unknown SYM in scope {0}", (SYM)rec);
86           // bits.Position = stop;
87         }
88       }
89
90       if (bits.Position != block.end) {
91         throw new Exception("Not at S_END");
92       }
93
94       ushort esiz;
95       ushort erec;
96       bits.ReadUInt16(out esiz);
97       bits.ReadUInt16(out erec);
98
99       if (erec != (ushort)SYM.S_END) {
100         throw new Exception("Missing S_END");
101       }
102     }
103   }
104 }