Default to 2.0 profile
[mono.git] / mcs / tools / pdb2mdb / PdbFunction.cs
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
10 namespace Microsoft.Cci.Pdb {
11   internal class PdbFunction {
12     static internal readonly Guid msilMetaData = new Guid(0xc6ea3fc9, 0x59b3, 0x49d6, 0xbc, 0x25,
13                                                         0x09, 0x02, 0xbb, 0xab, 0xb4, 0x60);
14     static internal readonly IComparer byAddress = new PdbFunctionsByAddress();
15     static internal readonly IComparer byToken = new PdbFunctionsByToken();
16
17     internal uint token;
18     internal uint slotToken;
19     internal string name;
20     internal string module;
21     internal ushort flags;
22
23     internal uint segment;
24     internal uint address;
25     internal uint length;
26
27     //internal byte[] metadata;
28     internal PdbScope[] scopes;
29     internal PdbLines[] lines;
30     internal ushort[]/*?*/ usingCounts;
31     internal IEnumerable<INamespaceScope>/*?*/ namespaceScopes;
32     internal string/*?*/ iteratorClass;
33     internal List<ILocalScope>/*?*/ iteratorScopes;
34
35     private static string StripNamespace(string module) {
36       int li = module.LastIndexOf('.');
37       if (li > 0) {
38         return module.Substring(li + 1);
39       }
40       return module;
41     }
42
43
44     internal static PdbFunction[] LoadManagedFunctions(string module,
45                                                        BitAccess bits, uint limit,
46                                                        bool readStrings) {
47       string mod = StripNamespace(module);
48       int begin = bits.Position;
49       int count = 0;
50
51       while (bits.Position < limit) {
52         ushort siz;
53         ushort rec;
54
55         bits.ReadUInt16(out siz);
56         int star = bits.Position;
57         int stop = bits.Position + siz;
58         bits.Position = star;
59         bits.ReadUInt16(out rec);
60
61         switch ((SYM)rec) {
62           case SYM.S_GMANPROC:
63           case SYM.S_LMANPROC:
64             ManProcSym proc;
65             bits.ReadUInt32(out proc.parent);
66             bits.ReadUInt32(out proc.end);
67             bits.Position = (int)proc.end;
68             count++;
69             break;
70
71           case SYM.S_END:
72             bits.Position = stop;
73             break;
74
75           default:
76             //Console.WriteLine("{0,6}: {1:x2} {2}",
77             //                  bits.Position, rec, (SYM)rec);
78             bits.Position = stop;
79             break;
80         }
81       }
82       if (count == 0) {
83         return null;
84       }
85
86       bits.Position = begin;
87       PdbFunction[] funcs = new PdbFunction[count];
88       int func = 0;
89
90       while (bits.Position < limit) {
91         ushort siz;
92         ushort rec;
93
94         bits.ReadUInt16(out siz);
95         int star = bits.Position;
96         int stop = bits.Position + siz;
97         bits.ReadUInt16(out rec);
98
99         switch ((SYM)rec) {
100
101           case SYM.S_GMANPROC:
102           case SYM.S_LMANPROC:
103             ManProcSym proc;
104             int offset = bits.Position;
105
106             bits.ReadUInt32(out proc.parent);
107             bits.ReadUInt32(out proc.end);
108             bits.ReadUInt32(out proc.next);
109             bits.ReadUInt32(out proc.len);
110             bits.ReadUInt32(out proc.dbgStart);
111             bits.ReadUInt32(out proc.dbgEnd);
112             bits.ReadUInt32(out proc.token);
113             bits.ReadUInt32(out proc.off);
114             bits.ReadUInt16(out proc.seg);
115             bits.ReadUInt8(out proc.flags);
116             bits.ReadUInt16(out proc.retReg);
117             if (readStrings) {
118               bits.ReadCString(out proc.name);
119             } else {
120               bits.SkipCString(out proc.name);
121             }
122             //Console.WriteLine("token={0:X8} [{1}::{2}]", proc.token, module, proc.name);
123
124             bits.Position = stop;
125             funcs[func++] = new PdbFunction(module, proc, bits);
126             break;
127
128           default: {
129               //throw new PdbDebugException("Unknown SYMREC {0}", (SYM)rec);
130               bits.Position = stop;
131               break;
132             }
133         }
134       }
135       return funcs;
136     }
137
138     internal static void CountScopesAndSlots(BitAccess bits, uint limit,
139                                              out int constants, out int scopes, out int slots, out int usedNamespaces) {
140       int pos = bits.Position;
141       BlockSym32 block;
142       constants = 0;
143       slots = 0;
144       scopes = 0;
145       usedNamespaces = 0;
146
147       while (bits.Position < limit) {
148         ushort siz;
149         ushort rec;
150
151         bits.ReadUInt16(out siz);
152         int star = bits.Position;
153         int stop = bits.Position + siz;
154         bits.Position = star;
155         bits.ReadUInt16(out rec);
156
157         switch ((SYM)rec) {
158           case SYM.S_BLOCK32: {
159               bits.ReadUInt32(out block.parent);
160               bits.ReadUInt32(out block.end);
161
162               scopes++;
163               bits.Position = (int)block.end;
164               break;
165             }
166
167           case SYM.S_MANSLOT:
168             slots++;
169             bits.Position = stop;
170             break;
171
172           case SYM.S_UNAMESPACE:
173             usedNamespaces++;
174             bits.Position = stop;
175             break;
176
177           case SYM.S_MANCONSTANT:
178             constants++;
179             bits.Position = stop;
180             break;
181
182           default:
183             bits.Position = stop;
184             break;
185         }
186       }
187       bits.Position = pos;
188     }
189
190     internal PdbFunction() {
191     }
192
193     internal PdbFunction(string module, ManProcSym proc, BitAccess bits) {
194       this.token = proc.token;
195       this.module = module;
196       this.name = proc.name;
197       this.flags = proc.flags;
198       this.segment = proc.seg;
199       this.address = proc.off;
200       this.length = proc.len;
201       this.slotToken = 0;
202
203       if (proc.seg != 1) {
204         throw new PdbDebugException("Segment is {0}, not 1.", proc.seg);
205       }
206       if (proc.parent != 0 || proc.next != 0) {
207         throw new PdbDebugException("Warning parent={0}, next={1}",
208                                     proc.parent, proc.next);
209       }
210       if (proc.dbgStart != 0 || proc.dbgEnd != 0) {
211         throw new PdbDebugException("Warning DBG start={0}, end={1}",
212                                     proc.dbgStart, proc.dbgEnd);
213       }
214
215       int constantCount;
216       int scopeCount;
217       int slotCount;
218       int usedNamespacesCount;
219       CountScopesAndSlots(bits, proc.end, out constantCount, out scopeCount, out slotCount, out usedNamespacesCount);
220       scopes = new PdbScope[scopeCount];
221       int scope = 0;
222
223       while (bits.Position < proc.end) {
224         ushort siz;
225         ushort rec;
226
227         bits.ReadUInt16(out siz);
228         int star = bits.Position;
229         int stop = bits.Position + siz;
230         bits.Position = star;
231         bits.ReadUInt16(out rec);
232
233         switch ((SYM)rec) {
234           case SYM.S_OEM: {          // 0x0404
235               OemSymbol oem;
236
237               bits.ReadGuid(out oem.idOem);
238               bits.ReadUInt32(out oem.typind);
239               // internal byte[]   rgl;        // user data, force 4-byte alignment
240
241               if (oem.idOem == msilMetaData) {
242                 string name = bits.ReadString();
243                 if (name == "MD2") {
244                   byte version;
245                   bits.ReadUInt8(out version);
246                   if (version == 4) {
247                     byte count;
248                     bits.ReadUInt8(out count);
249                     bits.Align(4);
250                     while (count-- > 0)
251                       this.ReadCustomMetadata(bits);
252                   }
253                 }
254                 bits.Position = stop;
255                 break;
256               } else {
257                 throw new PdbDebugException("OEM section: guid={0} ti={1}",
258                                             oem.idOem, oem.typind);
259                 // bits.Position = stop;
260               }
261             }
262
263           case SYM.S_BLOCK32: {
264               BlockSym32 block = new BlockSym32();
265
266               bits.ReadUInt32(out block.parent);
267               bits.ReadUInt32(out block.end);
268               bits.ReadUInt32(out block.len);
269               bits.ReadUInt32(out this.address);
270               bits.ReadUInt16(out block.seg);
271               bits.SkipCString(out block.name);
272               bits.Position = stop;
273
274               scopes[scope] = new PdbScope(block, bits, out slotToken);
275               bits.Position = (int)block.end;
276               break;
277             }
278
279           case SYM.S_UNAMESPACE:
280             bits.Position = stop;
281             break;
282
283           case SYM.S_END:
284             bits.Position = stop;
285             break;
286
287           default: {
288               //throw new PdbDebugException("Unknown SYM: {0}", (SYM)rec);
289               bits.Position = stop;
290               break;
291             }
292         }
293       }
294
295       if (bits.Position != proc.end) {
296         throw new PdbDebugException("Not at S_END");
297       }
298
299       ushort esiz;
300       ushort erec;
301       bits.ReadUInt16(out esiz);
302       bits.ReadUInt16(out erec);
303
304       if (erec != (ushort)SYM.S_END) {
305         throw new PdbDebugException("Missing S_END");
306       }
307     }
308
309     private void ReadCustomMetadata(BitAccess bits) {
310       int savedPosition = bits.Position;
311       byte version;
312       bits.ReadUInt8(out version);
313       if (version != 4) {
314         throw new PdbDebugException("Unknown custom metadata item version: {0}", version);
315       }
316       byte kind;
317       bits.ReadUInt8(out kind);
318       bits.Align(4);
319       uint numberOfBytesInItem;
320       bits.ReadUInt32(out numberOfBytesInItem);
321       switch (kind) {
322         case 0: this.ReadUsingInfo(bits); break;
323         case 1: this.ReadForwardInfo(bits); break;
324         case 2: this.ReadForwardedToModuleInfo(bits); break;
325         case 3: this.ReadIteratorLocals(bits); break;
326         case 4: this.ReadForwardIterator(bits); break;
327         default: throw new PdbDebugException("Unknown custom metadata item kind: {0}", kind);
328       }
329       bits.Position = savedPosition+(int)numberOfBytesInItem;
330     }
331
332     private void ReadForwardIterator(BitAccess bits) {
333       this.iteratorClass = bits.ReadString();
334     }
335
336     private void ReadIteratorLocals(BitAccess bits) {
337       uint numberOfLocals;
338       bits.ReadUInt32(out numberOfLocals);
339       this.iteratorScopes = new List<ILocalScope>((int)numberOfLocals);
340       while (numberOfLocals-- > 0) {
341         uint ilStartOffset;
342         uint ilEndOffset;
343         bits.ReadUInt32(out ilStartOffset);
344         bits.ReadUInt32(out ilEndOffset);
345         this.iteratorScopes.Add(new PdbIteratorScope(ilStartOffset, ilEndOffset-ilStartOffset));
346       }
347     }
348
349     private void ReadForwardedToModuleInfo(BitAccess bits) {
350     }
351
352     private void ReadForwardInfo(BitAccess bits) {
353     }
354
355     private void ReadUsingInfo(BitAccess bits) {
356       ushort numberOfNamespaces;
357       bits.ReadUInt16(out numberOfNamespaces);
358       this.usingCounts = new ushort[numberOfNamespaces];
359       for (ushort i = 0; i < numberOfNamespaces; i++) {
360         bits.ReadUInt16(out this.usingCounts[i]);
361       }
362     }
363
364     internal class PdbFunctionsByAddress : IComparer {
365       public int Compare(Object x, Object y) {
366         PdbFunction fx = (PdbFunction)x;
367         PdbFunction fy = (PdbFunction)y;
368
369         if (fx.segment < fy.segment) {
370           return -1;
371         } else if (fx.segment > fy.segment) {
372           return 1;
373         } else if (fx.address < fy.address) {
374           return -1;
375         } else if (fx.address > fy.address) {
376           return 1;
377         } else {
378           return 0;
379         }
380       }
381     }
382
383     internal class PdbFunctionsByToken : IComparer {
384       public int Compare(Object x, Object y) {
385         PdbFunction fx = (PdbFunction)x;
386         PdbFunction fy = (PdbFunction)y;
387
388         if (fx.token < fy.token) {
389           return -1;
390         } else if (fx.token > fy.token) {
391           return 1;
392         } else {
393           return 0;
394         }
395       }
396
397     }
398   }
399 }