stacktraces.nim 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Additional code for customizable stack traces. Unstable API, for internal
  10. # usage only.
  11. const
  12. reraisedFromBegin* = -10
  13. reraisedFromEnd* = -100
  14. maxStackTraceLines* = 128
  15. when defined(nimStackTraceOverride):
  16. ## Procedure types for overriding the default stack trace.
  17. type
  18. cuintptr_t* {.importc: "uintptr_t", nodecl.} = uint
  19. ## This is the same as the type `uintptr_t` in C.
  20. StackTraceOverrideGetTracebackProc* = proc (): string {.
  21. nimcall, gcsafe, raises: [], tags: [], noinline.}
  22. StackTraceOverrideGetProgramCountersProc* = proc (maxLength: cint): seq[cuintptr_t] {.
  23. nimcall, gcsafe, raises: [], tags: [], noinline.}
  24. StackTraceOverrideGetDebuggingInfoProc* =
  25. proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
  26. nimcall, gcsafe, raises: [], tags: [], noinline.}
  27. # Default procedures (not normally used, because people opting in on this
  28. # override are supposed to register their own versions).
  29. var
  30. stackTraceOverrideGetTraceback: StackTraceOverrideGetTracebackProc =
  31. proc (): string {.nimcall, gcsafe, raises: [], tags: [], noinline.} =
  32. discard
  33. #result = "Stack trace override procedure not registered.\n"
  34. stackTraceOverrideGetProgramCounters: StackTraceOverrideGetProgramCountersProc =
  35. proc (maxLength: cint): seq[cuintptr_t] {.nimcall, gcsafe, raises: [], tags: [], noinline.} =
  36. discard
  37. stackTraceOverrideGetDebuggingInfo: StackTraceOverrideGetDebuggingInfoProc =
  38. proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
  39. nimcall, gcsafe, raises: [], tags: [], noinline.} =
  40. discard
  41. # Custom procedure registration.
  42. proc registerStackTraceOverride*(overrideProc: StackTraceOverrideGetTracebackProc) =
  43. ## Override the default stack trace inside rawWriteStackTrace() with your
  44. ## own procedure.
  45. stackTraceOverrideGetTraceback = overrideProc
  46. proc registerStackTraceOverrideGetProgramCounters*(overrideProc: StackTraceOverrideGetProgramCountersProc) =
  47. stackTraceOverrideGetProgramCounters = overrideProc
  48. proc registerStackTraceOverrideGetDebuggingInfo*(overrideProc: StackTraceOverrideGetDebuggingInfoProc) =
  49. stackTraceOverrideGetDebuggingInfo = overrideProc
  50. # Custom stack trace manipulation.
  51. proc auxWriteStackTraceWithOverride*(s: var string) =
  52. add(s, stackTraceOverrideGetTraceback())
  53. proc auxWriteStackTraceWithOverride*(s: var seq[StackTraceEntry]) =
  54. let programCounters = stackTraceOverrideGetProgramCounters(maxStackTraceLines)
  55. if s.len == 0:
  56. s = newSeqOfCap[StackTraceEntry](programCounters.len)
  57. for programCounter in programCounters:
  58. s.add(StackTraceEntry(programCounter: cast[uint](programCounter)))
  59. # We may have more stack trace lines in the output, due to inlined procedures.
  60. proc addDebuggingInfo*(s: seq[StackTraceEntry]): seq[StackTraceEntry] =
  61. var programCounters: seq[cuintptr_t]
  62. # We process program counters in groups from complete stack traces, because
  63. # we have logic that keeps track of certain functions being inlined or not.
  64. for entry in s:
  65. if entry.procname.isNil and entry.programCounter != 0:
  66. programCounters.add(cast[cuintptr_t](entry.programCounter))
  67. elif entry.procname.isNil and (entry.line == reraisedFromBegin or entry.line == reraisedFromEnd):
  68. result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
  69. programCounters = @[]
  70. result.add(entry)
  71. else:
  72. result.add(entry)
  73. if programCounters.len > 0:
  74. result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))