1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
include std/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) =
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 hexadecimal
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
result.nodes = move nodes
result.roots = move roots
if paramCount() == 1:
repl(importData(paramStr(1)))
else:
quit "usage: heapdumprepl inputfile"
|