nim-libbacktrace/libbacktrace.nim

116 lines
3.8 KiB
Nim
Raw Normal View History

# Copyright (c) 2019-2020 Status Research & Development GmbH
2019-12-15 23:21:43 +00:00
# Licensed under either of
# * Apache License, version 2.0,
# * MIT license
2019-12-15 23:21:43 +00:00
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
2020-09-23 10:19:32 +00:00
when defined(nimStackTraceOverride) and defined(nimHasStacktracesModule):
import system/stacktraces
2019-12-15 23:21:43 +00:00
# Don't warn that this module is unused (e.g.: when the Nim compiler supports it
# and users need to import it, even if they don't call getBacktrace() manually).
{.used.}
# There is no "copyMem()" in Nimscript, so "getBacktrace()" will not work in
# there, but we might still want to import this module with a global
# "--import:libbacktrace" Nim compiler flag.
when not (defined(nimscript) or defined(js)):
import algorithm, libbacktrace_wrapper, os, system/ansi_c
2019-12-15 23:21:43 +00:00
const installPath = currentSourcePath.parentDir() / "install" / "usr"
{.passc: "-I" & currentSourcePath.parentDir().}
2019-12-15 23:21:43 +00:00
when defined(cpp):
{.passl: installPath / "lib" / "libbacktracenimcpp.a".}
else:
{.passl: installPath / "lib" / "libbacktracenim.a".}
2019-12-15 23:21:43 +00:00
when defined(libbacktraceUseSystemLibs):
{.passl: "-lbacktrace".}
when defined(macosx) or defined(windows):
{.passl: "-lunwind".}
else:
{.passc: "-I" & installPath / "include".}
{.passl: installPath / "lib" / "libbacktrace.a".}
when defined(macosx) or defined(windows):
{.passl: installPath / "lib" / "libunwind.a".}
2019-12-15 23:21:43 +00:00
when defined(windows):
{.passl: "-lpsapi".}
2019-12-15 23:21:43 +00:00
proc getBacktrace*(): string {.noinline.} =
let
# bt: cstring = get_backtrace_c()
bt: cstring = get_backtrace_max_length_c(max_length = 128, skip = 3)
btLen = len(bt)
result = newString(btLen)
if btLen > 0:
copyMem(addr(result[0]), bt, btLen)
c_free(bt)
when defined(nimStackTraceOverride) and declared(registerStackTraceOverride):
registerStackTraceOverride(getBacktrace)
proc getProgramCounters*(maxLength: cint): seq[cuintptr_t] {.noinline.} =
result = newSeqOfCap[cuintptr_t](maxLength)
var
pcPtr = get_program_counters_c(max_length = maxLength, skip = 2)
iPtr = pcPtr
while iPtr[] != 0:
result.add(iPtr[])
iPtr = cast[ptr cuintptr_t](cast[uint](iPtr) + sizeof(cuintptr_t).uint)
c_free(pcPtr)
when defined(nimStackTraceOverride) and declared(registerStackTraceOverrideGetProgramCounters):
registerStackTraceOverrideGetProgramCounters(getProgramCounters)
proc getDebuggingInfo*(programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.noinline.} =
result = newSeqOfCap[StackTraceEntry](maxLength)
if programCounters.len == 0:
return
var
functionInfoPtr = get_debugging_info_c(unsafeAddr programCounters[0], maxLength)
iPtr = functionInfoPtr
res: StackTraceEntry
while iPtr[].filename != nil:
# Older stdlib doesn't have this field in "StackTraceEntry".
when compiles(res.filenameStr):
let filenameLen = len(iPtr[].filename)
res.filenameStr = newString(filenameLen)
if filenameLen > 0:
copyMem(addr(res.filenameStr[0]), iPtr[].filename, filenameLen)
res.filename = res.filenameStr
res.line = iPtr[].lineno
when compiles(res.procnameStr):
let functionLen = len(iPtr[].function)
res.procnameStr = newString(functionLen)
if functionLen > 0:
copyMem(addr(res.procnameStr[0]), iPtr[].function, functionLen)
res.procname = res.procnameStr
c_free(iPtr[].filename)
c_free(iPtr[].function)
iPtr = cast[ptr DebuggingInfo](cast[uint](iPtr) + sizeof(DebuggingInfo).uint)
result.add(res)
c_free(functionInfoPtr)
# Nim convention.
reverse(result)
when defined(nimStackTraceOverride) and declared(registerStackTraceOverrideGetDebuggingInfo):
registerStackTraceOverrideGetDebuggingInfo(getDebuggingInfo)