Skip to content

percontation/ocaml-xed-bindings

Repository files navigation

Xed Bindings

Bindings to Intel XED from OCaml.

Warning: This binding doesn't perfectly ensure safety of underlying XED function calls, e.g. calling Xed.Inst.operand x 99999999 has no bounds check and will crash.

Build

Run xed-build.sh before building with dune build --ignore-promoted-rules.

Building without --ignore-promoted-rules requires that Python bindings for Clang be installed.

About

This binding is mostly a direct mapping to underlying XED functions, but names have been reorganized to be more idiomatic to OCaml.

XED structures are handled as opaque types, e.g. xed_decoded_inst_t is Xed.DecodedInst.t. XED functions that resemble methods on a struct have been sorted into modules, e.g. xed_decoded_inst_get_length is Xed.DecodedInst.get_length. As with their XED counterparts, these structures are generally mutable. You'll see [<`Read|`Write] as parameters to the OCaml opaque types; these are to prevent attempted modification of const struct pointers and should't get in your way unless you're breaking const-correctness in the XED API (which isn't necessarily unsafe).

XED enums are exposed as OCaml constructors in Xed.Enum. XED functions that concern only enums are in that module. The enum–string conversion functions are there too and have been renamed, e.g. xed_reg_enum_t2str and str2xed_reg_enum_t are now reg_to_string and reg_of_string respectively. There are also foo_to_int & foo_of_int functions for each enum type, but you typically shouldn't need those.

Many XED functions that initialize a particular XED structure have been modified to both allocate and initialize; e.g. xed_decode is Xed.decode : 'a XedStructs.State.t -> string -> ('b DecodedInst.t, Enum.error) result, instead of taking an uninitialized DecodedInst.t as a argument.

Much of the code in this library is automatically generated by a bespoke Python script that parses XED's header files. The generated code is a ocaml-ctypes "low-level" binding (function_desc.ml & type_desc.ml), and a "high-level" binding (bind.ml & XBEnums.ml) that is built on top of the low-level binding. The high-level binding is exposed via the manually written xed.ml, that adds some convenience functions and shadows some of the auto-generated bindings with more ergonomic replacements.

Example

#require "xedbindings";;
open Xedbindings.Xed;;
(* state64 is convenience; you could make one yourself with State.init2 Enum.LONG_64 Enum.A64b *)
let xedd = decode state64 "\x55" |> ok_exn;;
let () = DecodedInst.get_reg xedd Enum.REG0 |> Enum.reg_to_string |> print_endline;; (* "RBP" *)
let () = DecodedInst.inst xedd |> Inst.iform_enum |> Enum.iform_to_iclass_string_att |> print_endline;; (* "PUSH" *)
(* DecodedInst.format is a special wrapper for xed_format_generic. *)
let () = DecodedInst.format ~syntax:Enum.ATT xedd 0xdeadbeefL |> print_endline;; (* "pushq  %rbp" *)

Also see test/test.ml.

Updates

This library may slightly break backwards-compatibility of its API on any minor version update. For example, these incompatibilities may include:

  • Minor type changes or function renames for better OCaml ergonomics
  • Upstream XED updates (that don't broadly break stuff)

Future work

  • Optional bindings for the "enc2" encoder.
  • Custom high-level OCaml to mirror XED's high-level encoding API (which is not currently exposed by this binding).
  • Determine what further parts of XED are excluded from the binding, and possibly complete the binding.