Skip to content

Instantly share code, notes, and snippets.

@gagern
Created April 23, 2014 08:02
Show Gist options
  • Select an option

  • Save gagern/11206319 to your computer and use it in GitHub Desktop.

Select an option

Save gagern/11206319 to your computer and use it in GitHub Desktop.
Print ECL data structures in GDB
from __future__ import with_statement
import gdb
class EclUtil(object):
def __init__(self, *args, **kwargs):
super(EclUtil, self).__init__(*args, **kwargs)
self.cl_object = gdb.lookup_type("cl_object").strip_typedefs()
self.cl_objectp = self.cl_object.pointer()
self.cl_fixnum = gdb.lookup_type("cl_fixnum")
self.cl_type = gdb.lookup_type("cl_type")
self.charp = gdb.lookup_type("char").pointer()
self.t_list = gdb.lookup_symbol("t_list")[0].value().cast(gdb.lookup_type("int8_t"))
self.nil = self.t_list.cast(self.cl_object)
if not "array" in self.cl_object.target():
raise gdb.GdbError("cl_object does not look as expected")
if "cons" in self.cl_object.target():
raise gdb.GdbError("This code can only handle ECL_SMALL_CONS layout")
def immediate(self, obj):
return (obj.cast(self.cl_fixnum) & 3)
def listp(self, obj):
return self.immediate(obj) == self.t_list
def null(self, obj):
return obj == self.nil
def consp(self, obj):
return self.listp(obj) and not self.null(obj)
def car(self, obj):
return (obj.cast(self.charp) - self.t_list).cast(self.cl_objectp).dereference()
def cdr(self, obj):
return (obj.cast(self.charp) + self.cl_object.sizeof - self.t_list).cast(self.cl_objectp).dereference()
def assert_cl_object(self, obj):
t = obj.type
if t is None:
raise gdb.GdbError("No type information available")
if str(t.strip_typedefs()) != str(self.cl_object):
raise gdb.GdbError("Value does not identify a cl_object")
def assert_cons(self, obj):
self.assert_cl_object(obj)
if not self.consp(obj):
raise gdb.GdbError("Value is not a cons")
return obj
def typeof(self, obj):
return obj.dereference()["d"]["t"].cast(self.cl_type)
def assert_type(self, obj, name):
if self.immediate(obj) != 0:
raise gdb.GdbError("Value at {} is an immediate".format(obj))
if not str(self.typeof(obj)) == str(name):
raise gdb.GdbError("Value at {} is not of type {}".format(obj, name))
return obj
def as_str(self, obj):
t = str(self.typeof(obj))
if t == "t_base_string":
s = obj.dereference()["base_string"]
elif t == "t_string":
s = obj.dereference()["string"]
else:
raise gdb.GdbError("Object of type {} at {} where string was expected".format(t, obj))
b = gdb.selected_inferior().read_memory(s["self"], s["dim"])
return str(b).decode("utf-8")
class eclp(EclUtil, gdb.Command):
def __init__(self):
super(eclp, self).__init__("eclp", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
def invoke(self, argument, from_tty):
sym, is_field = gdb.lookup_symbol(argument)
if sym is None:
raise gdb.GdbError("No such symbol: `{}'".format(argument))
self.assert_cl_object(sym)
self.process(sym.value(gdb.selected_frame()))
def process(self, obj):
self.recurse(obj, "", "", set())
def seen(self, s, seen):
s = str(s)
if s in seen:
return True
seen.add(s)
return False
def pr(self, indent, value, addr):
print("{:55s} ; {}".format(indent + value, addr))
def recurse(self, obj, indent, nextindent, seen):
if self.null(obj):
print(indent + "nil")
return
if self.seen(obj, seen):
self.pr(indent, "<recursive!>", obj)
return
if self.listp(obj):
nid = nextindent + " "
self.recurse(self.car(obj), indent + "( ", nid, seen.copy())
cdr = self.cdr(obj)
while self.consp(cdr):
if self.seen(cdr, seen):
self.pr(nextindent, ". <loop!>", cdr)
break
self.recurse(self.car(cdr), nid, nid, seen.copy())
cdr = self.cdr(cdr)
else:
if not self.null(cdr):
self.recurse(cdr, nextindent + ". ", nid, seen.copy())
self.pr(nextindent, ")", obj);
return
imm = self.immediate(obj)
if imm != 0:
self.pr(indent, "<immediate of type {}>".format(imm.cast(self.cl_type)), obj)
return
t = str(self.typeof(obj))[2:]
d = obj.dereference()
if t in d.type:
d = d[t]
f = getattr(self, "fmt_" + t, None)
if f is not None:
self.pr(indent, f(d), obj)
else:
f = getattr(self, "pr_" + t, None)
if f is not None:
f(d, obj, indent, nextindent)
else:
self.pr(indent, "<object of type {}>".format(t), obj)
def fmt_symbol(self, obj):
p = self.as_str(self.assert_type(obj["hpack"], "t_package")["pack"]["name"])
n = self.as_str(obj["name"])
return "{}::{}".format(p, n)
def fmt_base_string(self, obj):
return repr(str(gdb.selected_inferior().read_memory(obj["self"], obj["dim"])))
def fmt_string(self, obj):
return repr(str(gdb.selected_inferior().read_memory(obj["self"], obj["dim"])).decode("utf-8"))
def fmt_doublefloat(self, obj):
return str(obj["DF"]["DFVAL"])
class eclcar(EclUtil, gdb.Function):
def __init__(self):
super(eclcar, self).__init__("eclcar")
def invoke(self, obj):
return self.car(self.assert_cons(obj))
class eclcdr(EclUtil, gdb.Function):
def __init__(self):
super(eclcdr, self).__init__("eclcdr")
def invoke(self, obj):
return self.cdr(self.assert_cons(obj))
eclp()
eclcar()
eclcdr()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment