MonoSymbolFile.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. using Mono.Cecil;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Threading;
  6. namespace Mono.CompilerServices.SymbolWriter
  7. {
  8. public class MonoSymbolFile : IDisposable
  9. {
  10. private List<MethodEntry> methods = new List<MethodEntry>();
  11. private List<SourceFileEntry> sources = new List<SourceFileEntry>();
  12. private List<CompileUnitEntry> comp_units = new List<CompileUnitEntry>();
  13. private Dictionary<Type, int> type_hash = new Dictionary<Type, int>();
  14. private Dictionary<int, AnonymousScopeEntry> anonymous_scopes;
  15. private OffsetTable ot;
  16. private int last_type_index;
  17. private int last_method_index;
  18. private int last_namespace_index;
  19. public readonly string FileName = "<dynamic>";
  20. public readonly int MajorVersion = 50;
  21. public readonly int MinorVersion = 0;
  22. public int NumLineNumbers;
  23. private MyBinaryReader reader;
  24. private Dictionary<int, SourceFileEntry> source_file_hash;
  25. private Dictionary<int, CompileUnitEntry> compile_unit_hash;
  26. private List<MethodEntry> method_list;
  27. private Dictionary<int, MethodEntry> method_token_hash;
  28. private Dictionary<string, int> source_name_hash;
  29. private Guid guid;
  30. internal int LineNumberCount = 0;
  31. internal int LocalCount = 0;
  32. internal int StringSize = 0;
  33. internal int LineNumberSize = 0;
  34. internal int ExtendedLineNumberSize = 0;
  35. public int CompileUnitCount
  36. {
  37. get
  38. {
  39. return this.ot.CompileUnitCount;
  40. }
  41. }
  42. public int SourceCount
  43. {
  44. get
  45. {
  46. return this.ot.SourceCount;
  47. }
  48. }
  49. public int MethodCount
  50. {
  51. get
  52. {
  53. return this.ot.MethodCount;
  54. }
  55. }
  56. public int TypeCount
  57. {
  58. get
  59. {
  60. return this.ot.TypeCount;
  61. }
  62. }
  63. public int AnonymousScopeCount
  64. {
  65. get
  66. {
  67. return this.ot.AnonymousScopeCount;
  68. }
  69. }
  70. public int NamespaceCount
  71. {
  72. get
  73. {
  74. return this.last_namespace_index;
  75. }
  76. }
  77. public Guid Guid
  78. {
  79. get
  80. {
  81. return this.guid;
  82. }
  83. }
  84. public OffsetTable OffsetTable
  85. {
  86. get
  87. {
  88. return this.ot;
  89. }
  90. }
  91. public SourceFileEntry[] Sources
  92. {
  93. get
  94. {
  95. if (this.reader == null)
  96. {
  97. throw new InvalidOperationException();
  98. }
  99. SourceFileEntry[] retval = new SourceFileEntry[this.SourceCount];
  100. for (int i = 0; i < this.SourceCount; i++)
  101. {
  102. retval[i] = this.GetSourceFile(i + 1);
  103. }
  104. return retval;
  105. }
  106. }
  107. public CompileUnitEntry[] CompileUnits
  108. {
  109. get
  110. {
  111. if (this.reader == null)
  112. {
  113. throw new InvalidOperationException();
  114. }
  115. CompileUnitEntry[] retval = new CompileUnitEntry[this.CompileUnitCount];
  116. for (int i = 0; i < this.CompileUnitCount; i++)
  117. {
  118. retval[i] = this.GetCompileUnit(i + 1);
  119. }
  120. return retval;
  121. }
  122. }
  123. public MethodEntry[] Methods
  124. {
  125. get
  126. {
  127. if (this.reader == null)
  128. {
  129. throw new InvalidOperationException();
  130. }
  131. bool flag = false;
  132. MethodEntry[] result;
  133. this.read_methods();
  134. MethodEntry[] retval = new MethodEntry[this.MethodCount];
  135. this.method_list.CopyTo(retval, 0);
  136. result = retval;
  137. return result;
  138. }
  139. }
  140. internal MyBinaryReader BinaryReader
  141. {
  142. get
  143. {
  144. if (this.reader == null)
  145. {
  146. throw new InvalidOperationException();
  147. }
  148. return this.reader;
  149. }
  150. }
  151. internal MonoSymbolFile()
  152. {
  153. this.ot = new OffsetTable();
  154. }
  155. internal int AddSource(SourceFileEntry source)
  156. {
  157. this.sources.Add(source);
  158. return this.sources.Count;
  159. }
  160. internal int AddCompileUnit(CompileUnitEntry entry)
  161. {
  162. this.comp_units.Add(entry);
  163. return this.comp_units.Count;
  164. }
  165. internal int DefineType(Type type)
  166. {
  167. int index;
  168. int result;
  169. if (this.type_hash.TryGetValue(type, out index))
  170. {
  171. result = index;
  172. }
  173. else
  174. {
  175. index = ++this.last_type_index;
  176. this.type_hash.Add(type, index);
  177. result = index;
  178. }
  179. return result;
  180. }
  181. internal void AddMethod(MethodEntry entry)
  182. {
  183. this.methods.Add(entry);
  184. }
  185. public MethodEntry DefineMethod(CompileUnitEntry comp_unit, int token, ScopeVariable[] scope_vars, LocalVariableEntry[] locals, LineNumberEntry[] lines, CodeBlockEntry[] code_blocks, string real_name, MethodEntry.Flags flags, int namespace_id)
  186. {
  187. if (this.reader != null)
  188. {
  189. throw new InvalidOperationException();
  190. }
  191. MethodEntry method = new MethodEntry(this, comp_unit, token, scope_vars, locals, lines, code_blocks, real_name, flags, namespace_id);
  192. this.AddMethod(method);
  193. return method;
  194. }
  195. internal void DefineAnonymousScope(int id)
  196. {
  197. if (this.reader != null)
  198. {
  199. throw new InvalidOperationException();
  200. }
  201. if (this.anonymous_scopes == null)
  202. {
  203. this.anonymous_scopes = new Dictionary<int, AnonymousScopeEntry>();
  204. }
  205. this.anonymous_scopes.Add(id, new AnonymousScopeEntry(id));
  206. }
  207. internal void DefineCapturedVariable(int scope_id, string name, string captured_name, CapturedVariable.CapturedKind kind)
  208. {
  209. if (this.reader != null)
  210. {
  211. throw new InvalidOperationException();
  212. }
  213. AnonymousScopeEntry scope = this.anonymous_scopes[scope_id];
  214. scope.AddCapturedVariable(name, captured_name, kind);
  215. }
  216. internal void DefineCapturedScope(int scope_id, int id, string captured_name)
  217. {
  218. if (this.reader != null)
  219. {
  220. throw new InvalidOperationException();
  221. }
  222. AnonymousScopeEntry scope = this.anonymous_scopes[scope_id];
  223. scope.AddCapturedScope(id, captured_name);
  224. }
  225. internal int GetNextTypeIndex()
  226. {
  227. return ++this.last_type_index;
  228. }
  229. internal int GetNextMethodIndex()
  230. {
  231. return ++this.last_method_index;
  232. }
  233. internal int GetNextNamespaceIndex()
  234. {
  235. return ++this.last_namespace_index;
  236. }
  237. //private void Write(MyBinaryWriter bw, Guid guid)
  238. //{
  239. // bw.Write(5037318119232611860L);
  240. // bw.Write(this.MajorVersion);
  241. // bw.Write(this.MinorVersion);
  242. // bw.Write(guid.ToByteArray());
  243. // long offset_table_offset = bw.BaseStream.Position;
  244. // this.ot.Write(bw, this.MajorVersion, this.MinorVersion);
  245. // this.methods.Sort();
  246. // for (int i = 0; i < this.methods.Count; i++)
  247. // {
  248. // this.methods[i].Index = i + 1;
  249. // }
  250. // this.ot.DataSectionOffset = (int)bw.BaseStream.Position;
  251. // foreach (SourceFileEntry source in this.sources)
  252. // {
  253. // //SourceFileEntry source;
  254. // source.WriteData(bw);
  255. // }
  256. // foreach (CompileUnitEntry comp_unit in this.comp_units)
  257. // {
  258. // comp_unit.WriteData(bw);
  259. // }
  260. // foreach (MethodEntry method in this.methods)
  261. // {
  262. // method.WriteData(this, bw);
  263. // }
  264. // this.ot.DataSectionSize = (int)bw.BaseStream.Position - this.ot.DataSectionOffset;
  265. // this.ot.MethodTableOffset = (int)bw.BaseStream.Position;
  266. // for (int i = 0; i < this.methods.Count; i++)
  267. // {
  268. // MethodEntry entry = this.methods[i];
  269. // entry.Write(bw);
  270. // }
  271. // this.ot.MethodTableSize = (int)bw.BaseStream.Position - this.ot.MethodTableOffset;
  272. // this.ot.SourceTableOffset = (int)bw.BaseStream.Position;
  273. // for (int i = 0; i < this.sources.Count; i++)
  274. // {
  275. // SourceFileEntry source = this.sources[i];
  276. // source.Write(bw);
  277. // }
  278. // this.ot.SourceTableSize = (int)bw.BaseStream.Position - this.ot.SourceTableOffset;
  279. // this.ot.CompileUnitTableOffset = (int)bw.BaseStream.Position;
  280. // for (int i = 0; i < this.comp_units.Count; i++)
  281. // {
  282. // CompileUnitEntry unit = this.comp_units[i];
  283. // unit.Write(bw);
  284. // }
  285. // this.ot.CompileUnitTableSize = (int)bw.BaseStream.Position - this.ot.CompileUnitTableOffset;
  286. // this.ot.AnonymousScopeCount = ((this.anonymous_scopes != null) ? this.anonymous_scopes.Count : 0);
  287. // this.ot.AnonymousScopeTableOffset = (int)bw.BaseStream.Position;
  288. // if (this.anonymous_scopes != null)
  289. // {
  290. // foreach (AnonymousScopeEntry scope in this.anonymous_scopes.Values)
  291. // {
  292. // scope.Write(bw);
  293. // }
  294. // }
  295. // this.ot.AnonymousScopeTableSize = (int)bw.BaseStream.Position - this.ot.AnonymousScopeTableOffset;
  296. // this.ot.TypeCount = this.last_type_index;
  297. // this.ot.MethodCount = this.methods.Count;
  298. // this.ot.SourceCount = this.sources.Count;
  299. // this.ot.CompileUnitCount = this.comp_units.Count;
  300. // this.ot.TotalFileSize = (int)bw.BaseStream.Position;
  301. // bw.Seek((int)offset_table_offset, SeekOrigin.Begin);
  302. // this.ot.Write(bw, this.MajorVersion, this.MinorVersion);
  303. // bw.Seek(0, SeekOrigin.End);
  304. //}
  305. //public void CreateSymbolFile(Guid guid, FileStream fs)
  306. //{
  307. // if (this.reader != null)
  308. // {
  309. // throw new InvalidOperationException();
  310. // }
  311. // this.Write(new MyBinaryWriter(fs), guid);
  312. //}
  313. private MonoSymbolFile(System.IO.Stream stream)
  314. {
  315. //this.FileName = filename;
  316. //FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
  317. this.reader = new MyBinaryReader(stream);
  318. try
  319. {
  320. long magic = this.reader.ReadInt64();
  321. int major_version = this.reader.ReadInt32();
  322. int minor_version = this.reader.ReadInt32();
  323. if (magic != 5037318119232611860L)
  324. {
  325. throw new MonoSymbolFileException("Symbol file `{0}' is not a valid Mono symbol file", new object[]
  326. {
  327. //filename
  328. });
  329. }
  330. if (major_version != 50)
  331. {
  332. throw new MonoSymbolFileException("Symbol file `{0}' has version {1}, but expected {2}", new object[]
  333. {
  334. //filename,
  335. major_version,
  336. 50
  337. });
  338. }
  339. if (minor_version != 0)
  340. {
  341. throw new MonoSymbolFileException("Symbol file `{0}' has version {1}.{2}, but expected {3}.{4}", new object[]
  342. {
  343. //filename,
  344. major_version,
  345. minor_version,
  346. 50,
  347. 0
  348. });
  349. }
  350. this.MajorVersion = major_version;
  351. this.MinorVersion = minor_version;
  352. this.guid = new Guid(this.reader.ReadBytes(16));
  353. this.ot = new OffsetTable(this.reader, major_version, minor_version);
  354. }
  355. catch
  356. {
  357. throw new MonoSymbolFileException("Cannot read symbol file `{0}'", new object[]
  358. {
  359. //filename
  360. });
  361. }
  362. this.source_file_hash = new Dictionary<int, SourceFileEntry>();
  363. this.compile_unit_hash = new Dictionary<int, CompileUnitEntry>();
  364. }
  365. private MonoSymbolFile(string filename)
  366. {
  367. this.FileName = filename;
  368. FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
  369. this.reader = new MyBinaryReader(stream);
  370. try
  371. {
  372. long magic = this.reader.ReadInt64();
  373. int major_version = this.reader.ReadInt32();
  374. int minor_version = this.reader.ReadInt32();
  375. if (magic != 5037318119232611860L)
  376. {
  377. throw new MonoSymbolFileException("Symbol file `{0}' is not a valid Mono symbol file", new object[]
  378. {
  379. filename
  380. });
  381. }
  382. if (major_version != 50)
  383. {
  384. throw new MonoSymbolFileException("Symbol file `{0}' has version {1}, but expected {2}", new object[]
  385. {
  386. filename,
  387. major_version,
  388. 50
  389. });
  390. }
  391. if (minor_version != 0)
  392. {
  393. throw new MonoSymbolFileException("Symbol file `{0}' has version {1}.{2}, but expected {3}.{4}", new object[]
  394. {
  395. filename,
  396. major_version,
  397. minor_version,
  398. 50,
  399. 0
  400. });
  401. }
  402. this.MajorVersion = major_version;
  403. this.MinorVersion = minor_version;
  404. this.guid = new Guid(this.reader.ReadBytes(16));
  405. this.ot = new OffsetTable(this.reader, major_version, minor_version);
  406. }
  407. catch
  408. {
  409. throw new MonoSymbolFileException("Cannot read symbol file `{0}'", new object[]
  410. {
  411. filename
  412. });
  413. }
  414. this.source_file_hash = new Dictionary<int, SourceFileEntry>();
  415. this.compile_unit_hash = new Dictionary<int, CompileUnitEntry>();
  416. }
  417. private void CheckGuidMatch(Guid other, string filename, string assembly)
  418. {
  419. if (other == this.guid)
  420. {
  421. return;
  422. }
  423. throw new MonoSymbolFileException("Symbol file `{0}' does not match assembly `{1}'", new object[]
  424. {
  425. filename,
  426. assembly
  427. });
  428. }
  429. protected MonoSymbolFile(string filename, ModuleDefinition module)
  430. : this(filename)
  431. {
  432. if (module != null)
  433. {
  434. this.CheckGuidMatch(module.Mvid, filename, module.FullyQualifiedName);
  435. }
  436. }
  437. protected MonoSymbolFile(System.IO.Stream stream, ModuleDefinition module)
  438. : this(stream)
  439. {
  440. if (module != null)
  441. {
  442. //this.CheckGuidMatch(module.Mvid, filename, module.FullyQualifiedName);
  443. }
  444. }
  445. public static MonoSymbolFile ReadSymbolFile(ModuleDefinition module)
  446. {
  447. return MonoSymbolFile.ReadSymbolFile(module, module.FullyQualifiedName);
  448. }
  449. public static MonoSymbolFile ReadSymbolFile(ModuleDefinition module, string filename)
  450. {
  451. string name = filename + ".mdb";
  452. return new MonoSymbolFile(name, module);
  453. }
  454. public static MonoSymbolFile ReadSymbolFile(ModuleDefinition module, System.IO.Stream stream)
  455. {
  456. return new MonoSymbolFile(stream, module);
  457. }
  458. public static MonoSymbolFile ReadSymbolFile(string mdbFilename)
  459. {
  460. return new MonoSymbolFile(mdbFilename);
  461. }
  462. public SourceFileEntry GetSourceFile(int index)
  463. {
  464. if (index < 1 || index > this.ot.SourceCount)
  465. {
  466. throw new ArgumentException();
  467. }
  468. if (this.reader == null)
  469. {
  470. throw new InvalidOperationException();
  471. }
  472. SourceFileEntry result;
  473. SourceFileEntry source;
  474. if (this.source_file_hash.TryGetValue(index, out source))
  475. {
  476. result = source;
  477. }
  478. else
  479. {
  480. long old_pos = this.reader.BaseStream.Position;
  481. this.reader.BaseStream.Position = (long)(this.ot.SourceTableOffset + SourceFileEntry.Size * (index - 1));
  482. source = new SourceFileEntry(this, this.reader);
  483. this.source_file_hash.Add(index, source);
  484. this.reader.BaseStream.Position = old_pos;
  485. result = source;
  486. }
  487. return result;
  488. }
  489. public CompileUnitEntry GetCompileUnit(int index)
  490. {
  491. if (index < 1 || index > this.ot.CompileUnitCount)
  492. {
  493. throw new ArgumentException();
  494. }
  495. if (this.reader == null)
  496. {
  497. throw new InvalidOperationException();
  498. }
  499. CompileUnitEntry result;
  500. CompileUnitEntry unit;
  501. if (this.compile_unit_hash.TryGetValue(index, out unit))
  502. {
  503. result = unit;
  504. }
  505. else
  506. {
  507. long old_pos = this.reader.BaseStream.Position;
  508. this.reader.BaseStream.Position = (long)(this.ot.CompileUnitTableOffset + CompileUnitEntry.Size * (index - 1));
  509. unit = new CompileUnitEntry(this, this.reader);
  510. this.compile_unit_hash.Add(index, unit);
  511. this.reader.BaseStream.Position = old_pos;
  512. result = unit;
  513. }
  514. return result;
  515. }
  516. private void read_methods()
  517. {
  518. if (this.method_token_hash == null)
  519. {
  520. this.method_token_hash = new Dictionary<int, MethodEntry>();
  521. this.method_list = new List<MethodEntry>();
  522. long old_pos = this.reader.BaseStream.Position;
  523. this.reader.BaseStream.Position = (long)this.ot.MethodTableOffset;
  524. for (int i = 0; i < this.MethodCount; i++)
  525. {
  526. MethodEntry entry = new MethodEntry(this, this.reader, i + 1);
  527. this.method_token_hash.Add(entry.Token, entry);
  528. this.method_list.Add(entry);
  529. }
  530. this.reader.BaseStream.Position = old_pos;
  531. }
  532. }
  533. public MethodEntry GetMethodByToken(int token)
  534. {
  535. if (this.reader == null)
  536. {
  537. throw new InvalidOperationException();
  538. }
  539. MethodEntry result;
  540. this.read_methods();
  541. MethodEntry me;
  542. this.method_token_hash.TryGetValue(token, out me);
  543. result = me;
  544. return result;
  545. }
  546. public MethodEntry GetMethod(int index)
  547. {
  548. if (index < 1 || index > this.ot.MethodCount)
  549. {
  550. throw new ArgumentException();
  551. }
  552. if (this.reader == null)
  553. {
  554. throw new InvalidOperationException();
  555. }
  556. MethodEntry result;
  557. this.read_methods();
  558. result = this.method_list[index - 1];
  559. return result;
  560. }
  561. public int FindSource(string file_name)
  562. {
  563. if (this.reader == null)
  564. {
  565. throw new InvalidOperationException();
  566. }
  567. int result;
  568. if (this.source_name_hash == null)
  569. {
  570. this.source_name_hash = new Dictionary<string, int>();
  571. for (int i = 0; i < this.ot.SourceCount; i++)
  572. {
  573. SourceFileEntry source = this.GetSourceFile(i + 1);
  574. this.source_name_hash.Add(source.FileName, i);
  575. }
  576. }
  577. int value;
  578. if (!this.source_name_hash.TryGetValue(file_name, out value))
  579. {
  580. result = -1;
  581. }
  582. else
  583. {
  584. result = value;
  585. }
  586. return result;
  587. }
  588. public AnonymousScopeEntry GetAnonymousScope(int id)
  589. {
  590. if (this.reader == null)
  591. {
  592. throw new InvalidOperationException();
  593. }
  594. AnonymousScopeEntry result;
  595. if (this.anonymous_scopes != null)
  596. {
  597. AnonymousScopeEntry scope;
  598. this.anonymous_scopes.TryGetValue(id, out scope);
  599. result = scope;
  600. }
  601. else
  602. {
  603. this.anonymous_scopes = new Dictionary<int, AnonymousScopeEntry>();
  604. this.reader.BaseStream.Position = (long)this.ot.AnonymousScopeTableOffset;
  605. for (int i = 0; i < this.ot.AnonymousScopeCount; i++)
  606. {
  607. AnonymousScopeEntry scope = new AnonymousScopeEntry(this.reader);
  608. this.anonymous_scopes.Add(scope.ID, scope);
  609. }
  610. result = this.anonymous_scopes[id];
  611. }
  612. return result;
  613. }
  614. public void Dispose()
  615. {
  616. this.Dispose(true);
  617. }
  618. protected virtual void Dispose(bool disposing)
  619. {
  620. if (disposing)
  621. {
  622. if (this.reader != null)
  623. {
  624. this.reader.Close();
  625. this.reader = null;
  626. }
  627. }
  628. }
  629. }
  630. }