[ocaml-ctypes] Logging function calls

Jeremy Yallop yallop at gmail.com
Sat Sep 13 12:20:25 BST 2014


On 12 September 2014 10:15, Thomas Braibant <thomas.braibant at gmail.com> wrote:
> I would like to log function calls using something like the following code:
>
> let rec log:
> type a. a fn -> a -> a =
>     function
>     | Static.Returns ty ->
>        fun result ->
>        Printf.printf "<- %s\n%!" (string_of ty result);
>        result
>     | Static.Function (ty, fn) ->
>        fun f x ->
>        Printf.printf "-> %s\n%!" (string_of ty x);
>        log fn (f x)
>
> This works beautifully for simple enough function arguments. However,
> I would also like to display a bit more than what is currently
> available.
> Two quick examples come to mind.
>
> First, printing the name of manifest constants (e.g., defined in C
> using #define FOO 0x0001337). I would like to log FOO rather than its
> integer value. If I provide a correct printing function, it might even
> produces correct C code.
>
> Second, a bit more akward, printing the content of structs that are
> passed by reference to functions. I do not see a way to print that
> information as valid C, but it would be tremendously useful in my
> logs.

I think that you can do what you want by matching a little deeper on
"ty".  Here's a function that prints C values, dereferencing
pointers-to-structures rather than just printing their addresses:

  let rec format_val : type a. a typ -> Format.formatter -> a -> unit =
    fun t fmt -> let open Static in match t with
    | Pointer (Struct _ as s) ->
       fun v -> Format.fprintf fmt "pointer to %a" (format_val s) !@v
    | t -> Ctypes.format t fmt

You can then call format_val instead of string_of inside your log function:

  let rec log:
    type a. a fn -> a -> a =
      function
      | Static.Returns ty ->
         fun result ->
         Format.(fprintf std_formatter) "<- @[%a@]@\n%!" (format_val ty) result;
         result
      | Static.Function (ty, fn) ->
         fun f x ->
         Format.(fprintf std_formatter) "-> @[%a@]@\n%!" (format_val ty) x;
         log fn (f x)

Here are the results, logging the results of passing the address of an
uninitialized struct to the identity function:

   # let s = structure "s";;
   val s : '_a structure typ = struct s
   # let i = field s "i" int;;
   val i : (int, ('_a, [ `Struct ]) structured) field = <abstr>
   # let j = field s "j" float;;
   val j : (float, ('_a, [ `Struct ]) structured) field = <abstr>
   # let () = seal s;;
   # let v = make s;;
   val v : ('_a, [ `Struct ]) structured = {
       i = -486857096, j = 4.5857492245e-41
     }
   # log (ptr s @-> returning (ptr s)) (fun x -> x) (addr v);;
   -> pointer to { i = -486857096, j = 4.5857492245e-41  }
   <- pointer to { i = -486857096, j = 4.5857492245e-41  }
   - : '_a structure ptr = (struct s*) 0x95fc40


More information about the Ctypes mailing list