StackFrame.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. //
  2. // System.Diagnostics.StackFrame.cs
  3. //
  4. // Author:
  5. // Alexander Klyubin ([email protected])
  6. //
  7. // (C) 2001
  8. //
  9. using System;
  10. using System.Reflection;
  11. namespace System.Diagnostics {
  12. /// <summary>
  13. /// Stack frame.
  14. /// TODO: more information.
  15. /// </summary>
  16. public class StackFrame {
  17. /// <value>
  18. /// Constant returned when the native or IL offset is unknown.
  19. /// </value>
  20. public const int OFFSET_UNKNOWN = -1;
  21. /// <value>
  22. /// Offset from the start of the IL code for the method
  23. /// being executed.
  24. /// </value>
  25. private int ilOffset = OFFSET_UNKNOWN;
  26. /// <value>
  27. /// Method associated with this stack frame.
  28. /// </value>
  29. private MethodBase methodBase;
  30. /// <value>
  31. /// File name.
  32. /// </value>
  33. private string fileName;
  34. /// <value>
  35. /// Line number.
  36. /// </value>
  37. private int lineNumber;
  38. /// <value>
  39. /// Column number.
  40. /// </value>
  41. private int columnNumber;
  42. /// <summary>
  43. /// Initializes a new StackFrame object corresponding to the
  44. /// active stack frame.
  45. /// </summary>
  46. public StackFrame() {
  47. throw new NotImplementedException();
  48. }
  49. /// <summary>
  50. /// Initializes a new StackFrame object corresponding to the
  51. /// active stack frame.
  52. /// </summary>
  53. /// <param name="needFileInfo">
  54. /// TODO:
  55. /// </param>
  56. public StackFrame(bool needFileInfo) : this() {
  57. if (needFileInfo) {
  58. PopulateFileInfo();
  59. }
  60. }
  61. /// <summary>
  62. /// Initializes a new StackFrame object corresponding to the
  63. /// active stack frame.
  64. /// </summary>
  65. /// <param name="skipFrames">
  66. /// The number of frames up the stack to skip.
  67. /// </param>
  68. public StackFrame(int skipFrames) {
  69. throw new NotImplementedException();
  70. }
  71. /// <summary>
  72. /// Initializes a new StackFrame object corresponding to the
  73. /// active stack frame.
  74. /// </summary>
  75. /// <param name="skipFrames">
  76. /// The number of frames up the stack to skip.
  77. /// </param>
  78. /// <param name="needFileInfo">
  79. /// TODO:
  80. /// </param>
  81. public StackFrame(int skipFrames, bool needFileInfo)
  82. : this(skipFrames) {
  83. if (needFileInfo) {
  84. PopulateFileInfo();
  85. }
  86. }
  87. /// <summary>
  88. /// Constructs a fake stack frame that just contains the
  89. /// given file name and line number. Use this constructor
  90. /// when you do not want to use the debugger's line mapping
  91. /// logic.
  92. /// </summary>
  93. /// <param name="fileName">
  94. /// The given file name.
  95. /// </param>
  96. /// <param name="lineNumber">
  97. /// The line number in the specified file.
  98. /// </param>
  99. public StackFrame(string fileName, int lineNumber)
  100. : this (fileName, lineNumber, 0) {}
  101. /// <summary>
  102. /// Constructs a fake stack frame that just contains the
  103. /// given file name and line number. Use this constructor
  104. /// when you do not want to use the debugger's line mapping
  105. /// logic.
  106. /// </summary>
  107. /// <param name="fileName">
  108. /// The given file name.
  109. /// </param>
  110. /// <param name="lineNumber">
  111. /// The line number in the specified file.
  112. /// </param>
  113. /// <param name="colNumber">
  114. /// The column number in the specified file.
  115. /// </param>
  116. public StackFrame(string fileName,
  117. int lineNumber,
  118. int colNumber) {
  119. this.methodBase = null;
  120. this.fileName = fileName;
  121. this.lineNumber = lineNumber;
  122. this.columnNumber = colNumber;
  123. }
  124. /// <summary>
  125. /// Gets the line number in the file containing the code
  126. /// being executed. This information is typically extracted
  127. /// from the debugging symbols for the executable.
  128. /// </summary>
  129. /// <returns>
  130. /// The file line number or zero if it cannot be determined.
  131. /// </returns>
  132. public virtual int GetFileLineNumber()
  133. {
  134. return lineNumber;
  135. }
  136. /// <summary>
  137. /// Gets the column number in the file containing the code
  138. /// being executed. This information is typically extracted
  139. /// from the debugging symbols for the executable.
  140. /// </summary>
  141. /// <returns>
  142. /// The file column number or zero if it cannot be determined.
  143. /// </returns>
  144. public virtual int GetFileColumnNumber()
  145. {
  146. return columnNumber;
  147. }
  148. /// <summary>
  149. /// Gets the file name containing the code being executed.
  150. /// This information is typically extracted from the
  151. /// debugging symbols for the executable.
  152. /// </summary>
  153. /// <returns>
  154. /// The file name or null if it cannot be determined.
  155. /// </returns>
  156. public virtual string GetFileName()
  157. {
  158. return fileName;
  159. }
  160. /// <summary>
  161. /// Gets the offset from the start of the IL code for the
  162. /// method being executed. This offset may be approximate
  163. /// depending on whether the JIT compiler is generating
  164. /// debugging code or not.
  165. /// </summary>
  166. /// <returns>
  167. /// The offset from the start of the IL code for the method
  168. /// being executed.
  169. /// </returns>
  170. public virtual int GetILOffset()
  171. {
  172. return ilOffset;
  173. }
  174. /// <summary>
  175. /// Gets the method in which the frame is executing.
  176. /// </summary>
  177. /// <returns>
  178. /// The method the frame is executing in.
  179. /// </returns>
  180. public virtual MethodBase GetMethod()
  181. {
  182. return methodBase;
  183. }
  184. /// <summary>
  185. /// Gets the offset from the start of the native
  186. /// (JIT-compiled) code for the method being executed.
  187. /// </summary>
  188. /// <returns>
  189. /// The offset from the start of the native (JIT-compiled)
  190. /// code or the method being executed.
  191. /// </returns>
  192. public virtual int GetNativeOffset()
  193. {
  194. throw new NotImplementedException();
  195. }
  196. /// <summary>
  197. /// Builds a readable representation of the stack frame.
  198. /// </summary>
  199. /// <returns>
  200. /// A readable representation of the stack frame.
  201. /// </returns>
  202. public override string ToString() {
  203. string methodNameString =
  204. (GetMethod() == null)
  205. ? "<unknown method>"
  206. : GetMethod().Name;
  207. string offsetString =
  208. (GetILOffset() == OFFSET_UNKNOWN)
  209. ? "<unknown offset>"
  210. : "offset " + GetILOffset();
  211. string fileNameString =
  212. (GetFileName() == null)
  213. ? "<filename unknown>" : GetFileName();
  214. return methodNameString + " at " + offsetString
  215. + " in file:line:column " + fileNameString
  216. + ":" + GetFileLineNumber()
  217. + ":" + GetFileColumnNumber();
  218. }
  219. public override bool Equals(Object obj) {
  220. if ((obj == null) || (!(obj is StackFrame))) {
  221. return false;
  222. }
  223. StackFrame rhs = (StackFrame) obj;
  224. if (!ObjectsEqual(GetMethod(), rhs.GetMethod())) {
  225. return false;
  226. }
  227. if (!ObjectsEqual(GetFileName(), rhs.GetFileName())) {
  228. return false;
  229. }
  230. if (GetFileLineNumber() != rhs.GetFileLineNumber()) {
  231. return false;
  232. }
  233. if (GetFileColumnNumber() != rhs.GetFileColumnNumber()) {
  234. return false;
  235. }
  236. if (GetILOffset() != rhs.GetILOffset()) {
  237. return false;
  238. }
  239. if (GetNativeOffset() != rhs.GetNativeOffset()) {
  240. return false;
  241. }
  242. return true;
  243. }
  244. public override int GetHashCode() {
  245. return GetFileLineNumber();
  246. }
  247. /// <summary>
  248. /// Checks whether two objects are equal.
  249. /// The objects are assumed equal if and only if either
  250. /// both of the references are <code>null</code> or they
  251. /// equal via <code>Equals</code> method.
  252. /// </summary>
  253. /// <param name="obj1">
  254. /// First object.
  255. /// </param>
  256. /// <param name="obj2">
  257. /// Second object.
  258. /// </param>
  259. /// <returns>
  260. /// <code>true</code> if the two objects are equal,
  261. /// </code>false</code> otherwise.
  262. /// </returns>
  263. private static bool ObjectsEqual(Object obj1, Object obj2) {
  264. if (obj1 == null) {
  265. return (obj2 == null);
  266. } else {
  267. return obj1.Equals(obj2);
  268. }
  269. }
  270. /// <summary>
  271. /// Populates file information for this frame.
  272. /// </summary>
  273. private void PopulateFileInfo() {
  274. // TODO: Populate this.fileName, this.lineNumber and
  275. // this.columnNumber
  276. throw new NotImplementedException();
  277. }
  278. }
  279. }