PdbFunction.cs 18 KB

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