mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
cleaned up heapdumprepl tool
This commit is contained in:
150
tools/heapdumprepl.nim
Normal file
150
tools/heapdumprepl.nim
Normal file
@@ -0,0 +1,150 @@
|
||||
|
||||
include prelude
|
||||
import intsets
|
||||
|
||||
type
|
||||
NodeKind = enum
|
||||
internal, local, localInvalid, global, globalInvalid
|
||||
Color = enum
|
||||
white, grey, black
|
||||
Node = ref object
|
||||
id, rc: int
|
||||
kids: seq[int]
|
||||
k: NodeKind
|
||||
col: Color
|
||||
Graph = object
|
||||
nodes: Table[int, Node]
|
||||
roots: Table[int, NodeKind]
|
||||
|
||||
proc add(father: Node; son: int) =
|
||||
if father.kids.isNil: father.kids = @[]
|
||||
father.kids.add(son)
|
||||
|
||||
proc renderNode(g: Graph; id: int) =
|
||||
let n = g.nodes[id]
|
||||
echo n[]
|
||||
|
||||
proc toNodeId(aliases: var Table[string,int]; s: string): int =
|
||||
result = aliases.getOrDefault(s)
|
||||
if result == 0:
|
||||
if s.startsWith("x"):
|
||||
discard s.parseHex(result, 1)
|
||||
else:
|
||||
result = s.parseInt
|
||||
|
||||
proc parseHex(s: string): int =
|
||||
discard parseutils.parseHex(s, result, 0)
|
||||
|
||||
proc reachable(g: Graph; stack: var seq[int]; goal: int): bool =
|
||||
var t = initIntSet()
|
||||
while stack.len > 0:
|
||||
let it = stack.pop
|
||||
if not t.containsOrIncl(it):
|
||||
if it == goal: return true
|
||||
if it in g.nodes:
|
||||
for kid in g.nodes[it].kids:
|
||||
stack.add(kid)
|
||||
|
||||
const Help = """
|
||||
quit -- quits this REPL
|
||||
locals, l -- output the list of local stack roots
|
||||
globals, g -- output the list of global roots
|
||||
alias name addr -- give addr a name. start 'addr' with 'x' for hexidecimal
|
||||
notation
|
||||
print name|addr -- print a node by name or address
|
||||
reachable,r l|g|node dest -- outputs TRUE or FALSE depending on whether
|
||||
dest is reachable by (l)ocals, (g)lobals or by the
|
||||
other given node. Nodes can be node names or node
|
||||
addresses.
|
||||
"""
|
||||
|
||||
proc repl(g: Graph) =
|
||||
var aliases = initTable[string,int]()
|
||||
while true:
|
||||
let line = stdin.readLine()
|
||||
let data = line.split()
|
||||
if data.len == 0: continue
|
||||
case data[0]
|
||||
of "quit":
|
||||
break
|
||||
of "help":
|
||||
echo Help
|
||||
of "locals", "l":
|
||||
for k,v in g.roots:
|
||||
if v == local: renderNode(g, k)
|
||||
of "globals", "g":
|
||||
for k,v in g.roots:
|
||||
if v == global: renderNode(g, k)
|
||||
of "alias", "a":
|
||||
# generate alias
|
||||
if data.len == 3:
|
||||
aliases[data[1]] = toNodeId(aliases, data[2])
|
||||
of "print", "p":
|
||||
if data.len == 2:
|
||||
renderNode(g, toNodeId(aliases, data[1]))
|
||||
of "reachable", "r":
|
||||
if data.len == 3:
|
||||
var stack: seq[int] = @[]
|
||||
case data[1]
|
||||
of "locals", "l":
|
||||
for k,v in g.roots:
|
||||
if v == local: stack.add k
|
||||
of "globals", "g":
|
||||
for k,v in g.roots:
|
||||
if v == global: stack.add k
|
||||
else:
|
||||
stack.add(toNodeId(aliases, data[1]))
|
||||
let goal = toNodeId(aliases, data[2])
|
||||
echo reachable(g, stack, goal)
|
||||
else: discard
|
||||
|
||||
proc importData(input: string): Graph =
|
||||
#c_fprintf(file, "%s %p %d rc=%ld color=%c\n",
|
||||
# msg, c, kind, c.refcount shr rcShift, col)
|
||||
# cell 0x10a908190 22 rc=2 color=w
|
||||
var i: File
|
||||
var
|
||||
nodes = initTable[int, Node]()
|
||||
roots = initTable[int, NodeKind]()
|
||||
if open(i, input):
|
||||
var currNode: Node
|
||||
for line in lines(i):
|
||||
let data = line.split()
|
||||
if data.len == 0: continue
|
||||
case data[0]
|
||||
of "end":
|
||||
currNode = nil
|
||||
of "cell":
|
||||
let rc = parseInt(data[3].substr("rc=".len))
|
||||
let col = case data[4].substr("color=".len)
|
||||
of "b": black
|
||||
of "w": white
|
||||
of "g": grey
|
||||
else: (assert(false); grey)
|
||||
let id = parseHex(data[1])
|
||||
currNode = Node(id: id,
|
||||
k: roots.getOrDefault(id),
|
||||
rc: rc, col: col)
|
||||
nodes[currNode.id] = currNode
|
||||
of "child":
|
||||
assert currNode != nil
|
||||
currNode.add parseHex(data[1])
|
||||
of "global_root":
|
||||
roots[data[1].parseHex] = global
|
||||
of "global_root_invalid":
|
||||
roots[data[1].parseHex] = globalInvalid
|
||||
of "onstack":
|
||||
roots[data[1].parseHex] = local
|
||||
of "onstack_invalid":
|
||||
roots[data[1].parseHex] = localInvalid
|
||||
else: discard
|
||||
close(i)
|
||||
else:
|
||||
quit "error: cannot open " & input
|
||||
shallowCopy(result.nodes, nodes)
|
||||
shallowCopy(result.roots, roots)
|
||||
|
||||
if paramCount() == 1:
|
||||
repl(importData(paramStr(1)))
|
||||
else:
|
||||
quit "usage: heapdumprepl inputfile"
|
||||
Reference in New Issue
Block a user