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"
|