PdbFunction.cs 14 KB

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