[ocaml-ctypes] Logging function calls

Thomas Braibant thomas.braibant at gmail.com
Mon Sep 15 10:01:11 BST 2014


Hi Jeremy,

Thanks for your reply. Your proposal is quite close to what I had in
mind. Yet, I am a bit puzzled about the dereferencing of the pointer
in format_val. Shouldn't we test if it is the null-pointer before
doing that? In that case, is testing if p = Ctypes.null the preferred
way to do that? (I spotted that pattern somewhere in memory.ml I
think.)

Regarding my other use case, what I miss is a way to tag a view (with
the identity coercion both way) with a name, and be able to use that
name to pick the right pretty printer (for flags, and so on). That
would be a tiny bit more convenient than reading the integer value of
(FLAG_BAR | FLAG_FOO) in my log, but I can cope with that.

Best,
Thomas


On Sat, Sep 13, 2014 at 1:20 PM, Jeremy Yallop <yallop at gmail.com> wrote:
> 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