Commits

Carl Pulley committed 885afb8

Lifted C code into Ocaml.
Merged in libvol code.

Comments (0)

Files changed (9)

 	-L $(BAP)/libtracewrap/libtrace/piqi/piqi/build/lib/ocaml/piqi \
 	-L $(BAP)/libasmir/src \
 	-L $(BAP)/VEX
-PACKS=camlidl,bigarray,str,num,unix,camomile,threads,llvm,llvm.executionengine,llvm.bitwriter
+PACKS=camlidl,bigarray,str,num,unix,camomile,threads,ctypes,ctypes.foreign,llvm,llvm.executionengine,llvm.bitwriter
 
 # Build everything
 all:
-	$(OCAMLFIND) $(OCAMLC) -g -predicates $(PACKS) -package $(PACKS) -linkpkg -thread -output-obj -o bap.o $(INCLUDES) $(SRC) codegen.ml topredicate.ml iltrans.ml bap.ml
+	$(OCAMLFIND) $(OCAMLC) -g -predicates $(PACKS) -package $(PACKS) -linkpkg -thread -output-obj -o bap.o $(INCLUDES) $(SRC) volatility.ml bap_ast.ml bap_cfg.ml bap_ssa.ml codegen.ml topredicate.ml iltrans.ml bap.ml
 
 # Clean up
 clean:
 (* along with this program; if not, write to the Free Software             *)
 (* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *)
 
-let _ = Callback.register "string_of_big_int" Big_int_Z.string_of_big_int
-
-let _ = Callback.register "string_of_exn" Printexc.to_string
-
-type py_cfg
-external node_to_python: Cfg.AST.G.t -> Cfg.AST.G.V.t -> py_cfg -> py_cfg = "node_to_python"
-external edge_to_python: Cfg.AST.G.E.t -> py_cfg -> py_cfg = "edge_to_python"
-
-let _ = Callback.register "fold_nodes" (fun g -> Cfg.AST.G.fold_vertex (node_to_python g) g)
-
-let _ = Callback.register "fold_edges" (Cfg.AST.G.fold_edges_e edge_to_python)
-
-let _ = Callback.register "node_hash" Cfg.AST.G.V.hash
-
-let _ = Callback.register "node_label" Cfg.AST.G.V.label
-
-let _ = Callback.register "node_stmts" Cfg.AST.get_stmts
-
-let _ = Callback.register "edge_source" (fun e -> Cfg.AST.G.V.hash(Cfg.AST.G.E.src e))
-
-let _ = Callback.register "edge_target" (fun e -> Cfg.AST.G.V.hash(Cfg.AST.G.E.dst e))
-
-let _ = Callback.register "edge_label" Cfg.AST.G.E.label
-
-type py_ssa
-external ssa_node_to_python: Cfg.SSA.G.t -> Cfg.SSA.G.V.t -> py_ssa -> py_ssa = "ssa_node_to_python"
-external ssa_edge_to_python: Cfg.SSA.G.E.t -> py_ssa -> py_ssa = "ssa_edge_to_python"
-
-let _ = Callback.register "ssa_fold_nodes" (fun g -> Cfg.SSA.G.fold_vertex (ssa_node_to_python g) g)
-
-let _ = Callback.register "ssa_fold_edges" (Cfg.SSA.G.fold_edges_e ssa_edge_to_python)
-
-let _ = Callback.register "ssa_node_hash" Cfg.SSA.G.V.hash
-
-let _ = Callback.register "ssa_node_label" Cfg.SSA.G.V.label
-
-let _ = Callback.register "ssa_node_stmts" Cfg.SSA.get_stmts
-
-let _ = Callback.register "ssa_edge_source" (fun e -> Cfg.SSA.G.V.hash(Cfg.SSA.G.E.src e))
-
-let _ = Callback.register "ssa_edge_target" (fun e -> Cfg.SSA.G.V.hash(Cfg.SSA.G.E.dst e))
-
-let _ = Callback.register "ssa_edge_label" Cfg.SSA.G.E.label
+open Volatility
 
 let str_to_arch = function
   | "x86" -> Libbfd.Bfd_arch_i386
     else
       apply_cmd remaining_cmds (new_prog_term, model, wp, foralls)
 
+let bap_to_python = function
+  | Iltrans.Ast(ast) ->
+      Bap_ast.to_python(ast)
+  | Iltrans.AstCfg(cfg) ->
+      Bap_cfg.to_python(cfg)
+  | Iltrans.Ssa(ssa) ->
+      Bap_ssa.to_python(ssa)
+
+let model_to_python = function
+  | Some interp ->
+      let maplet_to_python (s, i) = PyTuple [| PyString s; Bap_ast.big_int_to_python i |] in
+        PyList(List.map maplet_to_python interp)
+  | None ->
+      PyNone
+
 let _ = Callback.register "apply_cmd" (fun cmd_opts ast_term -> 
   let filtered_cmds = List.filter (fun cmd -> Array.length cmd >= 2 && cmd.(0) <> "control") cmd_opts in
-  let result = if List.length filtered_cmds = 0 then (Iltrans.Ast ast_term, None, None, None) else exception_wrapper(fun () -> apply_cmd filtered_cmds (Iltrans.Ast ast_term, None, None, None)) in
+  let term, model, wp, foralls = if List.length filtered_cmds = 0 then (Iltrans.Ast ast_term, None, None, None) else exception_wrapper(fun () -> apply_cmd filtered_cmds (Iltrans.Ast ast_term, None, None, None)) in
     flush_all();
-    if List.mem [| "control"; "-return" |] cmd_opts then
-      Some result
-    else
-      None
+    if List.mem [| "control"; "-return" |] cmd_opts then (
+      if BatOption.is_some model then (
+        if BatOption.is_some wp then
+          PyDict [ (PyString "term", bap_to_python term); (PyString "model", model_to_python(BatOption.get model)); (PyString "wp", PyDict [ (PyString "pre", Bap_ast.exp_to_python(BatOption.get wp)); (PyString "foralls", Bap_ast.vars_to_python(BatOption.get foralls)) ]) ]
+        else
+          PyDict [ (PyString "term", bap_to_python term); (PyString "model", model_to_python(BatOption.get model)) ]
+      ) else (
+        if BatOption.is_some wp then
+          PyDict [ (PyString "term", bap_to_python term); (PyString "wp", PyDict [ (PyString "pre", Bap_ast.exp_to_python(BatOption.get wp)); (PyString "foralls", Bap_ast.vars_to_python(BatOption.get foralls)) ]) ]
+        else
+          PyDict [ (PyString "term", bap_to_python term) ]
+      )
+    ) else
+        PyNone
 )
+(* bap_ast.ml                                                              *)
+(* Copyright (C) 2013 Carl Pulley <c.j.pulley@hud.ac.uk>                   *)
+(*                                                                         *)
+(* This program is free software; you can redistribute it and/or modify    *)
+(* it under the terms of the GNU General Public License as published by    *)
+(* the Free Software Foundation; either version 2 of the License, or (at   *)
+(* your option) any later version.                                         *)
+(*                                                                         *)
+(* This program is distributed in the hope that it will be useful, but     *)
+(* WITHOUT ANY WARRANTY; without even the implied warranty of              *)
+(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU        *)
+(* General Public License for more details.                                *)
+(*                                                                         *)
+(* You should have received a copy of the GNU General Public License       *)
+(* along with this program; if not, write to the Free Software             *)
+(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *)
+
+open Volatility
+open Type
+open Ast
+
+let int_to_python n = PyInt(Unsigned.UInt64.of_int n)
+
+let int64_to_python n = PyInt(Unsigned.UInt64.of_int(Int64.to_int n))
+
+let rec typ_to_python = function
+	| Reg(n) ->
+			PyDict [ (PyString "reg", int_to_python n) ]
+  | TMem(t) ->
+  		PyDict [ (PyString "tmem", typ_to_python t) ]
+  | Array(t1, t2) ->
+  		PyDict [ (PyString "array", PyTuple [| typ_to_python t1; typ_to_python t2 |]) ]
+
+let var_to_python var =
+	PyDict [ (PyString "v", PyTuple [| int_to_python(Var.hash var); PyString(Var.name var); typ_to_python(Var.typ var) |]) ]
+
+let vars_to_python var_list = PyList(List.map var_to_python var_list)
+
+let label_to_python = function
+  | Name(s) ->
+  		PyDict [ (PyString "name", PyString s) ]
+  | Addr(a) ->
+  		PyDict [ (PyString "addr", int64_to_python a) ]
+
+let usage_to_python = function
+	| RD ->
+			PyString "rd"
+	| WR -> 
+			PyString "wr"
+	| RW ->
+			PyString "rw"
+
+let taint_to_python = function
+	| Taint(i) ->
+			PyDict [ (PyString "taint", int_to_python i) ]
+
+let big_int_to_python big_int = PyString(Big_int_Z.string_of_big_int big_int)
+
+let exn_to_python ex = PyString(Printexc.to_string ex)
+
+let context_to_python context =
+	PyDict [ (PyString "name", PyString(context.name)); (PyString "mem", PyBool(context.mem)); (PyString "t", typ_to_python(context.t)); (PyString "index", int64_to_python(context.index)); (PyString "value", big_int_to_python(context.value)); (PyString "usage", usage_to_python(context.usage)); (PyString "taint", taint_to_python(context.taint)) ]
+
+let attr_to_python = function
+  | Pos(s, i) ->
+  		PyDict [ (PyString "pos", PyTuple [| PyString s; int_to_python i |]) ]
+  | Asm(s) ->
+  		PyDict [ (PyString "asm", PyString s) ]
+  | Address(a) ->
+  		PyDict [ (PyString "address", int64_to_python a) ]
+  | Liveout ->
+  		PyString "liveout"
+  | StrAttr(s) ->
+  		PyDict [ (PyString "strattr", PyString s) ]
+  | Context(c) ->
+  		PyDict [ (PyString "context", context_to_python c) ]
+  | ThreadId(i) ->
+  		PyDict [ (PyString "threadid", int_to_python i) ]
+  | ExnAttr(e) ->
+  		PyDict [ (PyString "exnattr", exn_to_python e) ]
+  | InitRO ->
+  		PyString "initro"
+  | Synthetic ->
+  		PyString "synthetic"
+
+let attrs_to_python attr_list = PyList(List.map attr_to_python attr_list)
+
+let cast_to_python = function
+  | CAST_UNSIGNED ->
+  		PyString "cast_unsigned"
+  | CAST_SIGNED ->
+  		PyString "cast_signed"
+  | CAST_HIGH ->
+  		PyString "cast_high"
+  | CAST_LOW ->
+  		PyString "cast_low"
+
+let binop_to_python = function
+  | PLUS ->
+  		PyString "plus"
+  | MINUS ->
+  		PyString "minus"
+  | TIMES ->
+  		PyString "times"
+  | DIVIDE ->
+  		PyString "divide"
+  | SDIVIDE ->
+  		PyString "sdivide"
+  | MOD ->
+  		PyString "mod"
+  | SMOD ->
+  		PyString "smod"
+  | LSHIFT ->
+  		PyString "lshift"
+  | RSHIFT ->
+  		PyString "rshift"
+  | ARSHIFT ->
+  		PyString "arshift"
+  | AND ->
+  		PyString "and"
+  | OR ->
+  		PyString "or"
+  | XOR ->
+  		PyString "xor"
+  | EQ ->
+  		PyString "eq"
+  | NEQ ->
+  		PyString "neq"
+  | LT ->
+  		PyString "lt"
+  | LE ->
+  		PyString "le"
+  | SLT ->
+  		PyString "slt"
+  | SLE ->
+  		PyString "sle"
+
+let unop_to_python = function
+  | NEG ->
+  		PyString "neg"
+  | NOT ->
+  		PyString "not"
+
+let rec exp_to_python = function
+  | Load(e1, e2, e3, t) ->
+  		PyDict [ (PyString "load", PyTuple [| exp_to_python e1; exp_to_python e2; exp_to_python e3; typ_to_python t |]) ]
+  | Store(e1, e2, e3, e4, t) ->
+  		PyDict [ (PyString "store", PyTuple [| exp_to_python e1; exp_to_python e2; exp_to_python e3; exp_to_python e4; typ_to_python t |]) ]
+  | BinOp(op, e1, e2) ->
+  		PyDict [ (PyString "binop", PyTuple [| binop_to_python op; exp_to_python e1; exp_to_python e2 |]) ]
+  | UnOp(op, e) ->
+  		PyDict [ (PyString "unop", PyTuple [| unop_to_python op; exp_to_python e |]) ]
+  | Var(v) ->
+  		PyDict [ (PyString "var", var_to_python v) ]
+  | Lab(s) ->
+  		PyDict [ (PyString "lab", PyString s) ]
+  | Int(i, t) ->
+  		PyDict [ (PyString "int", PyTuple [| big_int_to_python i; typ_to_python t |]) ]
+  | Cast(ct, t, e) ->
+  		PyDict [ (PyString "cast", PyTuple [| cast_to_python ct; typ_to_python t; exp_to_python e |]) ]
+  | Let(v, e1, e2) ->
+  		PyDict [ (PyString "let", PyTuple [| var_to_python v; exp_to_python e1; exp_to_python e2 |]) ]
+  | Unknown(s, t) ->
+  		PyDict [ (PyString "unknown", PyTuple [| PyString s; typ_to_python t |]) ]
+  | Ite(eB, eT, eF) ->
+  		PyDict [ (PyString "ite", PyTuple [| exp_to_python eB; exp_to_python eT; exp_to_python eF |]) ]
+  | Extract(i1, i2, e) ->
+  		PyDict [ (PyString "extract", PyTuple [| big_int_to_python i1; big_int_to_python i2; exp_to_python e |]) ]
+  | Concat(e1, e2) ->
+  		PyDict [ (PyString "concat", PyTuple [| exp_to_python e1; exp_to_python e2 |]) ]
+
+let stmt_to_python = function
+  | Move(v, e, a) ->
+  		PyDict [ (PyString "move", PyTuple [| var_to_python v; exp_to_python e; attrs_to_python a |]) ]
+  | Jmp(e, a) ->
+  		PyDict [ (PyString "jmp", PyTuple [| exp_to_python e; attrs_to_python a |]) ]
+  | CJmp(eB, eT, eF, a) ->
+  		PyDict [ (PyString "cjmp", PyTuple [| exp_to_python eB; exp_to_python eT; exp_to_python eF; attrs_to_python a |]) ]
+  | Label(l, a) ->
+  		PyDict [ (PyString "label", PyTuple [| label_to_python l; attrs_to_python a |]) ]
+  | Halt(e, a) ->
+  		PyDict [ (PyString "halt", PyTuple [| exp_to_python e; attrs_to_python a |]) ]
+  | Assert(e, a) ->
+  		PyDict [ (PyString "assert", PyTuple [| exp_to_python e; attrs_to_python a |]) ]
+  | Assume(e, a) ->
+  		PyDict [ (PyString "assume", PyTuple [| exp_to_python e; attrs_to_python a |]) ]
+  | Comment(s, a) ->
+  		PyDict [ (PyString "comment", PyTuple [| PyString s; attrs_to_python a |]) ]
+  | Special(s, a) ->
+  		PyDict [ (PyString "special", PyTuple [| PyString s; attrs_to_python a |]) ]
+
+let to_python stmt_list = PyList(List.map stmt_to_python stmt_list)
+(* bap_cfg.ml                                                              *)
+(* Copyright (C) 2013 Carl Pulley <c.j.pulley@hud.ac.uk>                   *)
+(*                                                                         *)
+(* This program is free software; you can redistribute it and/or modify    *)
+(* it under the terms of the GNU General Public License as published by    *)
+(* the Free Software Foundation; either version 2 of the License, or (at   *)
+(* your option) any later version.                                         *)
+(*                                                                         *)
+(* This program is distributed in the hope that it will be useful, but     *)
+(* WITHOUT ANY WARRANTY; without even the implied warranty of              *)
+(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU        *)
+(* General Public License for more details.                                *)
+(*                                                                         *)
+(* You should have received a copy of the GNU General Public License       *)
+(* along with this program; if not, write to the Free Software             *)
+(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *)
+
+open Volatility
+
+let int_to_python = Bap_ast.int_to_python
+
+let int64_to_python = Bap_ast.int64_to_python
+
+let bbid_to_python = function
+  | Cfg.BB_Entry ->
+  		PyString "bb_entry"
+  | Cfg.BB_Exit ->
+  		PyString "bb_exit"
+  | Cfg.BB_Indirect ->
+  		PyString "bb_indirect"
+  | Cfg.BB_Error ->
+  		PyString "bb_error"
+  | Cfg.BB(n) ->
+  		PyDict [ (PyString "bb", int_to_python n) ]
+
+let node_to_python cfg node py_nodes =
+	let py_stmts = Bap_ast.to_python(Cfg.AST.get_stmts cfg node) in
+	let py_label = bbid_to_python(Cfg.AST.G.V.label node) in
+	let py_hash = int_to_python(Cfg.AST.G.V.hash node) in
+	let py_node = PyDict [ (PyString "hash", py_hash); (PyString "label", py_label); (PyString "stmts", py_stmts) ] in
+		py_node :: py_nodes
+
+let edge_to_python edge py_edges =
+  let label = Cfg.AST.G.E.label edge in
+  let py_source = int_to_python(Cfg.AST.G.V.hash(Cfg.AST.G.E.src edge)) in
+  let py_target = int_to_python(Cfg.AST.G.V.hash(Cfg.AST.G.E.dst edge)) in
+  let py_edge =
+    match label with
+    | Some b ->
+        PyDict [ (PyString "source", py_source); (PyString "target", py_target); (PyString "label", PyBool b) ]
+    | None ->
+        PyDict [ (PyString "source", py_source); (PyString "target", py_target) ]
+  in
+    py_edge :: py_edges
+
+let to_python cfg =
+  let py_nodes = Cfg.AST.G.fold_vertex (node_to_python cfg) cfg [] in
+  let py_edges = Cfg.AST.G.fold_edges_e edge_to_python cfg [] in
+    PyDict [ (PyString "nodes", PyList py_nodes); (PyString "edges", PyList py_edges) ]
+(* bap_ssa.ml                                                              *)
+(* Copyright (C) 2013 Carl Pulley <c.j.pulley@hud.ac.uk>                   *)
+(*                                                                         *)
+(* This program is free software; you can redistribute it and/or modify    *)
+(* it under the terms of the GNU General Public License as published by    *)
+(* the Free Software Foundation; either version 2 of the License, or (at   *)
+(* your option) any later version.                                         *)
+(*                                                                         *)
+(* This program is distributed in the hope that it will be useful, but     *)
+(* WITHOUT ANY WARRANTY; without even the implied warranty of              *)
+(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU        *)
+(* General Public License for more details.                                *)
+(*                                                                         *)
+(* You should have received a copy of the GNU General Public License       *)
+(* along with this program; if not, write to the Free Software             *)
+(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *)
+
+open Volatility
+open Ssa
+
+let int_to_python = Bap_ast.int_to_python
+
+let int64_to_python = Bap_ast.int64_to_python
+
+let value_to_python = function
+  | Int(i, t) ->
+      PyDict [ (PyString "int", PyTuple [| Bap_ast.big_int_to_python i; Bap_ast.typ_to_python t |]) ]
+  | Var(v) ->
+      PyDict [ (PyString "var", Bap_ast.var_to_python v) ]
+  | Lab(l) ->
+      PyDict [ (PyString "lab", PyString l) ]
+
+let exp_to_python = function
+  | Load(v1, v2, v3, t) ->
+      PyDict [ (PyString "load", PyTuple [| value_to_python v1; value_to_python v2; value_to_python v3; Bap_ast.typ_to_python t |]) ]
+  | Store(v1, v2, v3, v4, t) ->
+      PyDict [ (PyString "store", PyTuple [| value_to_python v1; value_to_python v2; value_to_python v3; value_to_python v4; Bap_ast.typ_to_python t |]) ]
+  | Ite(vB, vT, vF) ->
+      PyDict [ (PyString "ite", PyTuple [| value_to_python vB; value_to_python vT; value_to_python vF |]) ]
+  | Extract(i1, i2, v) ->
+      PyDict [ (PyString "extract", PyTuple [| Bap_ast.big_int_to_python i1; Bap_ast.big_int_to_python i2; value_to_python v |]) ]
+  | Concat(v1, v2) ->
+      PyDict [ (PyString "concat", PyTuple [| value_to_python v1; value_to_python v2 |]) ]
+  | BinOp(op, v1, v2) ->
+      PyDict [ (PyString "binop", PyTuple [| Bap_ast.binop_to_python op; value_to_python v1; value_to_python v2 |]) ]
+  | UnOp(op, v) ->
+      PyDict [ (PyString "unop", PyTuple [| Bap_ast.unop_to_python op; value_to_python v |]) ]
+  | Val(v) ->
+      PyDict [ (PyString "val", value_to_python v) ]
+  | Cast(ct, t, v) ->
+      PyDict [ (PyString "cast", PyTuple [| Bap_ast.cast_to_python ct; Bap_ast.typ_to_python t; value_to_python v |]) ]
+  | Unknown(s, t) ->
+      PyDict [ (PyString "unknown", PyTuple [| PyString s; Bap_ast.typ_to_python t |]) ]
+  | Phi(vs) ->
+      PyDict [ (PyString "phi", Bap_ast.vars_to_python vs) ]
+
+let stmt_to_python = function
+  | Move(v, e, a) ->
+      PyDict [ (PyString "move", PyTuple [| exp_to_python e; Bap_ast.attrs_to_python a |]) ]
+  | Jmp(v, a) ->
+      PyDict [ (PyString "jmp", Bap_ast.attrs_to_python a) ]
+  | CJmp(vB, vT, vF, a) ->
+      PyDict [ (PyString "cjmp", PyTuple [| value_to_python vB; value_to_python vT; value_to_python vF; Bap_ast.attrs_to_python a |]) ]
+  | Label(l, a) ->
+      PyDict [ (PyString "label", PyTuple [| Bap_ast.label_to_python l; Bap_ast.attrs_to_python a |]) ]
+  | Halt(v, a) ->
+      PyDict [ (PyString "halt", PyTuple [| value_to_python v; Bap_ast.attrs_to_python a |]) ]
+  | Assert(v, a) ->
+      PyDict [ (PyString "assert", PyTuple [| value_to_python v; Bap_ast.attrs_to_python a |])]
+  | Assume(v, a) ->
+      PyDict [ (PyString "assume", PyTuple [| value_to_python v; Bap_ast.attrs_to_python a |])]
+  | Comment(c, a) ->
+      PyDict [ (PyString "comment", PyTuple [| PyString c; Bap_ast.attrs_to_python a |])]
+
+let ast_to_python stmt_list = PyList(List.map stmt_to_python stmt_list)
+
+let node_to_python ssa node py_nodes =
+  let py_stmts = ast_to_python(Cfg.SSA.get_stmts ssa node) in
+  let py_label = Bap_cfg.bbid_to_python(Cfg.SSA.G.V.label node) in
+  let py_hash = int_to_python(Cfg.SSA.G.V.hash node) in
+  let py_node = PyDict [ (PyString "hash", py_hash); (PyString "label", py_label); (PyString "stmts", py_stmts) ] in
+    py_node :: py_nodes
+
+let edge_to_python edge py_edges =
+  let label = Cfg.SSA.G.E.label edge in
+  let py_source = int_to_python(Cfg.SSA.G.V.hash(Cfg.SSA.G.E.src edge)) in
+  let py_target = int_to_python(Cfg.SSA.G.V.hash(Cfg.SSA.G.E.dst edge)) in
+  let py_edge =
+    match label with
+    | Some b ->
+        PyDict [ (PyString "source", py_source); (PyString "target", py_target); (PyString "label", PyBool b) ]
+    | None ->
+        PyDict [ (PyString "source", py_source); (PyString "target", py_target) ]
+  in
+    py_edge :: py_edges
+
+let to_python ssa =
+  let py_nodes = Cfg.SSA.G.fold_vertex (node_to_python ssa) ssa [] in
+  let py_edges = Cfg.SSA.G.fold_edges_e edge_to_python ssa [] in
+    PyDict [ (PyString "nodes", PyList py_nodes); (PyString "edges", PyList py_edges) ]

ocaml/volatility.ml

+(* volatility.ml                                                           *)
+(* Copyright (C) 2013 Carl Pulley <c.j.pulley@hud.ac.uk>                   *)
+(*                                                                         *)
+(* This program is free software; you can redistribute it and/or modify    *)
+(* it under the terms of the GNU General Public License as published by    *)
+(* the Free Software Foundation; either version 2 of the License, or (at   *)
+(* your option) any later version.                                         *)
+(*                                                                         *)
+(* This program is distributed in the hope that it will be useful, but     *)
+(* WITHOUT ANY WARRANTY; without even the implied warranty of              *)
+(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU        *)
+(* General Public License for more details.                                *)
+(*                                                                         *)
+(* You should have received a copy of the GNU General Public License       *)
+(* along with this program; if not, write to the Free Software             *)
+(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *)
+
+open Unsigned
+
+(* Exception wrapping up Volatility/Python exceptions *)
+exception VolatilityException of string
+let _ = Callback.register_exception "VolatilityException" (VolatilityException "any string")
+
+(* Abstract type which represents a Volatility object instance *)
+type vol_obj
+
+type py_object =
+  PyNone
+  | PyInt of UInt64.t
+  | PyBool of bool
+  | PyFloat of float
+  | PyString of string
+  | PyTuple of py_object array
+  | PyList of py_object list
+  | PyDict of (py_object * py_object) list
+  | PyObject of vol_obj
+
+type py_eval =
+  PyAttribute of string
+  | PyMethod of string * py_object * py_object
+  | PyCall of py_object * py_object
+  | PyIter of py_object BatLazyList.t
+
+let empty_tuple = PyTuple [||]
+
+let empty_dict = PyDict []
+
+external _VolatilityObject_callback: vol_obj -> py_eval list -> py_object = "VolatilityObject_callback"
+
+(* Allows Python iteration objects to be lazily unwound *)
+let py_iter as_PyType iter_obj = BatLazyList.from (fun () ->
+  try
+    as_PyType(_VolatilityObject_callback iter_obj [ PyMethod( "next", empty_tuple, empty_dict ) ])
+  with VolatilityException "<type 'exceptions.StopIteration'>" -> 
+    raise BatLazyList.No_more_elements
+)
+
+let py_object_to_string = function
+| PyNone -> "PyNone"
+| PyInt _ -> "PyInt"
+| PyBool _ -> "PyBool"
+| PyFloat _ -> "PyFloat"
+| PyString _ -> "PyString"
+| PyTuple _ -> "PyTuple"
+| PyList _ -> "PyList"
+| PyDict _ -> "PyDict"
+| PyObject _ -> "PyObject"
+
+let as_PyInt = function
+| PyInt n -> n
+| pyobj -> raise (VolatilityException ("as_PyInt: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyInt type"))
+
+let as_PyBool = function
+| PyInt n -> n <> UInt64.zero
+| pyobj -> raise (VolatilityException ("as_PyBool: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyBool type"))
+
+let as_PyFloat = function
+| PyFloat n -> n
+| pyobj -> raise (VolatilityException ("as_PyFloat: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyFloat type"))
+
+let as_PyString = function
+| PyString n -> n
+| pyobj -> raise (VolatilityException ("as_PyString: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyString type"))
+
+let as_PyTuple = function
+| PyTuple n -> n
+| pyobj -> raise (VolatilityException ("as_PyTuple: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyTuple type"))
+
+let as_PyList = function
+| PyList n -> n
+| pyobj -> raise (VolatilityException ("as_PyList: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyList type"))
+
+let as_PyDict = function
+| PyDict n -> n
+| pyobj -> raise (VolatilityException ("as_PyDict: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyDict type"))
+
+let as_PyObject = function
+| PyObject n -> n
+| pyobj -> raise (VolatilityException ("as_PyObject: got a " ^ (py_object_to_string pyobj) ^ " [" ^ (Batteries.dump pyobj) ^ "], expected a PyObject type"))
+
+let as_Option py_type = function
+| PyNone -> 
+    None
+| pyobj -> 
+    try
+      Some(py_type pyobj)
+    with VolatilityException msg ->
+      raise (VolatilityException ("as_Option: " ^ msg))
 
 LIBS = [
   OCAMLLIB,
+  "{0}/../ctypes".format(OCAMLLIB),
   "{0}/../llvm".format(OCAMLLIB),
   "{0}/..".format(OCAMLLIB),
   "{0}/../camlidl".format(OCAMLLIB),
   "opcodes",
   "threads",
   "python2.7",
+  "ctypes_stubs",
+  "ctypes-foreign_stubs",
+  "ffi",
   "LLVMCore",
   "LLVM-3.2svn",
   "llvm_executionengine",
         if not os.path.exists(self.build_temp):
           os.makedirs(self.build_temp)
         # DEBUG:
-        shutil.copyfile("/home/carlpulley/{0}".format(BAPTAR), "{0}/{1}".format(self.build_temp, BAPTAR))
+        shutil.copyfile("/home/bagpuss/{0}".format(BAPTAR), "{0}/{1}".format(self.build_temp, BAPTAR))
         #FancyURLopener().retrieve(BAPURL, "{0}/{1}".format(self.build_temp, BAPTAR), reporthook=progress)
     
     # check downloaded SHA1 against BAPSHA1
 setup(
   name = "bap", 
   version='1.0',
-  description='Python wrapper for the Binary Analysis Platform (BAP)',
+  description='Python/Volatility wrapper for the Binary Analysis Platform (BAP)',
   author='Carl Pulley',
   author_email='c.j.pulley@hud.ac.uk',
   url='https://bitbucket.org/carlpulley/libbap/',

src/ctypes_unsigned_stubs.h

+/*
+ * Copyright (c) 2013 Jeremy Yallop.
+ *
+ * This file is distributed under the terms of the MIT License.
+ * See the file LICENSE for details.
+ */
+
+#ifndef CTYPES_UNSIGNED_STUBS_H
+#define CTYPES_UNSIGNED_STUBS_H
+
+#include <caml/mlvalues.h>
+
+#include <stdint.h>
+
+#define UINT_DECLS(BITS)                                                  \
+  extern value ctypes_copy_uint ## BITS(uint ## BITS ## _t u);            \
+  /* uintX_add : t -> t -> t */                                           \
+  extern value ctypes_uint ## BITS ## _ ## add(value a, value b);         \
+  /* uintX_sub : t -> t -> t */                                           \
+  extern value ctypes_uint ## BITS ## _ ## sub(value a, value b);         \
+  /* uintX_mul : t -> t -> t */                                           \
+  extern value ctypes_uint ## BITS ## _ ## mul(value a, value b);         \
+  /* uintX_div : t -> t -> t */                                           \
+  extern value ctypes_uint ## BITS ## _ ## div(value a, value b);         \
+  /* uintX_rem : t -> t -> t */                                           \
+  extern value ctypes_uint ## BITS ## _ ## rem(value a, value b);         \
+  /* uintX_logand : t -> t -> t */                                        \
+  extern value ctypes_uint ## BITS ## _ ## logand(value a, value b);      \
+  /* uintX_logor : t -> t -> t */                                         \
+  extern value ctypes_uint ## BITS ## _ ## logor(value a, value b);       \
+  /* uintX_logxor : t -> t -> t */                                        \
+  extern value ctypes_uint ## BITS ## _ ## logxor(value a, value b);      \
+  /* uintX_shift_left : t -> t -> t */                                    \
+  extern value ctypes_uint ## BITS ## _ ## shift_left(value a, value b);  \
+  /* uintX_shift_right : t -> t -> t */                                   \
+  extern value ctypes_uint ## BITS ## _ ## shift_right(value a, value b); \
+  /* of_int : int -> t */                                                 \
+  extern value ctypes_uint ## BITS ## _of_int(value a);                   \
+  /* to_int : t -> int */                                                 \
+  extern value ctypes_uint ## BITS ## _to_int(value a);                   \
+  /* of_string : string -> t */                                           \
+  extern value ctypes_uint ## BITS ## _of_string(value a, value b);       \
+  /* to_string : t -> string */                                           \
+  extern value ctypes_uint ## BITS ## _to_string(value a);                \
+  /* max : unit -> t */                                                   \
+  extern value ctypes_uint ## BITS ## _max(value a);
+
+UINT_DECLS(8)
+UINT_DECLS(16)
+UINT_DECLS(32)
+UINT_DECLS(64)
+
+/* X_size : unit -> int */
+extern value ctypes_size_t_size (value _);
+extern value ctypes_ushort_size (value _);
+extern value ctypes_uint_size (value _);
+extern value ctypes_ulong_size (value _);
+extern value ctypes_ulonglong_size (value _);
+
+#define Uint8_val(V) (*((uint8_t *) Data_custom_val(V)))
+#define Uint16_val(V) (*((uint16_t *) Data_custom_val(V)))
+#define Uint32_val(V) (*((uint32_t *) Data_custom_val(V)))
+#define Uint64_val(V) (*((uint64_t *) Data_custom_val(V)))
+
+#endif /* CTYPES_UNMSIGNED_STUBS_H */
 #include <caml/alloc.h>
 #include <caml/callback.h>
 #include <caml/fail.h>
+#include <caml/custom.h>
+
+// Copied from https://github.com/ocamllabs/ocaml-ctypes/commit/6ede17ae0749d4660bbb27719ad2c523e616ae24#src/unsigned_stubs.h
+#include "ctypes_unsigned_stubs.h"
 
 typedef struct {
   PyObject_HEAD
   value term;
 } BAP;
 
+typedef struct {
+  PyObject_HEAD
+
+  value caml_self;
+  PyObject* obj;
+} VolatilityObject;
+
+static PyObject* vol_none_object;
+
+PyObject* ocaml_to_python(value caml_term) {
+  PyObject* py_term;
+  PyObject* dict_key;
+  PyObject* dict_val;
+  int i;
+
+  CAMLparam1(caml_term);
+  CAMLlocal2(caml_tuple, list_cons);
+
+  if (Is_long(caml_term)) {
+    // Constant constructors
+    switch(Int_val(caml_term)) {
+      case 0:
+        // PyNone
+        py_term = Py_None;
+        break;
+      default:
+        PyErr_SetString(PyExc_TypeError, "ocaml_to_python: constant constructor term has an unrecognised type");
+        py_term = NULL;
+    }
+  } else {
+    // Non constant constructors
+    switch(Tag_val(caml_term)) {
+      case 0: 
+        // PyInt of UInt64.t
+        py_term = PyLong_FromUnsignedLongLong(Uint64_val(Field(caml_term, 0)));
+        break;
+      case 1:
+        // PyBool of bool
+        py_term = PyBool_FromLong(Bool_val(Field(caml_term, 0)));
+        break;
+      case 2:
+        // PyFloat of double
+        py_term = PyFloat_FromDouble(Double_val(Field(caml_term, 0)));
+        break;
+      case 3:
+        // PyString of string
+        py_term = PyString_FromStringAndSize(String_val(Field(caml_term, 0)), caml_string_length(Field(caml_term, 0)));
+        break;
+      case 4:
+        // PyTuple of py_object array
+        caml_tuple = Field(caml_term, 0);
+        py_term = PyTuple_New(Wosize_val(caml_tuple));
+        for(i = 0; i < Wosize_val(caml_tuple); i++) {
+          if (PyTuple_SetItem(py_term, i, ocaml_to_python(Field(caml_tuple, i))) != 0) {
+            // error occurred - assuming PyErr is already set
+            Py_CLEAR(py_term);
+            py_term = NULL;
+            break;
+          }
+        }
+        break;
+      case 5:
+        // PyList of py_object list
+        list_cons = Field(caml_term, 0);
+        py_term = PyList_New(0);
+        while(!Is_long(list_cons)) {
+          if (PyList_Append(py_term, ocaml_to_python(Field(list_cons, 0))) == 0) {
+            list_cons = Field(list_cons, 1);
+          } else {
+            // error occurred - assuming PyErr is already set
+            Py_CLEAR(py_term);
+            py_term = NULL;
+            break;
+          }
+        }
+        break;
+      case 6:
+        // PyDict of (py_object * py_object) list
+        list_cons = Field(caml_term, 0);
+        py_term = PyDict_New();
+        while(!Is_long(list_cons)) {
+          dict_key = ocaml_to_python(Field(Field(list_cons, 0), 0));
+          dict_val = ocaml_to_python(Field(Field(list_cons, 0), 1));
+          if (PyDict_SetItem(py_term, dict_key, dict_val) == 0) {
+            list_cons = Field(list_cons, 1);
+          } else {
+            // error occurred - assuming PyErr is already set
+            Py_CLEAR(py_term);
+            py_term = NULL;
+            break;
+          }
+        }
+        break;
+      case 7:
+        // PyObject of vol_obj (vol_obj <: VolatilityObject)
+        py_term = (PyObject*)Int64_val(Field(caml_term, 0)); // FIXME:
+        break;
+      default:
+        PyErr_SetString(PyExc_TypeError, "ocaml_to_python: non-constant constructor term has an unrecognised type");
+        py_term = NULL;
+    }
+  }
+  CAMLreturnT(PyObject*, py_term);
+}
+
+staticforward PyTypeObject VolatilityObjectType;
+staticforward PyObject* VolatilityObject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
+
+value python_to_ocaml(PyObject* py_term) {
+  PyObject* dict_keys;
+  PyObject* ptype;
+  PyObject* pvalue;
+  PyObject* ptraceback;
+  int i;
+
+  CAMLparam0();
+  CAMLlocal5(caml_term, list_cons, dict_entry, tuple_term, item);
+
+  if (py_term == Py_None) {
+    // PyNone
+    caml_term = Val_long(0);
+  } else if (PyObject_IsInstance(py_term, vol_none_object)) {
+      // PyNone
+      caml_term = Val_long(0);
+  } else if (PyInt_Check(py_term)) {
+      // PyInt of UInt64.t
+      caml_term = caml_alloc(1, 0);
+      item = ctypes_copy_uint64(PyInt_AsUnsignedLongLongMask(py_term));
+      Field(caml_term, 0) = item;
+  } else if (PyLong_Check(py_term)) {
+      // PyInt of UInt64.t
+      caml_term = caml_alloc(1, 0);
+      item = ctypes_copy_uint64(PyLong_AsUnsignedLongLong(py_term));
+      Field(caml_term, 0) = item;
+  } else if (PyBool_Check(py_term)) {
+      // PyBool of bool
+      caml_term = caml_alloc(1, 1);
+      Field(caml_term, 0) = Val_bool(py_term == Py_True);
+  } else if (PyFloat_Check(py_term)) {
+      // PyFloat of float
+      caml_term = caml_alloc(1, 2);
+      Field(caml_term, 0) = copy_double(PyFloat_AsDouble(py_term));
+  } else if (PyString_Check(py_term)) {
+      // PyString of string
+      caml_term = caml_alloc(1, 3);
+      item = alloc_string(PyString_Size(py_term));
+      Field(caml_term, 0) = item;
+      for(i = 0; i < PyString_Size(py_term); i++) {
+        Byte_u(item, i) = PyString_AsString(py_term)[i];
+      }
+  } else if (PyTuple_Check(py_term)) {
+      // PyTuple of py_object array
+      caml_term = caml_alloc(1, 4);
+      tuple_term = alloc_tuple(PyTuple_Size(py_term));
+      Field(caml_term, 0) = tuple_term;
+      for(i = 0; i < PyTuple_Size(py_term); i++) {
+        item = python_to_ocaml(PyTuple_GetItem(py_term, i));
+        Field(tuple_term, i) = item;
+      }
+  } else if (PyList_Check(py_term)) {
+      // PyList of py_object list
+      caml_term = caml_alloc(1, 5);
+      Field(caml_term, 0) = Val_emptylist;
+      for(i = PyList_Size(py_term) - 1; i >= 0; i--) {
+        list_cons = alloc_tuple(2);
+        item = python_to_ocaml(PyList_GetItem(py_term, i));
+        Field(list_cons, 0) = item;
+        Field(list_cons, 1) = Field(caml_term, 0);
+        Field(caml_term, 0) = list_cons;
+      }
+  } else if (PyDict_Check(py_term)) {
+      // PyDict of (py_object * py_object) list
+      caml_term = caml_alloc(1, 6);
+      Field(caml_term, 0) = Val_emptylist;
+      dict_keys = PyDict_Keys(py_term);
+      for(i = 0; i < PyList_Size(dict_keys); i++) {
+        list_cons = alloc_tuple(2);
+        dict_entry = alloc_tuple(2);
+        item = python_to_ocaml(PyList_GetItem(dict_keys, i));
+        Field(dict_entry, 0) = item;
+        item = python_to_ocaml(PyDict_GetItem(py_term, PyList_GetItem(dict_keys, i)));
+        Field(dict_entry, 1) = item;
+        Field(list_cons, 0) = dict_entry;
+        Field(list_cons, 1) = Field(caml_term, 0);
+        Field(caml_term, 0) = list_cons;
+      }
+      Py_XDECREF(dict_keys);
+  } else {
+      // PyObject of vol_obj
+      caml_term = caml_alloc(1, 7);
+      if (PyObject_IsInstance(py_term, (PyObject*)(&VolatilityObjectType))) {
+        // py_term is already an instance of VolatilityObject
+        Field(caml_term, 0) = ((VolatilityObject*)py_term)->caml_self;
+        Py_XINCREF(py_term);
+      } else {
+        // py_term is not an instance of VolatilityObjectType
+        item = ((VolatilityObject*)(VolatilityObject_new(&VolatilityObjectType, Py_BuildValue("(O)", py_term), NULL)))->caml_self;
+        Field(caml_term, 0) = item;
+      }
+  }
+
+  // Check that no Python exceptions have occurred during previous checks etc.
+  if (PyErr_Occurred()) {
+    PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+    PyErr_Clear();
+    Py_XDECREF(py_term);
+    if (pvalue != NULL) {
+      raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(pvalue));
+    } else {
+      raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(PyObject_Str(ptype)));
+    }
+    Py_XDECREF(ptype);
+    Py_XDECREF(pvalue);
+    Py_XDECREF(ptraceback);
+  }
+
+  CAMLreturn(caml_term);
+}
+
+void volatility_finalize(value caml_self) {
+  VolatilityObject *self;
+
+  self = (VolatilityObject*)Data_custom_val(caml_self);
+
+  self->caml_self = NULL;
+  Py_XDECREF(self);
+}
+
+static struct custom_operations volatility_self_ops = {
+  "volatility.ocaml.self",
+  &volatility_finalize,
+  custom_compare_default,
+  custom_hash_default,
+  custom_serialize_default,
+  custom_deserialize_default
+};
+
+static PyObject* VolatilityObject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
+  VolatilityObject *self;
+
+  self = (VolatilityObject*)PyType_GenericNew(type, args, kwargs);
+  if (self == NULL) {
+    return NULL;
+  }
+
+  if (!PyArg_ParseTuple(args, "O", &(self->obj))) {
+    PyErr_SetString(PyExc_TypeError, "Need to supply a Python object instance (of volatility.obj.BaseObject)");
+
+    return NULL;
+  }
+
+  register_global_root(&(self->caml_self));
+  self->caml_self = alloc_custom(&volatility_self_ops, sizeof(VolatilityObject*), 0, 1);
+  Field(self->caml_self, 1) = self;
+
+  Py_XINCREF(self);
+  Py_XINCREF(self->obj);
+
+  return (PyObject*)self;
+}
+
+static void VolatilityObject_dealloc(VolatilityObject *self) {
+  Py_XDECREF(self->obj);
+  remove_global_root(&(self->caml_self));
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+value VolatilityObject_callback(value caml_self, value py_eval_list) {
+  VolatilityObject *self;
+  PyObject* ptype;
+  PyObject* pvalue;
+  PyObject* ptraceback;
+  PyObject* method;
+  PyObject* result;
+  char* name;
+  PyObject* args;
+  PyObject* kwargs;
+
+  CAMLparam2(caml_self, py_eval_list);
+  CAMLlocal3(list_cons, data, caml_result);
+
+  self = (VolatilityObject*)Field(caml_self, 1);
+
+  result = self->obj;
+  list_cons = py_eval_list;
+  while (!Is_long(list_cons)) {
+    data = Field(list_cons, 0);
+    switch(Tag_val(data)) {
+      case 0:
+        // PyAttribute of string
+        name = String_val(Field(data, 0));
+        result = PyObject_GetAttrString(result, name);
+        if (result == NULL) {
+          if (PyErr_Occurred()) {
+            PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+            PyErr_Clear();
+            if (pvalue != NULL) {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(pvalue));
+            } else {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(PyObject_Str(ptype)));
+            }
+            Py_XDECREF(ptype);
+            Py_XDECREF(pvalue);
+            Py_XDECREF(ptraceback);
+          } else {
+            raise_with_string(*caml_named_value("VolatilityException"), "VolatilityObject_callback: failed to evaluate a PyAttribute instance");
+          }
+        }
+        break;
+      case 1:
+        // PyMethod of string * py_object * py_object
+        name = String_val(Field(data, 0));
+        args = ocaml_to_python(Field(data, 1));
+        kwargs = ocaml_to_python(Field(data, 2));
+        method = PyObject_GetAttrString(result, name);
+        if (method != NULL) {
+          if (PyDict_Size(kwargs) == 0) {
+            result = PyObject_Call(method, args, NULL);
+          } else {
+            result = PyObject_Call(method, args, kwargs);
+          }
+        }
+        Py_XDECREF(args);
+        Py_XDECREF(kwargs);
+        Py_XDECREF(method);
+        if (method == NULL || result == NULL) {
+          if (PyErr_Occurred()) {
+            PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+            PyErr_Clear();
+            if (pvalue != NULL) {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(pvalue));
+            } else {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(PyObject_Str(ptype)));
+            }
+            Py_XDECREF(ptype);
+            Py_XDECREF(pvalue);
+            Py_XDECREF(ptraceback);
+          } else {
+            raise_with_string(*caml_named_value("VolatilityException"), "VolatilityObject_callback: failed to evaluate a PyMethod instance");
+          }
+        }
+        break;
+      case 2:
+        // PyCall of py_object * py_object
+        args = ocaml_to_python(Field(data, 0));
+        kwargs = ocaml_to_python(Field(data, 1));
+        if (PyObject_Size(kwargs) == 0) {
+          result = PyObject_Call(result, args, NULL);
+        } else {
+          result = PyObject_Call(result, args, kwargs);
+        }
+        Py_XDECREF(args);
+        Py_XDECREF(kwargs);
+        if (result == NULL) {
+          if (PyErr_Occurred()) {
+            PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+            PyErr_Clear();
+            if (pvalue != NULL) {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(pvalue));
+            } else {
+              raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(PyObject_Str(ptype)));
+            }
+            Py_XDECREF(ptype);
+            Py_XDECREF(pvalue);
+            Py_XDECREF(ptraceback);
+          } else {
+            raise_with_string(*caml_named_value("VolatilityException"), "VolatilityObject_callback: failed to evaluate a PyCall instance");
+          }
+        }
+        break;
+      default:
+        if (PyErr_Occurred()) {
+          PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+          PyErr_Clear();
+          if (pvalue != NULL) {
+            raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(pvalue));
+          } else {
+            raise_with_string(*caml_named_value("VolatilityException"), PyString_AsString(PyObject_Str(ptype)));
+          }
+          Py_XDECREF(ptype);
+          Py_XDECREF(pvalue);
+          Py_XDECREF(ptraceback);
+        } else {
+          raise_with_string(*caml_named_value("VolatilityException"), "VolatilityObject_callback: invalid tag type for py_eval");
+        }
+    }
+    list_cons = Field(list_cons, 1);
+  }
+
+  caml_result = python_to_ocaml(result);
+  Py_XDECREF(result);
+  CAMLreturn(caml_result);
+}
+
 static PyObject* Program_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
   BAP *self;
   char* arch;
   CAMLreturnT(PyObject*, Py_BuildValue("s", String_val(result)));
 }
 
-PyObject* typ_to_python(value typ) {
-  PyObject* result;
-
-  CAMLparam1(typ);
-  CAMLlocal3(item1, item2, arg);
-
-  arg = Field(typ, 0);
-  if (Is_block(typ) && Tag_val(typ) == 0 && Wosize_val(typ) == 1) {
-    // Reg of int
-    result = Py_BuildValue("{si}", "reg", Int_val(Field(typ, 0)));
-  } else if (Is_block(typ) && Tag_val(typ) == 1 && Wosize_val(typ) == 1) {
-    // TMem of typ
-    item1 = Field(typ, 0);
-    result = Py_BuildValue("{sO}", "tmem", typ_to_python(item1));
-  } else if (Is_block(typ) && Tag_val(typ) == 2 && Wosize_val(arg) == 2) {
-    // Array of typ * typ
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "array", typ_to_python(item1), typ_to_python(item2));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "typ_to_python: unexpected Type.typ datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* var_to_python(value var) {
-  PyObject* result;
-
-  CAMLparam1(var);
-  CAMLlocal1(item);
-
-  if (Is_block(var) && Tag_val(var) == 0 && Wosize_val(var) == 3) {
-    // V of int * string * Type.typ
-    item = Field(var, 2);
-    result = Py_BuildValue("{s(isO)}", "v", Int_val(Field(var, 0)), String_val(Field(var, 1)), typ_to_python(item));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "var_to_python: unexpected Var.t datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* vars_to_python(value var_list) {
-  PyObject* result;
-  PyObject* py_var;
-
-  CAMLparam1(var_list);
-  CAMLlocal1(var);
-
-  result = PyList_New(0);
-  while(!Is_long(var_list)) {
-    var = Field(var_list, 0);
-    py_var = var_to_python(var);
-    if (!PyErr_Occurred() && PyList_Append(result, py_var) == 0) {
-      var_list = Field(var_list, 1);
-    } else {
-      // Deal with Python exception
-      Py_CLEAR(result);
-      CAMLreturnT(PyObject*, NULL);
-    }
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* label_to_python(value label) {
-  PyObject* result;
-
-  CAMLparam1(label);
-  CAMLlocal1(item);
-
-  if (Is_block(label) && Tag_val(label) == 0 && Wosize_val(label) == 1) {
-    // Name of string
-    result = Py_BuildValue("{ss}", "name", String_val(Field(label, 0)));
-  } else if (Is_block(label) && Tag_val(label) == 1 && Wosize_val(label) == 1) {
-    // Addr of int64
-    item = Field(label, 0);
-    result = Py_BuildValue("{sL}", "addr", Int64_val(Field(label, 0)));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "label_to_python: unexpected Type.label datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* usage_to_python(value usage) {
-  PyObject* result;
-
-  CAMLparam1(usage);
-
-  if (Is_long(usage) && Long_val(usage) == 0) {
-    // RD
-    result = PyString_FromString("rd");
-  } else if (Is_long(usage) && Long_val(usage) == 1) {
-    // WR
-    result = PyString_FromString("wr");
-  } else if (Is_long(usage) && Long_val(usage) == 2) {
-    // RW
-    result = PyString_FromString("rw");
-  } else {
-    PyErr_SetString(PyExc_TypeError, "usage_to_python: unexpected Type.usage datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* taint_to_python(value taint) {
-  PyObject* result;
-
-  CAMLparam1(taint);
-  CAMLlocal1(item);
-
-  if (Is_block(taint) && Tag_val(taint) == 0 && Wosize_val(taint) == 1) {
-    // Taint of int
-    result = Py_BuildValue("{si}", "taint", Int_val(Field(taint, 0)));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "taint_to_python: unexpected Type.taint_type datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* big_int_to_python(value big_int) {
-  CAMLparam1(big_int);
-  CAMLlocal1(result);
-
-  result = caml_callback(*caml_named_value("string_of_big_int"), big_int);
-
-  CAMLreturnT(PyObject*, Py_BuildValue("s", String_val(result)));
-}
-
-PyObject* exn_to_python(value exn) {
-  CAMLparam1(exn);
-  CAMLlocal1(result);
-
-  result = caml_callback(*caml_named_value("string_of_exn"), exn);
-
-  CAMLreturnT(PyObject*, Py_BuildValue("s", String_val(result)));
-}
-
-PyObject* context_to_python(value context) {
-  PyObject* result;
-
-  CAMLparam1(context);
-  CAMLlocal4(t_item, big_int_item, usage_item, taint_item);
-
-  if (Is_block(context) && Tag_val(context) == 0 && Wosize_val(context) == 7) {
-    // { name: string; mem: bool; t: typ; index: addr; value: big_int; usage: usage; taint: taint_type }
-    t_item = Field(context, 2);
-    big_int_item = Field(context, 4);
-    usage_item = Field(context, 5);
-    taint_item = Field(context, 6);
-    result = Py_BuildValue("{sssbsOsLsOsOsO}", "name", String_val(Field(context, 0)), "mem", Bool_val(Field(context, 1)), "t", typ_to_python(t_item), "index", Int64_val(Field(context, 3)), "value", big_int_to_python(big_int_item), "usage", usage_to_python(usage_item), "taint", taint_to_python(taint_item));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "context_to_python: unexpected Type.context record value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* attr_to_python(value attr) {
-  PyObject* result;
-
-  CAMLparam1(attr);
-  CAMLlocal2(item, arg);
-
-  arg = Field(attr, 0);
-  if (Is_block(attr) && Tag_val(attr) == 0 && Wosize_val(arg) == 2) {
-    // Pos of string * int
-    result = Py_BuildValue("{ssi}", "pos", String_val(Field(arg, 0)), Int_val(Field(arg, 1)));
-  } else if (Is_block(attr) && Tag_val(attr) == 1 && Wosize_val(attr) == 1) {
-    // Asm of string
-    result = Py_BuildValue("{ss}", "asm", String_val(Field(attr, 0)));
-  } else if (Is_block(attr) && Tag_val(attr) == 2 && Wosize_val(attr) == 1) {
-    // Address of int64
-    result = Py_BuildValue("{sL}", "address", Int64_val(Field(attr, 0)));
-  } else if (Is_long(attr) && Long_val(attr) == 0) {
-    // Liveout
-    result = PyString_FromString("liveout");
-  } else if (Is_block(attr) && Tag_val(attr) == 3 && Wosize_val(attr) == 1) {
-    // StrAttr of string
-    result = Py_BuildValue("{ss}", "strattr", String_val(Field(attr, 0)));
-  } else if (Is_block(attr) && Tag_val(attr) == 4 && Wosize_val(attr) == 1) {
-    // Context of context
-    item = Field(attr, 0);
-    result = Py_BuildValue("{sO}", "context", context_to_python(item));
-  } else if (Is_block(attr) && Tag_val(attr) == 5 && Wosize_val(attr) == 1) {
-    // ThreadId of int
-    result = Py_BuildValue("{si}", "threadid", Int_val(Field(attr, 0)));
-  } else if (Is_block(attr) && Tag_val(attr) == 6 && Wosize_val(attr) == 1) {
-    // ExnAttr of exn
-    item = Field(attr, 0);
-    result = Py_BuildValue("{ss}", "exnattr", exn_to_python(item));
-  } else if (Is_long(attr) && Long_val(attr) == 1) {
-    // InitRO
-    result = PyString_FromString("initro");
-  } else if (Is_long(attr) && Long_val(attr) == 2) {
-    // Synthetic
-    result = PyString_FromString("synthetic");
-  } else {
-    PyErr_SetString(PyExc_TypeError, "attr_to_python: unexpected Type.attribute datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* attrs_to_python(value attr_list) {
-  PyObject* result;
-  PyObject* py_attr;
-
-  CAMLparam1(attr_list);
-  CAMLlocal1(attr);
-
-  result = PyList_New(0);
-  while(!Is_long(attr_list)) {
-    attr = Field(attr_list, 0);
-    py_attr = attr_to_python(attr);
-    if (!PyErr_Occurred() && PyList_Append(result, py_attr) == 0) {
-      attr_list = Field(attr_list, 1);
-    } else {
-      // Deal with Python exception
-      Py_CLEAR(result);
-      CAMLreturnT(PyObject*, NULL);
-    }
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* cast_to_python(value cast) {
-  PyObject* result;
-
-  CAMLparam1(cast);
-
-  if (Is_long(cast) && Long_val(cast) == 0) {
-    // CAST_UNSIGNED
-    result = PyString_FromString("cast_unsigned");
-  } else if (Is_long(cast) && Long_val(cast) == 1) {
-    // CAST_SIGNED
-    result = PyString_FromString("cast_signed");
-  } else if (Is_long(cast) && Long_val(cast) == 2) {
-    // CAST_HIGH
-    result = PyString_FromString("cast_high");
-  } else if (Is_long(cast) && Long_val(cast) == 3) {
-    // CAST_LOW
-    result = PyString_FromString("cast_low");
-  } else {
-    PyErr_SetString(PyExc_TypeError, "cast_to_python: unexpected Type.cast_type datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* binop_to_python(value binop) {
-  PyObject* result;
-
-  CAMLparam1(binop);
-
-  if (Is_long(binop) && Long_val(binop) == 0) {
-    // PLUS
-    result = PyString_FromString("plus");
-  } else if (Is_long(binop) && Long_val(binop) == 1) {
-    // MINUS
-    result = PyString_FromString("minus");
-  } else if (Is_long(binop) && Long_val(binop) == 2) {
-    // TIMES
-    result = PyString_FromString("times");
-  } else if (Is_long(binop) && Long_val(binop) == 3) {
-    // DIVIDE
-    result = PyString_FromString("divide");
-  } else if (Is_long(binop) && Long_val(binop) == 4) {
-    // SDIVIDE
-    result = PyString_FromString("sdivide");
-  } else if (Is_long(binop) && Long_val(binop) == 5) {
-    // MOD
-    result = PyString_FromString("mod");
-  } else if (Is_long(binop) && Long_val(binop) == 6) {
-    // SMOD
-    result = PyString_FromString("smod");
-  } else if (Is_long(binop) && Long_val(binop) == 7) {
-    // LSHIFT
-    result = PyString_FromString("lshift");
-  } else if (Is_long(binop) && Long_val(binop) == 8) {
-    // RSHIFT
-    result = PyString_FromString("rshift");
-  } else if (Is_long(binop) && Long_val(binop) == 9) {
-    // ARSHIFT
-    result = PyString_FromString("arshift");
-  } else if (Is_long(binop) && Long_val(binop) == 10) {
-    // AND
-    result = PyString_FromString("and");
-  } else if (Is_long(binop) && Long_val(binop) == 11) {
-    // OR
-    result = PyString_FromString("or");
-  } else if (Is_long(binop) && Long_val(binop) == 12) {
-    // XOR
-    result = PyString_FromString("xor");
-  } else if (Is_long(binop) && Long_val(binop) == 13) {
-    // EQ
-    result = PyString_FromString("eq");
-  } else if (Is_long(binop) && Long_val(binop) == 14) {
-    // NEQ
-    result = PyString_FromString("neq");
-  } else if (Is_long(binop) && Long_val(binop) == 15) {
-    // LT
-    result = PyString_FromString("lt");
-  } else if (Is_long(binop) && Long_val(binop) == 16) {
-    // LE
-    result = PyString_FromString("le");
-  } else if (Is_long(binop) && Long_val(binop) == 17) {
-    // SLT
-    result = PyString_FromString("slt");
-  } else if (Is_long(binop) && Long_val(binop) == 18) {
-    // SLE
-    result = PyString_FromString("sle");
-  } else {
-    PyErr_SetString(PyExc_TypeError, "binop_to_python: unexpected Type.binop_type datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* unop_to_python(value unop) {
-  PyObject* result;
-
-  CAMLparam1(unop);
-
-  if (Is_long(unop) && Long_val(unop) == 0) {
-    // NEG
-    result = PyString_FromString("neg");
-  } else if (Is_long(unop) && Long_val(unop) == 1) {
-    // NOT
-    result = PyString_FromString("not");
-  } else {
-    PyErr_SetString(PyExc_TypeError, "unop_to_python: unexpected Type.unop_type datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* exp_to_python(value exp) {
-  PyObject* result;
-
-  CAMLparam1(exp);
-  CAMLlocal5(item, item1, item2, item3, item4);
-  CAMLlocal2(item5, arg);
-
-  arg = Field(exp, 0);
-  if (Is_block(exp) && Tag_val(exp) == 0 && Wosize_val(arg) == 3) {
-    // Load of (exp * exp * exp * typ) -> { "load": [exp, exp, exp, typ] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    item4 = Field(arg, 3);
-    result = Py_BuildValue("{s(OOOO)}", "load", exp_to_python(item1), exp_to_python(item2), exp_to_python(item3), typ_to_python(item4));
-  } else if (Is_block(exp) && Tag_val(exp) == 1 && Wosize_val(arg) == 5) {
-    // Store of (exp * exp * exp * exp * typ) -> { "store": [exp, exp, exp, exp, typ] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    item4 = Field(arg, 3);
-    item5 = Field(arg, 4);
-    result = Py_BuildValue("{s(OOOOO)}", "store", exp_to_python(item1), exp_to_python(item2), exp_to_python(item3), exp_to_python(item4), typ_to_python(item5));
-  } else if (Is_block(exp) && Tag_val(exp) == 2 && Wosize_val(arg) == 3) {
-    // BinOp of (binop_type * exp * exp) -> { "binop": [binop_type, exp, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "binop", binop_to_python(item1), exp_to_python(item2), exp_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 3 && Wosize_val(arg) == 2) {
-    // UnOp of (unop_type * exp) -> { "unop": [unop_type, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "unop", unop_to_python(item1), exp_to_python(item2));
-  } else if (Is_block(exp) && Tag_val(exp) == 4 && Wosize_val(exp) == 1) {
-    // Var of var -> { "var": [var] }
-    item1 = Field(exp, 0);
-    result = Py_BuildValue("{sO}", "var", var_to_python(item1));
-  } else if (Is_block(exp) && Tag_val(exp) == 5 && Wosize_val(exp) == 1) {
-    // Lab of string -> { "lab": string }
-    result = Py_BuildValue("{ss}", "lab", String_val(Field(exp, 0)));
-  } else if (Is_block(exp) && Tag_val(exp) == 6 && Wosize_val(arg) == 2) {
-    // Int of (big_int * typ) -> { "int": [big_int, typ] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "int", big_int_to_python(item1), typ_to_python(item2));
-  } else if (Is_block(exp) && Tag_val(exp) == 7 && Wosize_val(arg) == 3) {
-    // Cast of (cast_type * typ * exp) -> { "cast": [cast_type, typ, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "cast", cast_to_python(item1), typ_to_python(item2), exp_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 8 && Wosize_val(arg) == 3) {
-    // Let of (var * exp * exp) -> { "let": [var, exp, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "let", var_to_python(item1), exp_to_python(item2), exp_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 9 && Wosize_val(arg) == 2) {
-    // Unknown of (string * typ) -> { "unknown": [string, typ] }
-    item1 = Field(arg, 1);
-    result = Py_BuildValue("{s(sO)}", "unknown", String_val(Field(arg, 0)), typ_to_python(item1));
-  } else if (Is_block(exp) && Tag_val(exp) == 10 && Wosize_val(arg) == 3) {
-    // Ite of (exp * exp * exp) -> { "ite": [exp, exp, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "ite", exp_to_python(item1), exp_to_python(item2), exp_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 11 && Wosize_val(arg) == 3) {
-    // Extract of (big_int * big_int * exp) -> { "extract": [big_int, big_int, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "extract", big_int_to_python(item1), big_int_to_python(item2), exp_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 12 && Wosize_val(arg) == 2) {
-    // Concat of (exp * exp) -> { "concat": [exp, exp] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "concat", exp_to_python(item1), exp_to_python(item2));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "exp_to_python: unexpected Ast.exp datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* stmt_to_python(value stmt) {
-  PyObject* result;
-
-  CAMLparam1(stmt);
-  CAMLlocal5(item, item1, item2, item3, item4);
-  CAMLlocal1(arg);
-
-  arg = Field(stmt, 0);
-  if (Is_block(stmt) && Tag_val(stmt) == 0 && Wosize_val(arg) == 3) {
-    // Move of (var * exp * attrs) -> { "move": [var, exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    result = Py_BuildValue("{s(OOO)}", "move", var_to_python(item1), exp_to_python(item2), attrs_to_python(item3));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 1 && Wosize_val(arg) == 2) {
-    // Jmp of (exp * attrs) -> { "jmp": [exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "jmp", exp_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 2 && Wosize_val(arg) == 4) {
-    // CJmp of (exp * exp * exp * attrs) -> { "cjmp": [exp, exp, exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    item3 = Field(arg, 2);
-    item4 = Field(arg, 3);
-    result = Py_BuildValue("{s(OOOO)}", "cjmp", exp_to_python(item1), exp_to_python(item2), exp_to_python(item3), attrs_to_python(item4));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 3 && Wosize_val(arg) == 2) {
-    // Label of (label * attrs) -> { "label": [label, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "label", label_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 4 && Wosize_val(arg) == 2) {
-    // Halt of (exp * attrs) -> { "halt": [exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "halt", exp_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 5 && Wosize_val(arg) == 2) {
-    // Assert of (exp * attrs) -> { "assert": [exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "assert", exp_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 6 && Wosize_val(arg) == 2) {
-    // Assume of (exp * attrs) -> { "assume": [exp, attrs] }
-    item1 = Field(arg, 0);
-    item2 = Field(arg, 1);
-    result = Py_BuildValue("{s(OO)}", "assume", exp_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 7 && Wosize_val(arg) == 2) {
-    // Comment of (string * attrs) -> { "comment": [string, attrs] }
-    item = Field(arg, 1);
-    result = Py_BuildValue("{s(sO)}", "comment", String_val(Field(arg, 0)), attrs_to_python(item));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 8 && Wosize_val(arg) == 2) {
-    // Special of (string * attrs) -> { "special": [string, attrs] }
-    item = Field(arg, 1);
-    result = Py_BuildValue("{s(sO)}", "special", String_val(Field(arg, 0)), attrs_to_python(item));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "stmt_to_python: unexpected Ast.stmt datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ast_to_python(value stmt_list) {
-  // stmt list -> [stmt,..]
-  PyObject* result;
-  PyObject* py_stmt;
-
-  CAMLparam1(stmt_list);
-  CAMLlocal1(stmt);
-
-  result = PyList_New(0);
-  while(stmt_list != Val_emptylist) {
-    stmt = Field(stmt_list, 0);
-    py_stmt = stmt_to_python(stmt);
-    if (!PyErr_Occurred() && PyList_Append(result, py_stmt) == 0) {
-      stmt_list = Field(stmt_list, 1);
-    } else {
-      // Deal with Python exception
-      Py_CLEAR(result);
-      CAMLreturnT(PyObject*, NULL);
-    }
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* bbid_to_python(value bbid) {
-  PyObject* result;
-
-  CAMLparam1(bbid);
-  CAMLlocal1(bb);
-
-  if (Is_long(bbid) && Long_val(bbid) == 0) {
-    // BB_Entry
-    result = PyString_FromString("bb_entry");
-  } else if (Is_long(bbid) && Long_val(bbid) == 1) {
-    // BB_Exit
-    result = PyString_FromString("bb_exit");
-  } else if (Is_long(bbid) && Long_val(bbid) == 2) {
-    // BB_Indirect
-    result = PyString_FromString("bb_indirect");
-  } else if (Is_long(bbid) && Long_val(bbid) == 3) {
-    // BB_Error
-    result = PyString_FromString("bb_error");
-  } else if (Is_block(bbid) && Tag_val(bbid) == 0 && Wosize_val(bbid) == 1) {
-    // BB of int
-    bb = Field(bbid, 0);
-    result = Py_BuildValue("{si}", "bb", Int_val(bb));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "bbid_to_python: unexpected Cfg.bbid datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* node_to_python(value cfg, value node, PyObject* py_nodes) {
-  PyObject* py_stmts;
-  PyObject* py_label;
-  PyObject* py_node;
-
-  CAMLparam1(node);
-  CAMLlocal3(stmts, label, hash);
-
-  stmts = caml_callback2(*caml_named_value("node_stmts"), cfg, node);
-  label = caml_callback(*caml_named_value("node_label"), node);
-  hash = caml_callback(*caml_named_value("node_hash"), node);
-  py_stmts = ast_to_python(stmts);
-  py_label = bbid_to_python(label);
-  py_node = Py_BuildValue("{sisOsO}", "hash", Int_val(hash), "label", py_label, "stmts", py_stmts);
-  if (!PyErr_Occurred() && PyList_Append(py_nodes, py_node) == 0) {
-    CAMLreturnT(PyObject*, py_nodes);
-  } else {
-    // Deal with Python exception
-    CAMLreturnT(PyObject*, NULL);
-  }
-}
-
-PyObject* edge_to_python(value edge, PyObject* py_edges) {
-  PyObject* py_label;
-  PyObject* py_edge;
-
-  CAMLparam1(edge);
-  CAMLlocal3(label, source, target);
-
-  label = caml_callback(*caml_named_value("edge_label"), edge);
-  source = caml_callback(*caml_named_value("edge_source"), edge);
-  target = caml_callback(*caml_named_value("edge_target"), edge);
-  if (Is_block(label)) {
-    // label == Some of bool
-    if (Bool_val(Field(label, 0)) == Val_true) {
-      py_label = Py_True;
-    } else {
-      py_label = Py_False;
-    }
-    py_edge = Py_BuildValue("{sisisO}", "source", Int_val(source), "target", Int_val(target), "label", py_label);
-  } else {
-    // label == None
-    py_edge = Py_BuildValue("{sisi}", "source", Int_val(source), "target", Int_val(target));
-  }
-  if (!PyErr_Occurred() && PyList_Append(py_edges, py_edge) == 0) {
-    CAMLreturnT(PyObject*, py_edges);
-  } else {
-    // Deal with Python exception
-    CAMLreturnT(PyObject*, NULL);
-  }
-}
-
-PyObject* cfg_to_python(value cfg) {
-  // Graph(Ast.stmt list)
-  PyObject* py_nodes;
-  PyObject* py_edges;
-  PyObject* result;
-
-  CAMLparam1(cfg);
-  CAMLlocal2(nodes, edges);
-
-  py_nodes = PyList_New(0);
-  nodes = caml_callback2(*caml_named_value("fold_nodes"), cfg, py_nodes);
-
-  py_edges = PyList_New(0);
-  edges = caml_callback2(*caml_named_value("fold_edges"), cfg, py_edges);
-
-  result = Py_BuildValue("{sOsO}", "nodes", py_nodes, "edges", py_edges);
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ssa_value_to_python(value val) {
-  PyObject* result;
-
-  CAMLparam1(val);
-
-  if (Is_block(val) && Tag_val(val) == 0 && Wosize_val(val) == 2) {
-    // Int of big_int * typ
-    result = Py_BuildValue("{s(sO)}", "pos", big_int_to_python(Field(val, 0)), typ_to_python(Field(val, 1)));
-  } else if (Is_block(val) && Tag_val(val) == 1 && Wosize_val(val) == 1) {
-    // Var of var
-    result = Py_BuildValue("{sO}", "var", var_to_python(Field(val, 0)));
-  } else if (Is_block(val) && Tag_val(val) == 2 && Wosize_val(val) == 1) {
-    // Lab of string
-    result = Py_BuildValue("{ss}", "lab", String_val(Field(val, 0)));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "ssa_value_to_python: unexpected Ssa.value datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ssa_exp_to_python(value exp) {
-  PyObject* result;
-
-  CAMLparam1(exp);
-  CAMLlocal5(item, item1, item2, item3, item4);
-  CAMLlocal1(item5);
-
-  if (Is_block(exp) && Tag_val(exp) == 0 && Wosize_val(exp) == 3) {
-    // Load of value * value * value * typ -> { "load": [value, value, value, typ] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    item4 = Field(exp, 3);
-    result = Py_BuildValue("{s(OOOO)}", "load", ssa_value_to_python(item1), ssa_value_to_python(item2), ssa_value_to_python(item3), typ_to_python(item4));
-  } else if (Is_block(exp) && Tag_val(exp) == 1 && Wosize_val(exp) == 5) {
-    // Store of value * value * value * value * typ -> { "store": [value, value, value, value, typ] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    item4 = Field(exp, 3);
-    item5 = Field(exp, 4);
-    result = Py_BuildValue("{s(OOOOO)}", "store", ssa_value_to_python(item1), ssa_value_to_python(item2), ssa_value_to_python(item3), ssa_value_to_python(item4), typ_to_python(item5));
-  } else if (Is_block(exp) && Tag_val(exp) == 2 && Wosize_val(exp) == 3) {
-    // Ite of value * value * value -> { "ite": [value, value, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    result = Py_BuildValue("{s(OOO)}", "ite", ssa_value_to_python(item1), ssa_value_to_python(item2), ssa_value_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 3 && Wosize_val(exp) == 3) {
-    // Extract of big_int * big_int * value -> { "extract": [big_int, big_int, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    result = Py_BuildValue("{s(OOO)}", "extract", big_int_to_python(item1), big_int_to_python(item2), ssa_value_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 4 && Wosize_val(exp) == 2) {
-    // Concat of value * value -> { "concat": [value, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    result = Py_BuildValue("{s(OO)}", "concat", ssa_value_to_python(item1), ssa_value_to_python(item2));
-  } else if (Is_block(exp) && Tag_val(exp) == 5 && Wosize_val(exp) == 3) {
-    // BinOp of binop_type * value * value -> { "binop": [binop_type, value, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    result = Py_BuildValue("{s(OOO)}", "binop", binop_to_python(item1), ssa_value_to_python(item2), ssa_value_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 6 && Wosize_val(exp) == 2) {
-    // UnOp of unop_type * value -> { "unop": [unop_type, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    result = Py_BuildValue("{s(OO)}", "unop", unop_to_python(item1), ssa_value_to_python(item2));
-  } else if (Is_block(exp) && Tag_val(exp) == 7 && Wosize_val(exp) == 1) {
-    // Val of value -> { "val": [value] }
-    item1 = Field(exp, 0);
-    result = Py_BuildValue("{sO}", "val", ssa_value_to_python(item1));
-  } else if (Is_block(exp) && Tag_val(exp) == 8 && Wosize_val(exp) == 3) {
-    // Cast of cast_type * typ * value -> { "cast": [cast_type, typ, value] }
-    item1 = Field(exp, 0);
-    item2 = Field(exp, 1);
-    item3 = Field(exp, 2);
-    result = Py_BuildValue("{s(OOO)}", "cast", cast_to_python(item1), typ_to_python(item2), ssa_value_to_python(item3));
-  } else if (Is_block(exp) && Tag_val(exp) == 9 && Wosize_val(exp) == 2) {
-    // Unknown of string * typ -> { "unknown": [string, typ] }
-    item1 = Field(exp, 1);
-    result = Py_BuildValue("{s(sO)}", "unknown", String_val(Field(exp, 0)), typ_to_python(item1));
-  } else if (Is_block(exp) && Tag_val(exp) == 5 && Wosize_val(exp) == 1) {
-    // Phi of var list -> { "phi": var list }
-    result = Py_BuildValue("{sO}", "phi", vars_to_python(Field(exp, 0)));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "ssa_exp_to_python: unexpected Ssa.exp datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ssa_stmt_to_python(value stmt) {
-  PyObject* result;
-
-  CAMLparam1(stmt);
-  CAMLlocal5(item, item1, item2, item3, item4);
-
-  if (Is_block(stmt) && Tag_val(stmt) == 0 && Wosize_val(stmt) == 3) {
-    // Move of var * exp * attrs -> { "move": [var, exp, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    item3 = Field(stmt, 2);
-    result = Py_BuildValue("{s(OOO)}", "move", var_to_python(item1), ssa_exp_to_python(item2), attrs_to_python(item3));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 1 && Wosize_val(stmt) == 2) {
-    // Jmp of value * attrs -> { "jmp": [value, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(OO)}", "jmp", ssa_value_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 2 && Wosize_val(stmt) == 4) {
-    // CJmp of value * value * value * attrs -> { "cjmp": [value, value, value, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    item3 = Field(stmt, 2);
-    item4 = Field(stmt, 3);
-    result = Py_BuildValue("{s(OOOO)}", "cjmp", ssa_value_to_python(item1), ssa_value_to_python(item2), ssa_value_to_python(item3), attrs_to_python(item4));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 3 && Wosize_val(stmt) == 2) {
-    // Label of label * attrs -> { "label": [label, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(OO)}", "label", label_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 4 && Wosize_val(stmt) == 2) {
-    // Halt of value * attrs -> { "halt": [value, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(OO)}", "halt", ssa_value_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 5 && Wosize_val(stmt) == 2) {
-    // Assert of value * attrs -> { "assert": [value, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(OO)}", "assert", ssa_value_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 6 && Wosize_val(stmt) == 2) {
-    // Assume of value * attrs -> { "assume": [value, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(OO)}", "assume", ssa_value_to_python(item1), attrs_to_python(item2));
-  } else if (Is_block(stmt) && Tag_val(stmt) == 7 && Wosize_val(stmt) == 2) {
-    // Comment of string * attrs -> { "comment": [string, attrs] }
-    item1 = Field(stmt, 0);
-    item2 = Field(stmt, 1);
-    result = Py_BuildValue("{s(sO)}", "comment", String_val(item1), attrs_to_python(item2));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "ssa_stmt_to_python: unexpected Ssa.stmt datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ssa_ast_to_python(value stmt_list) {
-  // stmt list -> [stmt,..]
-  PyObject* result;
-  PyObject* py_stmt;
-
-  CAMLparam1(stmt_list);
-  CAMLlocal1(stmt);
-
-  result = PyList_New(0);
-  while(stmt_list != Val_emptylist) {
-    stmt = Field(stmt_list, 0);
-    py_stmt = ssa_stmt_to_python(stmt);
-    if (!PyErr_Occurred() && PyList_Append(result, py_stmt) == 0) {
-      stmt_list = Field(stmt_list, 1);
-    } else {
-      // Deal with Python exception
-      Py_CLEAR(result);
-      CAMLreturnT(PyObject*, NULL);
-    }
-  }
-
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* ssa_node_to_python(value ssa, value node, PyObject* py_nodes) {
-  PyObject* py_stmts;
-  PyObject* py_label;
-  PyObject* py_node;
-
-  CAMLparam1(node);
-  CAMLlocal3(stmts, label, hash);
-
-  stmts = caml_callback2(*caml_named_value("ssa_node_stmts"), ssa, node);
-  label = caml_callback(*caml_named_value("ssa_node_label"), node);
-  hash = caml_callback(*caml_named_value("ssa_node_hash"), node);
-  py_stmts = ssa_ast_to_python(stmts);
-  py_label = bbid_to_python(label);
-  py_node = Py_BuildValue("{sisOsO}", "hash", Int_val(hash), "label", py_label, "stmts", py_stmts);
-  if (!PyErr_Occurred() && PyList_Append(py_nodes, py_node) == 0) {
-    CAMLreturnT(PyObject*, py_nodes);
-  } else {
-    // Deal with Python exception
-    CAMLreturnT(PyObject*, NULL);
-  }
-}
-
-PyObject* ssa_edge_to_python(value edge, PyObject* py_edges) {
-  PyObject* py_label;
-  PyObject* py_edge;
-
-  CAMLparam1(edge);
-  CAMLlocal3(label, source, target);
-
-  label = caml_callback(*caml_named_value("ssa_edge_label"), edge);
-  source = caml_callback(*caml_named_value("ssa_edge_source"), edge);
-  target = caml_callback(*caml_named_value("ssa_edge_target"), edge);
-  if (Is_block(label)) {
-    // label == Some of bool
-    if (Bool_val(Field(label, 0)) == Val_true) {
-      py_label = Py_True;
-    } else {
-      py_label = Py_False;
-    }
-    py_edge = Py_BuildValue("{sisisO}", "source", Int_val(source), "target", Int_val(target), "label", py_label);
-  } else {
-    // label == None
-    py_edge = Py_BuildValue("{sisi}", "source", Int_val(source), "target", Int_val(target));
-  }
-  if (!PyErr_Occurred() && PyList_Append(py_edges, py_edge) == 0) {
-    CAMLreturnT(PyObject*, py_edges);
-  } else {
-    // Deal with Python exception
-    CAMLreturnT(PyObject*, NULL);
-  }
-}
-
-PyObject* ssa_to_python(value ssa) {
-  // Graph(Ssa.stmt list)
-  PyObject* py_nodes;
-  PyObject* py_edges;
-  PyObject* result;
-
-  CAMLparam1(ssa);
-  CAMLlocal2(nodes, edges);
-
-  py_nodes = PyList_New(0);
-  nodes = caml_callback2(*caml_named_value("ssa_fold_nodes"), ssa, py_nodes);
-
-  py_edges = PyList_New(0);
-  edges = caml_callback2(*caml_named_value("ssa_fold_edges"), ssa, py_edges);
-
-  result = Py_BuildValue("{sOsO}", "nodes", py_nodes, "edges", py_edges);
-  CAMLreturnT(PyObject*, result);
-}
-
-PyObject* bap_to_python(value prog_term) {
-  CAMLparam1(prog_term);
-  CAMLlocal1(item);
-
-  if (Is_block(prog_term) && Tag_val(prog_term) == 0 && Wosize_val(prog_term) == 1) {
-    // Ast of Ast.program
-    item = Field(prog_term, 0);
-
-    CAMLreturnT(PyObject*, ast_to_python(item));
-  } else if (Is_block(prog_term) && Tag_val(prog_term) == 1 && Wosize_val(prog_term) == 1) {
-    // AstCfg of Cfg.AST.G.t
-    item = Field(prog_term, 0);
-    CAMLreturnT(PyObject*, cfg_to_python(item));
-  } else if (Is_block(prog_term) && Tag_val(prog_term) == 2 && Wosize_val(prog_term) == 1) {
-    // Ssa of Cfg.SSA.G.t
-    item = Field(prog_term, 0);
-    CAMLreturnT(PyObject*, ssa_to_python(item));
-  } else {
-    PyErr_SetString(PyExc_TypeError, "bap_to_python: unexpected Iltrans.prog datatype value");
-
-    CAMLreturnT(PyObject*, NULL);
-  }
-}
-
-PyObject* model_to_python(value model) {
-  // model: (string * big_int) list option
-  PyObject* py_model;
-  PyObject* py_key;
-  PyObject* py_val;
-
-  CAMLparam1(model);
-  CAMLlocal4(interp, maplet, key, val);
-
-  if (Is_block(model)) {
-    // model == Some interp
-    py_model = PyDict_New();
-    interp = Field(Field(model, 0), 0);
-    while(!Is_long(interp)) {
-      // interp == maplet :: interp
-      maplet = Field(interp, 0);
-      key = Field(maplet, 0);
-      py_key = PyString_FromString(String_val(key));
-      val = Field(maplet, 1);
-      py_val = big_int_to_python(val);
-      if (!PyErr_Occurred() && PyDict_SetItem(py_model, py_key, py_val) == 0) {
-        interp = Field(interp, 1);
-      } else {
-        // Deal with Python exception
-        Py_CLEAR(py_model);
-        CAMLreturnT(PyObject*, NULL);
-      }
-    }
-    // interp == []
-  } else {
-    // model == None
-    py_model = Py_None;
-  }
-
-  CAMLreturnT(PyObject*, py_model);
-}
-
 static PyObject* BAP_call(BAP* self, PyObject* args, PyObject* kwargs) {
   PyObject* cmds;
   Py_ssize_t num_cmds, cmd_size, i, j;
   PyObject* cmd;
   PyObject* cmd_str;
-  PyObject* py_term;
-  PyObject* py_model;
-  PyObject* py_result;
 
   if (self->term == NULL) {
     PyErr_SetString(PyExc_TypeError, "__call__: need to __init__ object (currently we encapsulate a null BAP term)");
 
   CAMLparam1(ocaml_cmds);
   CAMLlocal5(ocaml_cmd, cons_cmds, item, result, exn);
-  CAMLlocal3(model, wp, foralls);
 
   ocaml_cmds = Val_emptylist;
   for (i=num_cmds-1; i >= 0; i--) {
     CAMLreturnT(PyObject*, NULL);
   }
 
-  // result: (Iltrans.prog * Smtexec.model * Ast.exp option * Ast.var option) option
-  if (Is_block(result)) {
-    // Some of Iltrans.prog * Smtexec.model * Ast.exp option * Ast.var option
-    item = Field(result, 0);
-    py_term = bap_to_python(Field(item, 0));
-    model = Field(item, 1);
-    wp = Field(item, 2);
-    foralls = Field(item, 3);
-    if (Is_long(model)) {
-      // model == None
-      if (Is_long(wp)) {
-        // wp == None && foralls == None
-        py_result = Py_BuildValue("{sO}", "term", py_term);
-      } else {
-        // wp == Some _ && foralls == Some _
-        py_result = Py_BuildValue("{sOs{sOsO}}", "term", py_term, "wp", "pre", exp_to_python(Field(wp, 0)), "foralls", vars_to_python(Field(foralls, 0)));
-      }
-    } else {
-      // model == Some _
-      py_model = model_to_python(model);
-      if (Is_long(wp)) {
-        // wp == None && foralls == None
-        py_result = Py_BuildValue("{sOsO}", "term", py_term, "model", py_model);
-      } else {
-        // wp == Some _ && foralls == Some _
-        py_result = Py_BuildValue("{sOsOs{sOsO}}", "term", py_term, "model", py_model, "wp", "pre", exp_to_python(Field(wp, 0)), "foralls", vars_to_python(Field(foralls, 0)));
-      }
-    }
-    CAMLreturnT(PyObject*, py_result);
-  } else {
-    // None
-    CAMLreturnT(PyObject*, Py_None);
-  }
+  CAMLreturnT(PyObject*, ocaml_to_python(result));
 }
 
+static PyTypeObject VolatilityObjectType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                         /* ob_size */
+  "VolatilityObject",        /* tp_name */
+  sizeof(VolatilityObject),  /* tp_basicsize */
+  0,                         /* tp_itemsize */
+  (destructor)VolatilityObject_dealloc, /* tp_dealloc */
+  0,                         /* tp_print */
+  0,                         /* tp_getattr */
+  0,                         /* tp_setattr */
+  0,                         /* tp_compare */
+  0,                         /* tp_repr */
+  0,                         /* tp_as_number */
+  0,                         /* tp_as_sequence */
+  0,                         /* tp_as_mapping */
+  0,                         /* tp_hash */
+  0,                         /* tp_call */
+  0,                         /* tp_str */
+  PyObject_GenericGetAttr,   /* tp_getattro */
+  0,                         /* tp_setattro */
+  0,                         /* tp_as_buffer */
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
+  "OCaml/Volatility interface - allows volatility.obj.BaseObject instances to have methods called from OCaml", /* tp_doc */
+  0,                         /* tp_traverse */
+  0,                         /* tp_clear */
+  0,                         /* tp_richcompare */
+  0,                         /* tp_weaklistoffset */
+  0,                         /* tp_iter */
+  0,                         /* tp_iternext */
+  0,                         /* tp_methods */
+  0,                         /* tp_members */
+  0,                         /* tp_getset */
+  0,                         /* tp_base */
+  0,                         /* tp_dict */
+  0,                         /* tp_descr_get */
+  0,                         /* tp_descr_set */
+  0,                         /* tp_dictoffset */
+  0,                         /* tp_init */
+  0,                         /* tp_alloc */
+  VolatilityObject_new,      /* tp_new */
+};
+
 static PyTypeObject ProgramType = {
   PyObject_HEAD_INIT(NULL)
   0,                         /* ob_size */
 
 void initlibbap(void) {
   PyObject* mod;
+  PyObject* obj_mod;
   char *argv[2];
   
   argv[0] = "python";
   caml_startup(argv);
 
   // Create the module
-  mod = Py_InitModule3("libbap", NULL, "Python interface to the Binary Analysis Platform (BAP)");
+  mod = Py_InitModule3("libbap", NULL, "Python/Volatility interface to the Binary Analysis Platform (BAP)");
   if (mod == NULL) {
     return;
   }
 
   // Fill in some slots in the types, and make them ready
+  if (PyType_Ready(&VolatilityObjectType) < 0) {
+    return;
+  }
   if (PyType_Ready(&ProgramType) < 0) {
     return;
   }