diff options
Diffstat (limited to 'tools/heapdumprepl.nim')
-rw-r--r-- | tools/heapdumprepl.nim | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/tools/heapdumprepl.nim b/tools/heapdumprepl.nim new file mode 100644 index 000000000..4f06cf111 --- /dev/null +++ b/tools/heapdumprepl.nim @@ -0,0 +1,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" |