MangleProcs following the Itanium spec so they are demangled in the debugger call stack (#23260)

![image](https://github.com/nim-lang/Nim/assets/1496571/0d796c5b-0bbf-4bb4-8c95-c3e3cce22f15)

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
Juan M Gómez
2024-02-09 12:23:36 +00:00
committed by GitHub
parent c234a2a661
commit a45f43da34
4 changed files with 276 additions and 6 deletions

View File

@@ -55,13 +55,31 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)
proc fillBackendName(m: BModule; s: PSym) =
if s.loc.r == "":
var result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
var result: Rope
if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
if m.hcrOn:
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))

View File

@@ -13,7 +13,7 @@ import
ast, types, msgs, wordrecg,
platform, trees, options, cgendata
import std/[hashes, strutils]
import std/[hashes, strutils, formatFloat]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -153,3 +153,62 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.owner.name.s) & encodeName(name) & "E"
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

View File

@@ -137,6 +137,7 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file

View File

@@ -0,0 +1,192 @@
discard """
targets: "c cpp"
matrix: "--debugger:native"
ccodecheck: "'_ZN14titaniummangle8testFuncE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int7varargsI6stringE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle3BooE'"
ccodecheck: "'_ZN8testFunc8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI14uncheckedArrayI3intEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3setIN14titaniummangle10EnumSampleEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE4procI6string6stringE'"
ccodecheck: "'_ZN8testFunc8testFuncE3intN10Comparable10ComparableE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI3int3intE7cstring'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI5float5floatE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3ptrI3intEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3refIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3varIN14titaniummangle3FooEE5int325int323refIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3varI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9openArrayI6stringE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5arrayI7range013intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE10Container2I5int325int32E'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI10Container2I5int325int32EE'"
"""
#When debugging this notice that if one check fails, it can be due to any of the above.
type
Comparable = concept x, y
(x < y) is bool
type
Foo = object
a: int32
b: int32
FooTuple = tuple
a: int
b: int
Container[T] = object
data: T
Container2[T, T2] = object
data: T
data2: T2
Boo = distinct Foo
Coo = Foo
Doo = Boo | Foo
TestProc = proc(a:string): string
type EnumSample = enum
a, b, c
type EnumAnotherSample = enum
a, b, c
proc testFunc(a: set[EnumSample]) =
echo $a
proc testFunc(a: typedesc) =
echo $a
proc testFunc(a: ptr Foo) =
echo repr a
proc testFunc(s: string, a: Coo) =
echo repr a
proc testFunc(s: int, a: Comparable) =
echo repr a
proc testFunc(a: TestProc) =
let b = ""
echo repr a("")
proc testFunc(a: ref Foo) =
echo repr a
proc testFunc(b: Boo) =
echo repr b
proc testFunc(a: ptr UncheckedArray[int]) =
echo repr a
proc testFunc(a: ptr int) =
echo repr a
proc testFunc(a: ptr ptr int) =
echo repr a
proc testFunc(e: FooTuple, str: cstring) =
echo e
proc testFunc(e: (float, float)) =
echo e
proc testFunc(e: EnumSample) =
echo e
proc testFunc(e: var int) =
echo e
proc testFunc(e: var Foo, a, b: int32, refFoo: ref Foo) =
echo e
proc testFunc(xs: Container[int]) =
let a = 2
echo xs
proc testFunc(xs: Container2[int32, int32]) =
let a = 2
echo xs
proc testFunc(xs: Container[Container2[int32, int32]]) =
let a = 2
echo xs
proc testFunc(xs: seq[int]) =
let a = 2
echo xs
proc testFunc(xs: openArray[string]) =
let a = 2
echo xs
proc testFunc(xs: array[2, int]) =
let a = 2
echo xs
proc testFunc(e: EnumAnotherSample) =
echo e
proc testFunc(a, b: int) =
echo "hola"
discard
proc testFunc(a: int, xs: varargs[string]) =
let a = 10
for x in xs:
echo x
proc testFunc() =
var a = 2
var aPtr = a.addr
var foo = Foo()
let refFoo : ref Foo = new(Foo)
let b = Foo().Boo()
let d: Doo = Foo()
testFunc("", Coo())
testFunc(1, )
testFunc(b)
testFunc(EnumAnotherSample)
var t = [1, 2]
let uArr = cast[ptr UncheckedArray[int]](t.addr)
testFunc(uArr)
testFunc({})
testFunc(proc(s:string): string = "test")
testFunc(20, a.int32)
testFunc(20, 2)
testFunc(EnumSample.c)
testFunc(EnumAnotherSample.c)
testFunc((2, 1), "adios")
testFunc((22.1, 1.2))
testFunc(a.addr)
testFunc(foo.addr)
testFunc(aPtr.addr)
testFunc(refFoo)
testFunc(foo, 2, 1, refFoo)
testFunc(a)
testFunc(@[2, 1, 2])
testFunc(@["hola"])
testFunc(2, "hola", "adios")
let arr: array[2, int] = [2, 1]
testFunc(arr)
testFunc(Container[int](data: 10))
let c2 = Container2[int32, int32](data: 10, data2: 20)
testFunc(c2)
testFunc(Container[Container2[int32, int32]](data: c2))
testFunc()