MonoSymbolFile.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. //
  2. // Mono.CSharp.Debugger/MonoSymbolFile.cs
  3. //
  4. // Author:
  5. // Martin Baulig ([email protected])
  6. //
  7. // (C) 2003 Ximian, Inc. http://www.ximian.com
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Reflection;
  31. using System.Collections;
  32. using System.Text;
  33. using System.Threading;
  34. using System.IO;
  35. namespace Mono.CompilerServices.SymbolWriter
  36. {
  37. public class MonoSymbolFileException : Exception
  38. {
  39. public MonoSymbolFileException ()
  40. : base ()
  41. { }
  42. public MonoSymbolFileException (string message, params object[] args)
  43. : base (String.Format (message, args))
  44. { }
  45. }
  46. internal class MyMemoryStream : Stream
  47. {
  48. int length;
  49. int real_length;
  50. int position;
  51. int chunk_size = 4096;
  52. ArrayList chunks = new ArrayList ();
  53. private struct Chunk {
  54. public readonly int Offset;
  55. public readonly int Length;
  56. public byte[] Buffer;
  57. public Chunk (int offset, int length)
  58. {
  59. this.Offset = offset;
  60. this.Length = length;
  61. this.Buffer = new Byte [length];
  62. }
  63. }
  64. public override long Position {
  65. get { return position; }
  66. set {
  67. if (value > length)
  68. throw new ArgumentOutOfRangeException ();
  69. position = (int) value;
  70. }
  71. }
  72. public override long Length {
  73. get { return length; }
  74. }
  75. public override bool CanRead {
  76. get { return true; }
  77. }
  78. public override bool CanWrite {
  79. get { return true; }
  80. }
  81. public override bool CanSeek {
  82. get { return true; }
  83. }
  84. public override void SetLength (long new_length)
  85. {
  86. if (new_length < length)
  87. throw new ArgumentException ();
  88. while (new_length >= real_length) {
  89. Chunk new_chunk = new Chunk (real_length, chunk_size);
  90. chunks.Add (new_chunk);
  91. real_length += chunk_size;
  92. }
  93. length = (int) new_length;
  94. }
  95. public override void Flush ()
  96. { }
  97. public override long Seek (long offset, SeekOrigin origin)
  98. {
  99. int ref_point;
  100. switch (origin) {
  101. case SeekOrigin.Begin:
  102. ref_point = 0;
  103. break;
  104. case SeekOrigin.Current:
  105. ref_point = position;
  106. break;
  107. case SeekOrigin.End:
  108. ref_point = length;
  109. break;
  110. default:
  111. throw new ArgumentException ("Invalid SeekOrigin");
  112. }
  113. if ((ref_point + offset < 0) || (offset > real_length))
  114. throw new ArgumentOutOfRangeException ();
  115. position = ref_point + (int) offset;
  116. return position;
  117. }
  118. Chunk FindChunk (int offset)
  119. {
  120. return (Chunk) chunks [offset / chunk_size];
  121. }
  122. public override int Read (byte[] buffer, int offset, int count)
  123. {
  124. int old_count = count;
  125. while (count > 0) {
  126. Chunk chunk = FindChunk (position);
  127. int coffset = position - chunk.Offset;
  128. int rest = chunk.Length - coffset;
  129. int size = System.Math.Min (count, rest);
  130. Array.Copy (chunk.Buffer, coffset, buffer, offset, size);
  131. position += size;
  132. offset += size;
  133. count -= size;
  134. }
  135. return old_count;
  136. }
  137. public override void Write (byte[] buffer, int offset, int count)
  138. {
  139. if (position + count > length)
  140. SetLength (position + count);
  141. while (count > 0) {
  142. Chunk chunk = FindChunk (position);
  143. int coffset = position - chunk.Offset;
  144. int rest = chunk.Length - coffset;
  145. int size = System.Math.Min (count, rest);
  146. Array.Copy (buffer, offset, chunk.Buffer, coffset, size);
  147. position += size;
  148. offset += size;
  149. count -= size;
  150. }
  151. }
  152. public byte[] GetContents ()
  153. {
  154. byte[] retval = new byte [length];
  155. position = 0;
  156. Read (retval, 0, length);
  157. return retval;
  158. }
  159. }
  160. internal class MyBinaryWriter : BinaryWriter
  161. {
  162. public MyBinaryWriter (Stream stream)
  163. : base (stream)
  164. { }
  165. public void WriteLeb128 (int value)
  166. {
  167. base.Write7BitEncodedInt (value);
  168. }
  169. }
  170. internal class MyBinaryReader : BinaryReader
  171. {
  172. public MyBinaryReader (Stream stream)
  173. : base (stream)
  174. { }
  175. public int ReadLeb128 ()
  176. {
  177. return base.Read7BitEncodedInt ();
  178. }
  179. }
  180. public class MonoDebuggerSupport
  181. {
  182. static GetTypeFunc get_type;
  183. static GetMethodTokenFunc get_method_token;
  184. static GetMethodFunc get_method;
  185. static GetLocalTypeFromSignatureFunc local_type_from_sig;
  186. static GetGuidFunc get_guid;
  187. delegate Type GetTypeFunc (Assembly assembly, int token);
  188. delegate int GetMethodTokenFunc (Assembly assembly, MethodBase method);
  189. delegate MethodBase GetMethodFunc (Assembly assembly, int token);
  190. delegate Type GetLocalTypeFromSignatureFunc (Assembly assembly, byte[] sig);
  191. delegate Guid GetGuidFunc (Module module);
  192. static Delegate create_delegate (Type type, Type delegate_type, string name)
  193. {
  194. MethodInfo mi = type.GetMethod (name, BindingFlags.Static |
  195. BindingFlags.NonPublic);
  196. if (mi == null)
  197. throw new Exception ("Can't find " + name);
  198. return Delegate.CreateDelegate (delegate_type, mi);
  199. }
  200. static MonoDebuggerSupport ()
  201. {
  202. get_type = (GetTypeFunc) create_delegate (
  203. typeof (Assembly), typeof (GetTypeFunc),
  204. "MonoDebugger_GetType");
  205. get_method_token = (GetMethodTokenFunc) create_delegate (
  206. typeof (Assembly), typeof (GetMethodTokenFunc),
  207. "MonoDebugger_GetMethodToken");
  208. get_method = (GetMethodFunc) create_delegate (
  209. typeof (Assembly), typeof (GetMethodFunc),
  210. "MonoDebugger_GetMethod");
  211. local_type_from_sig = (GetLocalTypeFromSignatureFunc) create_delegate (
  212. typeof (Assembly), typeof (GetLocalTypeFromSignatureFunc),
  213. "MonoDebugger_GetLocalTypeFromSignature");
  214. get_guid = (GetGuidFunc) create_delegate (
  215. typeof (Module), typeof (GetGuidFunc), "Mono_GetGuid");
  216. }
  217. public static Type GetType (Assembly assembly, int token)
  218. {
  219. return get_type (assembly, token);
  220. }
  221. public static int GetMethodToken (MethodBase method)
  222. {
  223. return get_method_token (method.ReflectedType.Assembly, method);
  224. }
  225. public static MethodBase GetMethod (Assembly assembly, int token)
  226. {
  227. return get_method (assembly, token);
  228. }
  229. public static Type GetLocalTypeFromSignature (Assembly assembly, byte[] sig)
  230. {
  231. return local_type_from_sig (assembly, sig);
  232. }
  233. public static Guid GetGuid (Module module)
  234. {
  235. return get_guid (module);
  236. }
  237. }
  238. public class MonoSymbolFile : IDisposable
  239. {
  240. ArrayList methods = new ArrayList ();
  241. ArrayList sources = new ArrayList ();
  242. Hashtable method_source_hash = new Hashtable ();
  243. Hashtable type_hash = new Hashtable ();
  244. OffsetTable ot;
  245. int last_type_index;
  246. int last_method_index;
  247. int last_source_index;
  248. int last_namespace_index;
  249. public int NumLineNumbers;
  250. public MonoSymbolFile ()
  251. { }
  252. internal int AddSource (SourceFileEntry source)
  253. {
  254. sources.Add (source);
  255. return ++last_source_index;
  256. }
  257. internal int DefineType (Type type)
  258. {
  259. if (type_hash.Contains (type))
  260. return (int) type_hash [type];
  261. int index = ++last_type_index;
  262. type_hash.Add (type, index);
  263. return index;
  264. }
  265. internal void AddMethod (MethodEntry entry)
  266. {
  267. methods.Add (entry);
  268. }
  269. internal int GetNextTypeIndex ()
  270. {
  271. return ++last_type_index;
  272. }
  273. internal int GetNextMethodIndex ()
  274. {
  275. return ++last_method_index;
  276. }
  277. internal int GetNextNamespaceIndex ()
  278. {
  279. return ++last_namespace_index;
  280. }
  281. byte [] stringBuffer;
  282. int maxCharsPerRound;
  283. static Encoding enc = Encoding.UTF8;
  284. internal string ReadString (int offset)
  285. {
  286. int old_pos = (int) reader.BaseStream.Position;
  287. reader.BaseStream.Position = offset;
  288. string text = reader.ReadString ();
  289. reader.BaseStream.Position = old_pos;
  290. return text;
  291. }
  292. void Write (MyBinaryWriter bw, Guid guid)
  293. {
  294. // Magic number and file version.
  295. bw.Write (OffsetTable.Magic);
  296. bw.Write (OffsetTable.Version);
  297. bw.Write (guid.ToByteArray ());
  298. //
  299. // Offsets of file sections; we must write this after we're done
  300. // writing the whole file, so we just reserve the space for it here.
  301. //
  302. long offset_table_offset = bw.BaseStream.Position;
  303. ot.Write (bw);
  304. //
  305. // Write data sections.
  306. //
  307. ot.DataSectionOffset = (int) bw.BaseStream.Position;
  308. foreach (SourceFileEntry source in sources)
  309. source.WriteData (bw);
  310. ot.DataSectionSize = (int) bw.BaseStream.Position - ot.DataSectionOffset;
  311. //
  312. // Write out the method index
  313. //
  314. ot.MethodTableOffset = (int) bw.BaseStream.Position;
  315. for (int i = 0; i < methods.Count; i++) {
  316. MethodEntry entry = (MethodEntry) methods [i];
  317. entry.WriteIndex (bw);
  318. }
  319. ot.MethodTableSize = (int) bw.BaseStream.Position - ot.MethodTableOffset;
  320. //
  321. // Write source table.
  322. //
  323. ot.SourceTableOffset = (int) bw.BaseStream.Position;
  324. for (int i = 0; i < sources.Count; i++) {
  325. SourceFileEntry source = (SourceFileEntry) sources [i];
  326. source.Write (bw);
  327. }
  328. ot.SourceTableSize = (int) bw.BaseStream.Position - ot.SourceTableOffset;
  329. //
  330. // Fixup offset table.
  331. //
  332. ot.TypeCount = last_type_index;
  333. ot.MethodCount = methods.Count;
  334. ot.SourceCount = sources.Count;
  335. //
  336. // Write offset table.
  337. //
  338. ot.TotalFileSize = (int) bw.BaseStream.Position;
  339. bw.Seek ((int) offset_table_offset, SeekOrigin.Begin);
  340. ot.Write (bw);
  341. bw.Seek (0, SeekOrigin.End);
  342. }
  343. public byte[] CreateSymbolFile (Guid guid)
  344. {
  345. if (reader != null)
  346. throw new InvalidOperationException ();
  347. using (MyMemoryStream stream = new MyMemoryStream ()) {
  348. Write (new MyBinaryWriter (stream), guid);
  349. return stream.GetContents ();
  350. }
  351. }
  352. Assembly assembly;
  353. MyBinaryReader reader;
  354. Hashtable method_hash;
  355. Hashtable source_file_hash;
  356. Hashtable method_token_hash;
  357. Hashtable source_name_hash;
  358. protected MonoSymbolFile (string filename, Assembly assembly)
  359. {
  360. this.assembly = assembly;
  361. FileStream stream = new FileStream (filename, FileMode.Open, FileAccess.Read);
  362. reader = new MyBinaryReader (stream);
  363. Guid guid;
  364. try {
  365. long magic = reader.ReadInt64 ();
  366. long version = reader.ReadInt32 ();
  367. if (magic != OffsetTable.Magic)
  368. throw new MonoSymbolFileException (
  369. "Symbol file `{0}' is not a valid " +
  370. "Mono symbol file", filename);
  371. if (version != OffsetTable.Version)
  372. throw new MonoSymbolFileException (
  373. "Symbol file `{0}' has version {1}, " +
  374. "but expected {2}", filename, version,
  375. OffsetTable.Version);
  376. guid = new Guid (reader.ReadBytes (16));
  377. ot = new OffsetTable (reader);
  378. } catch {
  379. throw new MonoSymbolFileException (
  380. "Cannot read symbol file `{0}'", filename);
  381. }
  382. Module[] modules = assembly.GetModules ();
  383. Guid assembly_guid = MonoDebuggerSupport.GetGuid (modules [0]);
  384. if (guid != assembly_guid)
  385. throw new MonoSymbolFileException (
  386. "Symbol file `{0}' does not match assembly `{1}'",
  387. filename, assembly.Location);
  388. method_hash = new Hashtable ();
  389. source_file_hash = new Hashtable ();
  390. }
  391. public static MonoSymbolFile ReadSymbolFile (Assembly assembly)
  392. {
  393. string filename = assembly.Location;
  394. string name = filename + ".mdb";
  395. return new MonoSymbolFile (name, assembly);
  396. }
  397. public Assembly Assembly {
  398. get { return assembly; }
  399. }
  400. public int SourceCount {
  401. get { return ot.SourceCount; }
  402. }
  403. public int MethodCount {
  404. get { return ot.MethodCount; }
  405. }
  406. public int TypeCount {
  407. get { return ot.TypeCount; }
  408. }
  409. public int NamespaceCount {
  410. get { return last_namespace_index; }
  411. }
  412. internal int LineNumberCount = 0;
  413. internal int LocalCount = 0;
  414. internal int StringSize = 0;
  415. public SourceFileEntry GetSourceFile (int index)
  416. {
  417. if ((index < 1) || (index > ot.SourceCount))
  418. throw new ArgumentException ();
  419. if (reader == null)
  420. throw new InvalidOperationException ();
  421. SourceFileEntry source = (SourceFileEntry) source_file_hash [index];
  422. if (source != null)
  423. return source;
  424. reader.BaseStream.Position = ot.SourceTableOffset +
  425. SourceFileEntry.Size * (index - 1);
  426. source = new SourceFileEntry (this, reader);
  427. source_file_hash.Add (index, source);
  428. return source;
  429. }
  430. public SourceFileEntry[] Sources {
  431. get {
  432. if (reader == null)
  433. throw new InvalidOperationException ();
  434. SourceFileEntry[] retval = new SourceFileEntry [SourceCount];
  435. for (int i = 0; i < SourceCount; i++)
  436. retval [i] = GetSourceFile (i + 1);
  437. return retval;
  438. }
  439. }
  440. public MethodIndexEntry GetMethodIndexEntry (int index)
  441. {
  442. int old_pos = (int) reader.BaseStream.Position;
  443. reader.BaseStream.Position = ot.MethodTableOffset +
  444. MethodIndexEntry.Size * (index - 1);
  445. MethodIndexEntry ie = new MethodIndexEntry (reader);
  446. reader.BaseStream.Position = old_pos;
  447. return ie;
  448. }
  449. public MethodEntry GetMethodByToken (int token)
  450. {
  451. if (reader == null)
  452. throw new InvalidOperationException ();
  453. if (method_token_hash == null) {
  454. method_token_hash = new Hashtable ();
  455. for (int i = 0; i < MethodCount; i++) {
  456. MethodIndexEntry ie = GetMethodIndexEntry (i + 1);
  457. method_token_hash.Add (ie.Token, i + 1);
  458. }
  459. }
  460. object value = method_token_hash [token];
  461. if (value == null)
  462. return null;
  463. return GetMethod ((int) value);
  464. }
  465. public MethodEntry GetMethod (MethodBase method)
  466. {
  467. if (reader == null)
  468. throw new InvalidOperationException ();
  469. int token = MonoDebuggerSupport.GetMethodToken (method);
  470. return GetMethodByToken (token);
  471. }
  472. public MethodEntry GetMethod (int index)
  473. {
  474. if ((index < 1) || (index > ot.MethodCount))
  475. throw new ArgumentException ();
  476. if (reader == null)
  477. throw new InvalidOperationException ();
  478. MethodEntry entry = (MethodEntry) method_hash [index];
  479. if (entry != null)
  480. return entry;
  481. MethodIndexEntry ie = GetMethodIndexEntry (index);
  482. reader.BaseStream.Position = ie.FileOffset;
  483. entry = new MethodEntry (this, reader, index);
  484. method_hash.Add (index, entry);
  485. return entry;
  486. }
  487. public MethodEntry[] Methods {
  488. get {
  489. if (reader == null)
  490. throw new InvalidOperationException ();
  491. MethodEntry[] retval = new MethodEntry [MethodCount];
  492. for (int i = 0; i < MethodCount; i++)
  493. retval [i] = GetMethod (i + 1);
  494. return retval;
  495. }
  496. }
  497. public MethodSourceEntry GetMethodSource (int index)
  498. {
  499. if ((index < 1) || (index > ot.MethodCount))
  500. throw new ArgumentException ();
  501. if (reader == null)
  502. throw new InvalidOperationException ();
  503. object entry = method_source_hash [index];
  504. if (entry != null)
  505. return (MethodSourceEntry) entry;
  506. MethodEntry method = GetMethod (index);
  507. foreach (MethodSourceEntry source in method.SourceFile.Methods) {
  508. if (source.Index == index) {
  509. method_source_hash.Add (index, source);
  510. return source;
  511. }
  512. }
  513. throw new MonoSymbolFileException ("Internal error.");
  514. }
  515. public int FindSource (string file_name)
  516. {
  517. if (reader == null)
  518. throw new InvalidOperationException ();
  519. if (source_name_hash == null) {
  520. source_name_hash = new Hashtable ();
  521. for (int i = 0; i < ot.SourceCount; i++) {
  522. SourceFileEntry source = GetSourceFile (i + 1);
  523. source_name_hash.Add (source.FileName, i);
  524. }
  525. }
  526. object value = source_name_hash [file_name];
  527. if (value == null)
  528. return -1;
  529. return (int) value;
  530. }
  531. internal MyBinaryReader BinaryReader {
  532. get {
  533. if (reader == null)
  534. throw new InvalidOperationException ();
  535. return reader;
  536. }
  537. }
  538. void IDisposable.Dispose ()
  539. {
  540. Dispose (true);
  541. }
  542. protected virtual void Dispose (bool disposing)
  543. {
  544. if (disposing) {
  545. if (reader != null) {
  546. reader.Close ();
  547. reader = null;
  548. }
  549. }
  550. }
  551. }
  552. }