import gdb
import os
import subprocess
import tempfile
import time
import mozilla.prettyprinters
from mozilla.prettyprinters import pretty_printer
mozilla.prettyprinters.clear_module_printers(__name__)
class jsvmPrinterCache(object):
def __init__(self):
self.d = None
def __getattr__(self, name):
if self.d is None:
self.initialize()
return self.d[name]
def initialize(self):
self.d = {}
self.d['char'] = gdb.lookup_type('char')
class ModuleCache(object):
def __init__(self):
self.mod_IonGraph = None
@pretty_printer("js::vm::LSprinter")
class jsvmLSprinter(object):
def __init__(self, value, cache):
self.value = value
if not cache.mod_IonGraph:
cache.mod_IonGraph = jsvmPrinterCache()
self.cache = cache.mod_IonGraph
def to_string(self):
next = self.value['head_']
tail = self.value['tail_']
if next == 0:
return ""
res = ""
while next != tail:
chars = (next + 1).cast(self.cache.char.pointer())
res = res + chars.string('ascii', 'ignore', next['length'])
next = next['next']
length = next['length'] - self.value['unused_']
chars = (next + 1).cast(self.cache.char.pointer())
res = res + chars.string('ascii', 'ignore', length)
return res
def search_in_path(bin):
paths = os.getenv("PATH", "")
if paths == "":
return ""
for d in paths.split(":"):
f = os.path.join(d, bin)
if os.access(f, os.X_OK):
return f
return ""
class IonGraphBinParameter(gdb.Parameter):
set_doc = "Set the path to iongraph binary, used by iongraph command."
show_doc = "Show the path to iongraph binary, used by iongraph command."
def get_set_string(self):
return "Path to iongraph binary changed to: %s" % self.value
def get_show_string(self, value):
return "Path to iongraph binary set to: %s" % value
def __init__(self):
super(IonGraphBinParameter, self).__init__(
"iongraph-bin", gdb.COMMAND_SUPPORT, gdb.PARAM_FILENAME)
self.value = os.getenv("GDB_IONGRAPH", "")
if self.value == "":
self.value = search_in_path("iongraph")
class DotBinParameter(gdb.Parameter):
set_doc = "Set the path to dot binary, used by iongraph command."
show_doc = "Show the path to dot binary, used by iongraph command."
def get_set_string(self):
return "Path to dot binary changed to: %s" % self.value
def get_show_string(self, value):
return "Path to dot binary set to: %s" % value
def __init__(self):
super(DotBinParameter, self).__init__("dot-bin", gdb.COMMAND_SUPPORT, gdb.PARAM_FILENAME)
self.value = os.getenv("GDB_DOT", "")
if self.value == "":
self.value = search_in_path("dot")
class PngViewerBinParameter(gdb.Parameter):
set_doc = "Set the path to a png viewer binary, used by iongraph command."
show_doc = "Show the path to a png viewer binary, used by iongraph command."
def get_set_string(self):
return "Path to a png viewer binary changed to: %s" % self.value
def get_show_string(self):
return "Path to a png viewer binary set to: %s" % self.value
def __init__(self):
super(PngViewerBinParameter, self).__init__(
"pngviewer-bin", gdb.COMMAND_SUPPORT, gdb.PARAM_FILENAME)
self.value = os.getenv("GDB_PNGVIEWER", "")
if self.value == "":
self.value = search_in_path("xdg-open")
iongraph = IonGraphBinParameter()
dot = DotBinParameter()
pngviewer = PngViewerBinParameter()
class IonGraphCommand(gdb.Command):
def __init__(self):
super(IonGraphCommand, self).__init__(
"iongraph", gdb.COMMAND_DATA, gdb.COMPLETE_EXPRESSION)
self.typeCache = ModuleCache()
def invoke(self, mirGenExpr, from_tty):
mirGen = gdb.parse_and_eval(mirGenExpr)
jsonPrinter = mirGen['gs_']['jsonPrinter_']
jsonSpewer = mirGen['gs_']['jsonSpewer_']
graph = mirGen['graph_']
gdb.parse_and_eval('(*(%s*)(%s)).clear()' % (jsonPrinter.type, jsonPrinter.address,))
gdb.parse_and_eval('(*(%s*)(%s)).beginFunction((JSScript*)0)' %
(jsonSpewer.type, jsonSpewer.address,))
gdb.parse_and_eval('(*(%s*)(%s)).beginPass("gdb")' %
(jsonSpewer.type, jsonSpewer.address,))
gdb.parse_and_eval('(*(%s*)(%s)).spewMIR((%s)%s)' %
(jsonSpewer.type, jsonSpewer.address, graph.type, graph,))
gdb.parse_and_eval('(*(%s*)(%s)).spewLIR((%s)%s)' %
(jsonSpewer.type, jsonSpewer.address, graph.type, graph,))
gdb.parse_and_eval('(*(%s*)(%s)).endPass()' % (jsonSpewer.type, jsonSpewer.address,))
gdb.parse_and_eval('(*(%s*)(%s)).endFunction()' % (jsonSpewer.type, jsonSpewer.address,))
json = jsvmLSprinter(jsonPrinter, self.typeCache).to_string()
if json[0] == ",":
json = json[1:]
json = '{ "functions": [%s] }' % json
self.displayMIRGraph(json)
def displayMIRGraph(self, jsonStr):
png = tempfile.NamedTemporaryFile()
i = subprocess.Popen([iongraph.value, '--funcnum', '0', '--passnum', '0',
'--out-mir', '-', '-'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
d = subprocess.Popen([dot.value, '-Tpng'], stdin=i.stdout, stdout=png)
i.stdin.write(jsonStr.encode('utf8'))
i.stdin.close()
i.stdout.close()
i.wait()
d.communicate()[0]
subprocess.Popen([pngviewer.value, png.name], stdin=None, stdout=None)
time.sleep(1)
iongraph_cmd = IonGraphCommand()