StackFrame.cs 13 KB

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