Created
April 23, 2014 08:02
-
-
Save gagern/11206319 to your computer and use it in GitHub Desktop.
Print ECL data structures in GDB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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