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