nim-libbacktrace/libbacktrace.nim

134 lines
4.4 KiB
Nim
Raw Normal View History

# Copyright (c) 2019-2024 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.
when not compileOption("debuginfo"):
stderr.write("libbacktrace error: no debugging symbols available. Compile with '--debugger:native'.\n")
stderr.flushFile()
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 std/algorithm, libbacktrace/wrapper, std/os, system/ansi_c, std/strutils
2019-12-15 23:21:43 +00:00
2022-03-22 15:04:03 +00:00
const
topLevelPath = currentSourcePath.parentDir().replace('\\', '/')
installPath = topLevelPath & "/install/usr"
{.passc: "-I" & escape(topLevelPath).}
2019-12-15 23:21:43 +00:00
when defined(cpp):
{.passl: escape(installPath & "/lib/libbacktracenimcpp.a").}
else:
{.passl: escape(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" & escape(installPath & "/include").}
{.passl: escape(installPath & "/lib/libbacktrace.a").}
when defined(macosx) or defined(windows):
{.passl: escape(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(libbacktrace.getBacktrace)
proc getProgramCounters*(maxLength: cint): seq[cuintptr_t] {.noinline.} =
var
length {.noinit.}: cint
pcPtr = get_program_counters_c(maxLength, addr length, skip = 2)
iPtr = pcPtr
result = newSeqOfCap[cuintptr_t](length)
for i in 0 ..< length:
if iPtr[] == 0:
break
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(libbacktrace.getProgramCounters)
proc getDebuggingInfo*(
programCounters: seq[cuintptr_t],
maxLength: cint): seq[StackTraceEntry] {.noinline.} =
doAssert programCounters.len <= cint.high
if programCounters.len == 0:
return @[]
var
length {.noinit.}: cint
functionInfoPtr = get_debugging_info_c( # Nim 1.6 needs `unsafeAddr`
unsafeAddr programCounters[0], programCounters.len.cint,
maxLength, addr length)
iPtr = functionInfoPtr
res: StackTraceEntry
result = newSeqOfCap[StackTraceEntry](length.int)
for i in 0 ..< length:
if iPtr[].filename == nil:
break
# 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
result.add(res)
c_free(iPtr[].filename)
c_free(iPtr[].function)
iPtr = cast[ptr DebuggingInfo](
cast[uint](iPtr) + sizeof(DebuggingInfo).uint)
c_free(functionInfoPtr)
# Nim convention.
reverse(result)
when defined(nimStackTraceOverride) and declared(registerStackTraceOverrideGetDebuggingInfo):
registerStackTraceOverrideGetDebuggingInfo(libbacktrace.getDebuggingInfo)