2
0

PDBClasses.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  1. /*
  2. * PERWAPI - An API for Reading and Writing PE Files
  3. *
  4. * Copyright (c) Diane Corney, Queensland University of Technology, 2004.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the PERWAPI Copyright as included with this
  8. * distribution in the file PERWAPIcopyright.rtf.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY as is explained in the copyright notice.
  12. *
  13. * The author may be contacted at d.corney@qut.edu.au
  14. *
  15. * Version Date: 26/01/07
  16. */
  17. // If the compilation requires the use of the original
  18. // SimpleWriter.dll
  19. // then define the following symbol
  20. // #define SIMPLEWRITER
  21. // without this symbol, the code requires SymbolRW.
  22. using System;
  23. using System.IO;
  24. using System.Collections;
  25. using System.Diagnostics;
  26. using System.Diagnostics.SymbolStore;
  27. using QSy = QUT.Symbols;
  28. namespace QUT.PERWAPI
  29. {
  30. /**************************************************************************
  31. * Classes related to PDB *
  32. **************************************************************************/
  33. #region PDB Classes
  34. /// <summary>
  35. /// Writes PDB files
  36. /// </summary>
  37. public class PDBWriter
  38. {
  39. private ArrayList _docWriters = new ArrayList();
  40. private ArrayList methods = new ArrayList();
  41. private Method currentMethod = null;
  42. private Scope currentScope = null;
  43. private string filename;
  44. private byte[] debugInfo;
  45. private SymbolToken entryPoint;
  46. /// <summary>
  47. /// The name of the PE file this PDB file belongs to.
  48. /// </summary>
  49. public string PEFilename
  50. {
  51. get { return filename; }
  52. }
  53. /// <summary>
  54. /// The name of the PDB file being written.
  55. /// </summary>
  56. public string PDBFilename
  57. {
  58. get { return Path.ChangeExtension(filename, ".pdb"); }
  59. }
  60. /// <summary>
  61. /// Provide access to the debug info which needs to be written to the PE file.
  62. /// This is only available after the call to WritePDBFile() has been made.
  63. /// </summary>
  64. public byte[] DebugInfo
  65. {
  66. get
  67. {
  68. if (debugInfo == null) throw new Exception("DeugInfo is only available after calling WritePDBFile()");
  69. return debugInfo;
  70. }
  71. }
  72. /// <summary>
  73. /// Create a new instance of the PDB Writer
  74. /// </summary>
  75. /// <param name="PEFilename">The name of the PE file we are writting the PDB file for.</param>
  76. public PDBWriter(string PEFilename)
  77. {
  78. filename = PEFilename;
  79. }
  80. /// <summary>
  81. /// Set the entry method of the applicaiton
  82. /// </summary>
  83. /// <param name="token">The token for the entry method.</param>
  84. public void SetEntryPoint(int token)
  85. {
  86. entryPoint = new SymbolToken(token);
  87. }
  88. /// <summary>
  89. /// Open a new scope.
  90. /// </summary>
  91. /// <param name="offset">Offset as to where the scope should start.</param>
  92. public void OpenScope(int offset)
  93. {
  94. // Make sure we are in a method
  95. if (currentMethod == null)
  96. throw new Exception("You can not open a scope before opening a method.");
  97. // Create and add the new scope
  98. Scope scope = new Scope();
  99. scope.OffsetStart = offset;
  100. scope.ParentScope = currentScope;
  101. // Check if this is the first/root scope or a child scope.
  102. if (currentScope == null)
  103. {
  104. // Check to make sure we don't try to create two root scopes.
  105. if (currentMethod.Scope != null)
  106. throw new Exception("Only one top-most scope is permitted.");
  107. currentMethod.Scope = scope;
  108. }
  109. else
  110. {
  111. currentScope.ChildScopes.Add(scope);
  112. }
  113. // Set the current scope
  114. currentScope = scope;
  115. }
  116. /// <summary>
  117. /// Close the current scope at the given offset.
  118. /// </summary>
  119. /// <param name="offset">The offset of where to close the scope.</param>
  120. public void CloseScope(int offset)
  121. {
  122. // Make sure a scope is open
  123. if (currentScope == null)
  124. throw new Exception("You can not close a scope now, none are open.");
  125. // Set the end offset for this scope and close it.
  126. currentScope.OffsetEnd = offset;
  127. currentScope = currentScope.ParentScope;
  128. }
  129. /// <summary>
  130. /// Bind a local to the current scope.
  131. /// </summary>
  132. /// <param name="name">The name of the variable.</param>
  133. /// <param name="idx">The index of the variable in the locals table.</param>
  134. /// <param name="token">The symbol token for the given variable.</param>
  135. /// <param name="startOffset">The starting offset for the binding. Set to 0 to default to current scope.</param>
  136. /// <param name="endOffset">The ending offset for the binding. Set to 0 to default to current scope.</param>
  137. public void BindLocal(string name, int idx, uint token, int startOffset, int endOffset)
  138. {
  139. // Check to make sure a scope is open
  140. if (currentScope == null)
  141. throw new Exception("You must have an open scope in order to bind locals.");
  142. // Create the new local binding object
  143. LocalBinding lb = new LocalBinding();
  144. lb.Name = name;
  145. lb.Index = idx;
  146. lb.Token = new SymbolToken((int)token);
  147. lb.OffsetStart = startOffset;
  148. lb.OffsetEnd = endOffset;
  149. // Add to the current scope
  150. currentScope.Locals.Add(lb);
  151. }
  152. /// <summary>
  153. /// Adds a given ConstantBinding to the current scope.
  154. /// </summary>
  155. /// <param name="binding">The constant to add to this scope.</param>
  156. /* Not supported at this time. Doesn't work correctly. AKB 2007-02-03
  157. public void BindConstant(ConstantBinding binding) {
  158. // Check to make sure a scope is open
  159. if (currentScope == null)
  160. throw new Exception("You must have an open scope in order to bind a constant.");
  161. // Add the constants to the current scope
  162. currentScope.Constants.Add(binding);
  163. }
  164. */
  165. /// <summary>
  166. /// Add a new sequnce point.
  167. /// </summary>
  168. /// <param name="sourceFile">The source file the sequence point is in.</param>
  169. /// <param name="docLanguage">The language of the source file.</param>
  170. /// <param name="langVendor">The language vendor of the source file.</param>
  171. /// <param name="docType">The document type.</param>
  172. /// <param name="offset">The offset of the sequence point.</param>
  173. /// <param name="line">The starting line for the sequence point.</param>
  174. /// <param name="col">The starting column for the sequence point.</param>
  175. /// <param name="endLine">The ending line for the sequence point.</param>
  176. /// <param name="endCol">The ending column for the sequence point.</param>
  177. public void AddSequencePoint(string sourceFile, Guid docLanguage, Guid langVendor, Guid docType, int offset, int line, int col, int endLine, int endCol)
  178. {
  179. Document sourceDoc = null;
  180. // Make sure we are in a method
  181. if (currentMethod == null)
  182. throw new Exception("You can not add sequence points before opening a method.");
  183. // Check if a reference for this source document already exists
  184. foreach (Document doc in _docWriters)
  185. if (sourceFile == doc._file && docLanguage == doc._docLanguage && langVendor == doc._langVendor && docType == doc._docType)
  186. {
  187. sourceDoc = doc;
  188. break;
  189. }
  190. // If no existing document, create a new one
  191. if (sourceDoc == null)
  192. {
  193. sourceDoc = new Document();
  194. sourceDoc._file = sourceFile;
  195. sourceDoc._docLanguage = docLanguage;
  196. sourceDoc._langVendor = langVendor;
  197. sourceDoc._docType = docType;
  198. _docWriters.Add(sourceDoc);
  199. }
  200. SequencePointList spList = (SequencePointList)currentMethod.SequencePointList[sourceDoc];
  201. if (spList == null)
  202. currentMethod.SequencePointList.Add(sourceDoc, spList = new SequencePointList());
  203. spList.offsets.Add(offset);
  204. spList.lines.Add(line);
  205. spList.cols.Add(col);
  206. spList.endLines.Add(endLine);
  207. spList.endCols.Add(endCol);
  208. }
  209. /// <summary>
  210. /// Open a method. Scopes and sequence points will be added to this method.
  211. /// </summary>
  212. /// <param name="token">The token for this method.</param>
  213. public void OpenMethod(int token)
  214. {
  215. // Add this new method to the list of methods
  216. Method meth = new Method();
  217. meth.Token = new SymbolToken(token);
  218. methods.Add(meth);
  219. // Set the current method
  220. currentMethod = meth;
  221. }
  222. /// <summary>
  223. /// Close the current method.
  224. /// </summary>
  225. public void CloseMethod()
  226. {
  227. // Make sure a method is open
  228. if (currentMethod == null)
  229. throw new Exception("No methods currently open.");
  230. // Check to make sure all scopes have been closed.
  231. if (currentScope != null)
  232. throw new Exception("Can not close method until all scopes are closed. Method Token: " + currentMethod.Token.ToString());
  233. // Change the current method to null
  234. currentMethod = null;
  235. }
  236. /// <summary>
  237. /// Write the PDB file to disk.
  238. /// </summary>
  239. public void WritePDBFile()
  240. {
  241. /*
  242. * Write default template PDB file first
  243. *
  244. * NOTE: This is a dodgy hack so please feel free to change! AKB 06-01-2007
  245. *
  246. * For some reason if there isn't a PDB file to start with the
  247. * debugger used to step through the resulting PDB file will
  248. * jump all over the place. Resulting in incorrect step-throughs.
  249. * I have not been able to work out why yet but I think it has
  250. * something to do with the call to GetWriterForFile().
  251. * Also, it doesn't happen on all PDB files.
  252. * It is interesting to note that if it is writting a debug file
  253. * to go with a PE file compiled by csc (MS Compiler) it works fine.
  254. */
  255. // Get the blank PDB file from the resource assembly
  256. System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
  257. Stream blankPDB = currentAssembly.GetManifestResourceStream("QUT.PERWAPI.Blank.pdb");
  258. // Write the blank PDB file to the disk
  259. using (FileStream fs = new FileStream(PDBFilename, FileMode.OpenOrCreate, FileAccess.Write))
  260. {
  261. BinaryWriter bw = new BinaryWriter(fs);
  262. // Loop through the PDB file and write it to the disk
  263. byte[] buffer = new byte[32768];
  264. while (true)
  265. {
  266. int read = blankPDB.Read(buffer, 0, buffer.Length);
  267. if (read <= 0) break;
  268. bw.Write(buffer, 0, read);
  269. }
  270. // Close all of the streams we have opened
  271. bw.Close();
  272. fs.Close();
  273. }
  274. // Create the new Symbol Writer
  275. QSy.SymbolWriter symWriter = new QSy.SymbolWriter(PEFilename, PDBFilename);
  276. // Add each of the source documents
  277. foreach (Document doc in _docWriters)
  278. {
  279. #if SIMPLEWRITER
  280. doc._docWriter = symWriter.DefineDocument(
  281. doc._file,
  282. doc._docLanguage,
  283. doc._langVendor,
  284. doc._docType
  285. );
  286. // Set the entry point if it exists
  287. if (entryPoint.GetToken() != 0)
  288. symWriter.SetUserEntryPoint(entryPoint.GetToken());
  289. #else
  290. doc.docWriter = symWriter.DefineDocument(
  291. doc._file,
  292. ref doc._docLanguage,
  293. ref doc._langVendor,
  294. ref doc._docType
  295. );
  296. // Set the entry point if it exists
  297. if (entryPoint.GetToken() != 0)
  298. symWriter.SetUserEntryPoint(entryPoint);
  299. #endif // SIMPLEWRITER
  300. }
  301. // Loop through and add each method
  302. foreach (Method meth in methods)
  303. {
  304. #if SIMPLEWRITER
  305. symWriter.OpenMethod(meth.Token.GetToken());
  306. #else
  307. symWriter.OpenMethod(meth.Token);
  308. #endif
  309. // Write the scope and the locals
  310. if (meth.Scope != null) WriteScopeAndLocals(symWriter, meth.Scope);
  311. // Add each of the sequence points
  312. foreach (Document sourceDoc in meth.SequencePointList.Keys)
  313. {
  314. SequencePointList spList = (SequencePointList)meth.SequencePointList[sourceDoc];
  315. #if SIMPLEWRITER
  316. symWriter.DefineSequencePoints(sourceDoc._docWriter,
  317. (uint[])spList.offsets.ToArray(typeof(int)),
  318. (uint[])spList.lines.ToArray(typeof(int)),
  319. (uint[])spList.cols.ToArray(typeof(int)),
  320. (uint[])spList.endLines.ToArray(typeof(int)),
  321. (uint[])spList.endCols.ToArray(typeof(int)));
  322. #else
  323. symWriter.DefineSequencePoints(sourceDoc.docWriter,
  324. (int[])spList.offsets.ToArray(typeof(int)),
  325. (int[])spList.lines.ToArray(typeof(int)),
  326. (int[])spList.cols.ToArray(typeof(int)),
  327. (int[])spList.endLines.ToArray(typeof(int)),
  328. (int[])spList.endCols.ToArray(typeof(int)));
  329. #endif // SIMPLEWRITER
  330. }
  331. symWriter.CloseMethod();
  332. }
  333. // Get the debug info
  334. debugInfo = symWriter.GetDebugInfo();
  335. // Close the PDB file
  336. symWriter.Close();
  337. }
  338. /// <summary>
  339. /// Write out the scopes and the locals to the PDB file.
  340. /// </summary>
  341. /// <param name="symWriter">The symbol writer for this file.</param>
  342. /// <param name="scope">The scope to write out.</param>
  343. private void WriteScopeAndLocals(QSy.SymbolWriter symWriter, Scope scope)
  344. {
  345. // Open the scope
  346. symWriter.OpenScope(scope.OffsetStart);
  347. // Add each local variable
  348. foreach (LocalBinding lb in scope.Locals)
  349. {
  350. symWriter.DefineLocalVariable2(
  351. lb.Name,
  352. 0,
  353. #if SIMPLEWRITER
  354. lb.Token.GetToken(),
  355. #else
  356. lb.Token,
  357. #endif
  358. 1,
  359. lb.Index,
  360. 0,
  361. 0,
  362. lb.OffsetStart,
  363. lb.OffsetEnd
  364. );
  365. }
  366. // Add each constants
  367. /* For now don't add constants. Doesn't work. AKB 09-01-2007
  368. foreach (ConstantBinding cb in scope.Constants) {
  369. symWriter.DefineConstant(
  370. cb.Name,
  371. cb.Value,
  372. cb.GetSig()
  373. );
  374. }
  375. */
  376. // Add any child scopes
  377. foreach (Scope childScope in scope.ChildScopes)
  378. WriteScopeAndLocals(symWriter, childScope);
  379. // Close the scope
  380. symWriter.CloseScope(scope.OffsetEnd);
  381. }
  382. /// <summary>
  383. /// A list of sequence points.
  384. /// </summary>
  385. private class SequencePointList
  386. {
  387. internal ArrayList offsets = new ArrayList();
  388. internal ArrayList lines = new ArrayList();
  389. internal ArrayList cols = new ArrayList();
  390. internal ArrayList endLines = new ArrayList();
  391. internal ArrayList endCols = new ArrayList();
  392. }
  393. /// <summary>
  394. /// A source file document.
  395. /// </summary>
  396. private class Document
  397. {
  398. internal string _file;
  399. internal Guid _docLanguage, _langVendor, _docType;
  400. #if SIMPLEWRITER
  401. internal ulong _docWriter;
  402. #else
  403. internal object docWriter;
  404. #endif
  405. }
  406. /// <summary>
  407. /// A method.
  408. /// </summary>
  409. private class Method
  410. {
  411. internal SymbolToken Token;
  412. internal Scope Scope = null;
  413. internal Hashtable SequencePointList = new Hashtable();
  414. }
  415. /// <summary>
  416. /// A scope.
  417. /// </summary>
  418. private class Scope
  419. {
  420. internal int OffsetStart;
  421. internal int OffsetEnd;
  422. internal Scope ParentScope = null;
  423. internal ArrayList Locals = new ArrayList();
  424. internal ArrayList Constants = new ArrayList();
  425. internal ArrayList ChildScopes = new ArrayList();
  426. }
  427. /// <summary>
  428. /// A local binding.
  429. /// </summary>
  430. private class LocalBinding
  431. {
  432. internal string Name;
  433. internal int Index;
  434. internal SymbolToken Token;
  435. internal int OffsetStart;
  436. internal int OffsetEnd;
  437. }
  438. }
  439. /// <summary>
  440. /// Read a given PDB file.
  441. /// </summary>
  442. public class PDBReader
  443. {
  444. //private static Guid IID_IMetaDataImport = new Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44");
  445. //private static Guid CLSID_CorSymBinder = new Guid("AA544D41-28CB-11d3-BD22-0000F80849BD");
  446. private ISymbolReader _reader;
  447. private string _fileName;
  448. /// <summary>
  449. /// Read the given PDB file by filename.
  450. /// </summary>
  451. /// <param name="fileName">The filename and path to the PDB file.</param>
  452. public PDBReader(string fileName)
  453. {
  454. _reader = (ISymbolReader)(new QSy.SymbolReader(fileName));
  455. _fileName = fileName;
  456. }
  457. /// <summary>
  458. /// Return a particular method.
  459. /// </summary>
  460. /// <param name="token">The token to identify the method.</param>
  461. /// <returns>The method with the given token.</returns>
  462. public PDBMethod GetMethod(int token)
  463. {
  464. try
  465. {
  466. ISymbolMethod method = _reader.GetMethod(new SymbolToken(token));
  467. if (method != null)
  468. return new PDBMethod(method);
  469. else
  470. return null;
  471. }
  472. catch
  473. {
  474. return null; // call fails on tokens which are not referenced
  475. }
  476. }
  477. }
  478. /// <summary>
  479. /// Defines debug information for a method.
  480. /// </summary>
  481. public class PDBMethod
  482. {
  483. private ISymbolMethod _meth;
  484. /// <summary>
  485. /// Create a new PDB method object from an ISymbolMethod object.
  486. /// </summary>
  487. /// <param name="meth">The ISymbolMethod object to wrap.</param>
  488. internal PDBMethod(ISymbolMethod meth)
  489. {
  490. _meth = meth;
  491. }
  492. /// <summary>
  493. /// The root scope of the method.
  494. /// </summary>
  495. public PDBScope Scope
  496. {
  497. get
  498. {
  499. return new PDBScope(_meth.RootScope);
  500. }
  501. }
  502. /// <summary>
  503. /// The sequence points in the method.
  504. /// </summary>
  505. public PDBSequencePoint[] SequencePoints
  506. {
  507. get
  508. {
  509. int spCount = _meth.SequencePointCount;
  510. int[] offsets = new int[spCount];
  511. ISymbolDocument[] documents = new ISymbolDocument[spCount];
  512. int[] lines = new int[spCount];
  513. int[] cols = new int[spCount];
  514. int[] endLines = new int[spCount];
  515. int[] endCols = new int[spCount];
  516. _meth.GetSequencePoints(offsets, documents, lines, cols, endLines, endCols);
  517. PDBSequencePoint[] spList = new PDBSequencePoint[spCount];
  518. for (int i = 0; i < spCount; i++)
  519. spList[i] = new PDBSequencePoint(offsets[i], new PDBDocument(documents[i]), lines[i], cols[i], endLines[i], endCols[i]);
  520. return spList;
  521. }
  522. }
  523. }
  524. /// <summary>
  525. /// Defines a scope in which local variables exist.
  526. /// </summary>
  527. public class PDBScope
  528. {
  529. private ISymbolScope _scope;
  530. /// <summary>
  531. /// Create a new scope from a ISymbolScope
  532. /// </summary>
  533. /// <param name="scope"></param>
  534. internal PDBScope(ISymbolScope scope)
  535. {
  536. _scope = scope;
  537. }
  538. /// <summary>
  539. /// The starting index for the scope.
  540. /// </summary>
  541. public int StartOffset
  542. {
  543. get
  544. {
  545. return _scope.StartOffset;
  546. }
  547. }
  548. /// <summary>
  549. /// The end index for the scope.
  550. /// </summary>
  551. public int EndOffset
  552. {
  553. get
  554. {
  555. return _scope.EndOffset;
  556. }
  557. }
  558. /// <summary>
  559. /// The variables that exist in this scope.
  560. /// </summary>
  561. public PDBVariable[] Variables
  562. {
  563. get
  564. {
  565. ArrayList vars = new ArrayList();
  566. foreach (ISymbolVariable var in _scope.GetLocals())
  567. vars.Add(new PDBVariable(var));
  568. return (PDBVariable[])vars.ToArray(typeof(PDBVariable));
  569. }
  570. }
  571. /// <summary>
  572. /// The sub-scopes within this scope.
  573. /// </summary>
  574. public PDBScope[] Children
  575. {
  576. get
  577. {
  578. ArrayList children = new ArrayList();
  579. foreach (ISymbolScope child in _scope.GetChildren())
  580. children.Add(new PDBScope(child));
  581. return (PDBScope[])children.ToArray(typeof(PDBScope));
  582. }
  583. }
  584. }
  585. /// <summary>
  586. /// Defines a reference to one section of code to be highlighted when
  587. /// stepping through in debug mode. Typically one line of code.
  588. /// </summary>
  589. public class PDBSequencePoint
  590. {
  591. internal PDBDocument _document;
  592. internal int _offset;
  593. internal int _line;
  594. internal int _column;
  595. internal int _endLine;
  596. internal int _endColumn;
  597. /// <summary>
  598. /// Create a new sequence point.
  599. /// </summary>
  600. /// <param name="offset"></param>
  601. /// <param name="doc">The source file.</param>
  602. /// <param name="line">The line the point begins on.</param>
  603. /// <param name="col">The column the point begins with.</param>
  604. /// <param name="endLine">The line the point ends on.</param>
  605. /// <param name="endCol">The column the point ends with.</param>
  606. internal PDBSequencePoint(int offset, PDBDocument doc, int line, int col, int endLine, int endCol)
  607. {
  608. _offset = offset;
  609. _document = doc;
  610. _line = line;
  611. _column = col;
  612. _endLine = endLine;
  613. _endColumn = endCol;
  614. }
  615. /// <summary>
  616. /// The source file for this sequence point.
  617. /// </summary>
  618. public PDBDocument Document
  619. {
  620. get
  621. {
  622. return _document;
  623. }
  624. }
  625. /// <summary>
  626. ///
  627. /// </summary>
  628. public int Offset
  629. {
  630. get
  631. {
  632. return _offset;
  633. }
  634. }
  635. /// <summary>
  636. /// The line this sequence point starts on.
  637. /// </summary>
  638. public int Line
  639. {
  640. get
  641. {
  642. return _line;
  643. }
  644. }
  645. /// <summary>
  646. /// The column this sequnce point starts with.
  647. /// </summary>
  648. public int Column
  649. {
  650. get
  651. {
  652. return _column;
  653. }
  654. }
  655. /// <summary>
  656. /// The line this sequence point ends with.
  657. /// </summary>
  658. public int EndLine
  659. {
  660. get
  661. {
  662. return _endLine;
  663. }
  664. }
  665. /// <summary>
  666. /// The column this sequence point ends with.
  667. /// </summary>
  668. public int EndColumn
  669. {
  670. get
  671. {
  672. return _endColumn;
  673. }
  674. }
  675. }
  676. /// <summary>
  677. /// A PDB variable object. Stores debug information about a variable.
  678. /// </summary>
  679. public class PDBVariable
  680. {
  681. private ISymbolVariable _var;
  682. /// <summary>
  683. /// Create a new PDBVariable object from an ISymbolVariable object.
  684. /// </summary>
  685. /// <param name="var"></param>
  686. internal PDBVariable(ISymbolVariable var)
  687. {
  688. _var = var;
  689. }
  690. /// <summary>
  691. /// The name of the variable.
  692. /// </summary>
  693. public string Name
  694. {
  695. get
  696. {
  697. return _var.Name;
  698. }
  699. }
  700. /// <summary>
  701. /// The address or index of the variable.
  702. /// </summary>
  703. public int Address
  704. {
  705. get
  706. {
  707. return _var.AddressField1;
  708. }
  709. }
  710. }
  711. /// <summary>
  712. /// A PDB document is a source file.
  713. /// </summary>
  714. public class PDBDocument
  715. {
  716. private ISymbolDocument _doc;
  717. /// <summary>
  718. /// Create a new document object from an existing document.
  719. /// </summary>
  720. /// <param name="doc">The ISymbolDocument to wrap.</param>
  721. internal PDBDocument(ISymbolDocument doc)
  722. {
  723. _doc = doc;
  724. }
  725. /// <summary>
  726. /// The language for this document.
  727. /// </summary>
  728. public Guid Language
  729. {
  730. get
  731. {
  732. return _doc.Language; ;
  733. }
  734. }
  735. /// <summary>
  736. /// The language vendor for this document.
  737. /// </summary>
  738. public Guid LanguageVendor
  739. {
  740. get
  741. {
  742. return _doc.LanguageVendor;
  743. }
  744. }
  745. /// <summary>
  746. /// The type for this document.
  747. /// </summary>
  748. public Guid DocumentType
  749. {
  750. get
  751. {
  752. return _doc.DocumentType;
  753. }
  754. }
  755. /// <summary>
  756. /// The path/url to the source file.
  757. /// </summary>
  758. public string URL
  759. {
  760. get
  761. {
  762. return _doc.URL; ;
  763. }
  764. }
  765. }
  766. /**************************************************************************/
  767. // Added to enable PDB reading
  768. internal class MergeBuffer
  769. {
  770. private CILInstruction[] _buffer;
  771. private ArrayList _debugBuffer;
  772. private int _current;
  773. public MergeBuffer(CILInstruction[] buffer)
  774. {
  775. _debugBuffer = new ArrayList();
  776. _buffer = buffer;
  777. }
  778. public void Add(CILInstruction inst, uint offset)
  779. {
  780. while (_current < _buffer.Length && _buffer[_current].offset < offset)
  781. _debugBuffer.Add(_buffer[_current++]);
  782. if (_debugBuffer.Count > 0 && offset >= ((CILInstruction)_debugBuffer[_debugBuffer.Count - 1]).offset)
  783. {
  784. inst.offset = offset;
  785. _debugBuffer.Add(inst);
  786. }
  787. else
  788. {
  789. int i;
  790. for (i = 0; i < _debugBuffer.Count; i++)
  791. if (((CILInstruction)_debugBuffer[i]).offset > offset)
  792. break;
  793. inst.offset = offset;
  794. _debugBuffer.Insert((i > 0 ? i - 1 : i), inst);
  795. }
  796. }
  797. /// <summary>
  798. /// Tests if Instructions begin and end with an OpenScope/CloseScope pair
  799. /// </summary>
  800. /// <returns>True if there is a root scope</returns>
  801. public bool hasRootScope()
  802. {
  803. return (_debugBuffer.Count > 0 && _debugBuffer[0] is OpenScope);
  804. }
  805. public CILInstruction[] Instructions
  806. {
  807. get
  808. {
  809. while (_current < _buffer.Length)
  810. _debugBuffer.Add(_buffer[_current++]);
  811. return (CILInstruction[])_debugBuffer.ToArray(typeof(CILInstruction));
  812. }
  813. }
  814. }
  815. #endregion
  816. /**************************************************************************/
  817. }