StackFrame.jvm.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. #if TARGET_JVM
  50. 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. {
  54. native_offset = 0;
  55. line = 0;
  56. column = 0;
  57. file = "";
  58. iloffset = 0;
  59. method = null;
  60. return false;
  61. }
  62. #else
  63. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  64. extern static bool get_frame_info (int skip, bool needFileInfo, out MethodBase method,
  65. out int iloffset, out int native_offset,
  66. out string file, out int line, out int column);
  67. #endif
  68. /// <summary>
  69. /// Initializes a new StackFrame object corresponding to the
  70. /// active stack frame.
  71. /// </summary>
  72. public StackFrame()
  73. {
  74. get_frame_info (2, false, out methodBase, out ilOffset,
  75. out nativeOffset, out fileName, out lineNumber,
  76. out columnNumber);
  77. }
  78. /// <summary>
  79. /// Initializes a new StackFrame object corresponding to the
  80. /// active stack frame.
  81. /// </summary>
  82. /// <param name="needFileInfo">
  83. /// TODO:
  84. /// </param>
  85. public StackFrame(bool needFileInfo) : this() {
  86. get_frame_info (2, needFileInfo, out methodBase, out ilOffset,
  87. out nativeOffset, out fileName, out lineNumber,
  88. out columnNumber);
  89. }
  90. /// <summary>
  91. /// Initializes a new StackFrame object corresponding to the
  92. /// active stack frame.
  93. /// </summary>
  94. /// <param name="skipFrames">
  95. /// The number of frames up the stack to skip.
  96. /// </param>
  97. public StackFrame(int skipFrames) {
  98. get_frame_info (skipFrames + 2, false, out methodBase, out ilOffset,
  99. out nativeOffset, out fileName, out lineNumber,
  100. out columnNumber);
  101. }
  102. /// <summary>
  103. /// Initializes a new StackFrame object corresponding to the
  104. /// active stack frame.
  105. /// </summary>
  106. /// <param name="skipFrames">
  107. /// The number of frames up the stack to skip.
  108. /// </param>
  109. /// <param name="needFileInfo">
  110. /// TODO:
  111. /// </param>
  112. public StackFrame(int skipFrames, bool needFileInfo) {
  113. get_frame_info (skipFrames + 2, needFileInfo, out methodBase, out ilOffset,
  114. out nativeOffset, out fileName, out lineNumber,
  115. out columnNumber);
  116. }
  117. /// <summary>
  118. /// Constructs a fake stack frame that just contains the
  119. /// given file name and line number. Use this constructor
  120. /// when you do not want to use the debugger's line mapping
  121. /// logic.
  122. /// </summary>
  123. /// <param name="fileName">
  124. /// The given file name.
  125. /// </param>
  126. /// <param name="lineNumber">
  127. /// The line number in the specified file.
  128. /// </param>
  129. // LAMESPEC: According to the MSDN docs, this creates a
  130. // fake stack frame. But MS fills out the frame info as well
  131. public StackFrame(string fileName, int lineNumber) {
  132. get_frame_info (2, false, out methodBase, out ilOffset,
  133. out nativeOffset, out fileName, out lineNumber,
  134. out columnNumber);
  135. this.fileName = fileName;
  136. this.lineNumber = lineNumber;
  137. this.columnNumber = 0;
  138. }
  139. /// <summary>
  140. /// Constructs a fake stack frame that just contains the
  141. /// given file name and line number. Use this constructor
  142. /// when you do not want to use the debugger's line mapping
  143. /// logic.
  144. /// </summary>
  145. /// <param name="fileName">
  146. /// The given file name.
  147. /// </param>
  148. /// <param name="lineNumber">
  149. /// The line number in the specified file.
  150. /// </param>
  151. /// <param name="colNumber">
  152. /// The column number in the specified file.
  153. /// </param>
  154. // LAMESPEC: According to the MSDN docs, this creates a
  155. // fake stack frame. But MS fills out the frame info as well
  156. public StackFrame(string fileName,
  157. int lineNumber,
  158. int colNumber) {
  159. get_frame_info (2, false, out methodBase, out ilOffset,
  160. out nativeOffset, out fileName, out lineNumber,
  161. out columnNumber);
  162. this.fileName = fileName;
  163. this.lineNumber = lineNumber;
  164. this.columnNumber = colNumber;
  165. }
  166. /// <summary>
  167. /// Gets the line number in the file containing the code
  168. /// being executed. This information is typically extracted
  169. /// from the debugging symbols for the executable.
  170. /// </summary>
  171. /// <returns>
  172. /// The file line number or zero if it cannot be determined.
  173. /// </returns>
  174. public virtual int GetFileLineNumber()
  175. {
  176. return lineNumber;
  177. }
  178. /// <summary>
  179. /// Gets the column number in the file containing the code
  180. /// being executed. This information is typically extracted
  181. /// from the debugging symbols for the executable.
  182. /// </summary>
  183. /// <returns>
  184. /// The file column number or zero if it cannot be determined.
  185. /// </returns>
  186. public virtual int GetFileColumnNumber()
  187. {
  188. return columnNumber;
  189. }
  190. /// <summary>
  191. /// Gets the file name containing the code being executed.
  192. /// This information is typically extracted from the
  193. /// debugging symbols for the executable.
  194. /// </summary>
  195. /// <returns>
  196. /// The file name or null if it cannot be determined.
  197. /// </returns>
  198. public virtual string GetFileName()
  199. {
  200. return fileName;
  201. }
  202. /// <summary>
  203. /// Gets the offset from the start of the IL code for the
  204. /// method being executed. This offset may be approximate
  205. /// depending on whether the JIT compiler is generating
  206. /// debugging code or not.
  207. /// </summary>
  208. /// <returns>
  209. /// The offset from the start of the IL code for the method
  210. /// being executed.
  211. /// </returns>
  212. public virtual int GetILOffset()
  213. {
  214. return ilOffset;
  215. }
  216. /// <summary>
  217. /// Gets the method in which the frame is executing.
  218. /// </summary>
  219. /// <returns>
  220. /// The method the frame is executing in.
  221. /// </returns>
  222. public virtual MethodBase GetMethod()
  223. {
  224. return methodBase;
  225. }
  226. /// <summary>
  227. /// Gets the offset from the start of the native
  228. /// (JIT-compiled) code for the method being executed.
  229. /// </summary>
  230. /// <returns>
  231. /// The offset from the start of the native (JIT-compiled)
  232. /// code or the method being executed.
  233. /// </returns>
  234. public virtual int GetNativeOffset()
  235. {
  236. return nativeOffset;
  237. }
  238. /// <summary>
  239. /// Builds a readable representation of the stack frame.
  240. /// </summary>
  241. /// <returns>
  242. /// A readable representation of the stack frame.
  243. /// </returns>
  244. public override string ToString() {
  245. string methodNameString =
  246. (GetMethod() == null)
  247. ? "<unknown method>"
  248. : GetMethod().Name;
  249. string offsetString =
  250. (GetILOffset() == OFFSET_UNKNOWN)
  251. ? "<unknown offset>"
  252. : "offset " + GetILOffset();
  253. string fileNameString =
  254. (GetFileName() == null)
  255. ? "<filename unknown>" : GetFileName();
  256. return methodNameString + " at " + offsetString
  257. + " in file:line:column " + fileNameString
  258. + ":" + GetFileLineNumber()
  259. + ":" + GetFileColumnNumber();
  260. }
  261. public override bool Equals(Object obj) {
  262. if ((obj == null) || (!(obj is StackFrame))) {
  263. return false;
  264. }
  265. StackFrame rhs = (StackFrame) obj;
  266. if (!ObjectsEqual(GetMethod(), rhs.GetMethod())) {
  267. return false;
  268. }
  269. if (!ObjectsEqual(GetFileName(), rhs.GetFileName())) {
  270. return false;
  271. }
  272. if (GetFileLineNumber() != rhs.GetFileLineNumber()) {
  273. return false;
  274. }
  275. if (GetFileColumnNumber() != rhs.GetFileColumnNumber()) {
  276. return false;
  277. }
  278. if (GetILOffset() != rhs.GetILOffset()) {
  279. return false;
  280. }
  281. if (GetNativeOffset() != rhs.GetNativeOffset()) {
  282. return false;
  283. }
  284. return true;
  285. }
  286. public override int GetHashCode() {
  287. return GetFileLineNumber();
  288. }
  289. /// <summary>
  290. /// Checks whether two objects are equal.
  291. /// The objects are assumed equal if and only if either
  292. /// both of the references are <code>null</code> or they
  293. /// equal via <code>Equals</code> method.
  294. /// </summary>
  295. /// <param name="obj1">
  296. /// First object.
  297. /// </param>
  298. /// <param name="obj2">
  299. /// Second object.
  300. /// </param>
  301. /// <returns>
  302. /// <code>true</code> if the two objects are equal,
  303. /// </code>false</code> otherwise.
  304. /// </returns>
  305. private static bool ObjectsEqual(Object obj1, Object obj2) {
  306. if (obj1 == null) {
  307. return (obj2 == null);
  308. } else {
  309. return obj1.Equals(obj2);
  310. }
  311. }
  312. }
  313. }