769cd6b011fef05daa066fb092727be39ac0778f
[gnome.gobject-introspection] / girepository / girffi.c
1 /* GObject introspection: Helper functions for ffi integration
2  *
3  * Copyright (C) 2008 Red Hat, Inc
4  * Copyright (C) 2005 Matthias Clasen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <sys/types.h>
23 #include <sys/mman.h>
24
25 #include <config.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "girffi.h"
30 #include "girffi-private.h"
31 #include "girepository.h"
32
33 ffi_type *
34 g_ir_ffi_get_ffi_type (GITypeTag   tag,
35                        gboolean    is_pointer)
36 {
37   switch (tag)
38     {
39     case GI_TYPE_TAG_BOOLEAN:
40       return &ffi_type_uint;
41     case GI_TYPE_TAG_INT8:
42       return &ffi_type_sint8;
43     case GI_TYPE_TAG_UINT8:
44       return &ffi_type_uint8;
45     case GI_TYPE_TAG_INT16:
46       return &ffi_type_sint16;
47     case GI_TYPE_TAG_UINT16:
48       return &ffi_type_uint16;
49     case GI_TYPE_TAG_INT32:
50       return &ffi_type_sint32;
51     case GI_TYPE_TAG_UINT32:
52       return &ffi_type_uint32;
53     case GI_TYPE_TAG_INT64:
54       return &ffi_type_sint64;
55     case GI_TYPE_TAG_UINT64:
56       return &ffi_type_uint64;
57     case GI_TYPE_TAG_SHORT:
58       return &ffi_type_sshort;
59     case GI_TYPE_TAG_USHORT:
60       return &ffi_type_ushort;
61     case GI_TYPE_TAG_INT:
62       return &ffi_type_sint;
63     case GI_TYPE_TAG_UINT:
64       return &ffi_type_uint;
65     case GI_TYPE_TAG_SSIZE:
66 #if GLIB_SIZEOF_SIZE_T == 4
67       return &ffi_type_sint32;
68 #elif GLIB_SIZEOF_SIZE_T == 8
69       return &ffi_type_sint64;
70 #else
71 #  error "Unexpected size for size_t: not 4 or 8"
72 #endif
73     case GI_TYPE_TAG_LONG:
74       return &ffi_type_slong;
75     case GI_TYPE_TAG_SIZE:
76     case GI_TYPE_TAG_GTYPE:
77 #if GLIB_SIZEOF_SIZE_T == 4
78       return &ffi_type_uint32;
79 #elif GLIB_SIZEOF_SIZE_T == 8
80       return &ffi_type_uint64;
81 #else
82 #  error "Unexpected size for size_t: not 4 or 8"
83 #endif
84     case GI_TYPE_TAG_TIME_T:
85 #if SIZEOF_TIME_T == 4
86       return &ffi_type_sint32;
87 #elif SIZEOF_TIME_T == 8
88       return &ffi_type_sint64;
89 #else
90 #  error "Unexpected size for time_t: not 4 or 8"
91 #endif
92     case GI_TYPE_TAG_ULONG:
93       return &ffi_type_ulong;
94     case GI_TYPE_TAG_FLOAT:
95       return &ffi_type_float;
96     case GI_TYPE_TAG_DOUBLE:
97       return &ffi_type_double;
98     case GI_TYPE_TAG_UTF8:
99     case GI_TYPE_TAG_FILENAME:
100     case GI_TYPE_TAG_ARRAY:
101     case GI_TYPE_TAG_INTERFACE:
102     case GI_TYPE_TAG_GLIST:
103     case GI_TYPE_TAG_GSLIST:
104     case GI_TYPE_TAG_GHASH:
105     case GI_TYPE_TAG_ERROR:
106       return &ffi_type_pointer;
107     case GI_TYPE_TAG_VOID:
108       if (is_pointer)
109         return &ffi_type_pointer;
110       else
111         return &ffi_type_void;
112     }
113
114   g_assert_not_reached ();
115
116   return NULL;
117 }  
118
119 /**
120  * g_type_info_get_ffi_type:
121  * @info: A #GITypeInfo
122  *
123  * Returns: A #ffi_type corresponding to the platform default C ABI for @info.
124  */
125 ffi_type *
126 g_type_info_get_ffi_type (GITypeInfo *info)
127 {
128   return g_ir_ffi_get_ffi_type (g_type_info_get_tag (info), g_type_info_is_pointer (info));
129 }
130
131 /**
132  * g_callable_info_get_ffi_arg_types:
133  * @callable_info: a callable info from a typelib
134  *
135  * Return value: an array of ffi_type*. The array itself
136  * should be freed using g_free() after use.
137  */
138 static ffi_type **
139 g_callable_info_get_ffi_arg_types (GICallableInfo *callable_info)
140 {
141     ffi_type **arg_types;
142     gint n_args, i;
143     
144     g_return_val_if_fail (callable_info != NULL, NULL);
145
146     n_args = g_callable_info_get_n_args (callable_info);
147     
148     arg_types = (ffi_type **) g_new0 (ffi_type *, n_args + 1);
149     
150     for (i = 0; i < n_args; ++i)
151       {
152         GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
153         GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
154         arg_types[i] = g_type_info_get_ffi_type (arg_type);
155         g_base_info_unref ((GIBaseInfo *)arg_info);
156         g_base_info_unref ((GIBaseInfo *)arg_type);
157       }
158     arg_types[n_args] = NULL;
159
160     return arg_types;
161 }
162
163 /**
164  * g_callable_info_get_ffi_return_type:
165  * @callable_info: a callable info from a typelib
166  *
167  * Fetches the ffi_type for a corresponding return value of
168  * a #GICallableInfo
169  * Return value: the ffi_type for the return value
170  */
171 static ffi_type *
172 g_callable_info_get_ffi_return_type (GICallableInfo *callable_info)
173 {
174   GITypeInfo *return_type;
175   GITypeTag type_tag;
176   ffi_type *return_ffi_type;
177
178   g_return_val_if_fail (callable_info != NULL, NULL);
179
180   return_type = g_callable_info_get_return_type (callable_info);
181   type_tag = g_type_info_get_tag (return_type);
182   return_ffi_type = g_type_info_get_ffi_type (return_type);
183   g_base_info_unref((GIBaseInfo*)return_type);
184   
185   return return_ffi_type;
186 }
187
188 /**
189  * g_function_info_prep_invoker:
190  * @info: A #GIFunctionInfo
191  * @invoker: Output invoker structure
192  * @error: A #GError
193  *
194  * Initialize the caller-allocated @invoker structure with a cache
195  * of information needed to invoke the C function corresponding to
196  * @info with the platform's default ABI.
197  *
198  * A primary intent of this function is that a dynamic structure allocated
199  * by a language binding could contain a #GIFunctionInvoker structure
200  * inside the binding's function mapping.
201  */
202 gboolean
203 g_function_info_prep_invoker (GIFunctionInfo       *info,
204                               GIFunctionInvoker    *invoker,
205                               GError              **error)
206 {
207   const char *symbol;
208   ffi_type *rtype;
209   ffi_type **atypes;
210   GITypeInfo *tinfo;
211   GIArgInfo *ainfo;
212   gboolean is_method;
213   gboolean throws;
214   gint n_args, n_invoke_args, i;
215   
216   g_return_val_if_fail (info != NULL, FALSE);
217   g_return_val_if_fail (invoker != NULL, FALSE);
218   
219   symbol = g_function_info_get_symbol ((GIFunctionInfo*) info);
220   
221   if (!g_typelib_symbol (g_base_info_get_typelib((GIBaseInfo *) info),
222                          symbol, &(invoker->native_address)))
223     {
224       g_set_error (error,
225                    G_INVOKE_ERROR,
226                    G_INVOKE_ERROR_SYMBOL_NOT_FOUND,
227                    "Could not locate %s: %s", symbol, g_module_error ());
228
229       return FALSE;
230     }
231
232   is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0
233     && (g_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0;
234   throws = g_function_info_get_flags (info) & GI_FUNCTION_THROWS;
235
236   tinfo = g_callable_info_get_return_type ((GICallableInfo *)info);
237   rtype = g_type_info_get_ffi_type (tinfo);
238   g_base_info_unref ((GIBaseInfo *)tinfo);
239
240   n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
241   if (is_method)
242     n_invoke_args = n_args+1;
243   else
244     n_invoke_args = n_args;
245
246   if (throws)
247     /* Add an argument for the GError */
248     n_invoke_args ++;
249
250   /* TODO: avoid malloc here? */
251   atypes = g_malloc0 (sizeof (ffi_type*) * n_invoke_args);
252   
253   if (is_method)
254     {
255       atypes[0] = &ffi_type_pointer;
256     }
257   for (i = 0; i < n_args; i++)
258     {
259       int offset = (is_method ? 1 : 0);
260       ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i);
261       switch (g_arg_info_get_direction (ainfo))
262         {
263           case GI_DIRECTION_IN:
264             tinfo = g_arg_info_get_type (ainfo);
265             atypes[i+offset] = g_type_info_get_ffi_type (tinfo);
266             g_base_info_unref ((GIBaseInfo *)tinfo);
267             break;
268           case GI_DIRECTION_OUT:
269           case GI_DIRECTION_INOUT:
270             atypes[i+offset] = &ffi_type_pointer;
271             break;
272           default:
273             g_assert_not_reached ();
274         }
275       g_base_info_unref ((GIBaseInfo *)ainfo);
276     }
277
278   if (throws)
279     {
280       atypes[n_invoke_args - 1] = &ffi_type_pointer;
281     }
282
283   return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) == FFI_OK;
284 }
285
286 /**
287  * g_function_info_invoker_destroy:
288  * @invoker: A #GIFunctionInvoker
289  * 
290  * Release all resources allocated for the internals of @invoker; callers
291  * are responsible for freeing any resources allocated for the structure
292  * itself however.
293  */
294 void
295 g_function_invoker_destroy (GIFunctionInvoker    *invoker)
296 {
297   g_free (invoker->cif.arg_types);
298 }
299
300 /**
301  * g_callable_info_prepare_closure:
302  * @callable_info: a callable info from a typelib
303  * @cif: a ffi_cif structure
304  * @callback: the ffi callback
305  * @user_data: data to be passed into the callback
306  *
307  * Prepares a callback for ffi invocation.
308  *
309  * Note: this function requires the heap to be executable, which
310  *       might not function properly on systems with SELinux enabled.
311  *
312  * Return value: the ffi_closure or NULL on error.
313  * The return value should be freed by calling g_callable_info_prepare_closure().
314  */
315 ffi_closure *
316 g_callable_info_prepare_closure (GICallableInfo       *callable_info,
317                                  ffi_cif              *cif,
318                                  GIFFIClosureCallback  callback,
319                                  gpointer              user_data)
320 {
321   ffi_closure *closure;
322   ffi_status status;
323     
324   g_return_val_if_fail (callable_info != NULL, FALSE);
325   g_return_val_if_fail (cif != NULL, FALSE);
326   g_return_val_if_fail (callback != NULL, FALSE);
327     
328   closure = mmap (NULL, sizeof (ffi_closure),
329                   PROT_EXEC | PROT_READ | PROT_WRITE,
330                   MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE));
331   if (!closure)
332     {
333       g_warning("mmap failed: %s\n", strerror(errno));
334       return NULL;
335     }
336
337   status = ffi_prep_cif (cif, FFI_DEFAULT_ABI,
338                          g_callable_info_get_n_args (callable_info),
339                          g_callable_info_get_ffi_return_type (callable_info),
340                          g_callable_info_get_ffi_arg_types (callable_info));
341   if (status != FFI_OK)
342     {
343       g_warning("ffi_prep_cif failed: %d\n", status);
344       munmap(closure, sizeof (closure));
345       return NULL;
346     }
347
348   status = ffi_prep_closure (closure, cif, callback, user_data);
349   if (status != FFI_OK)
350     {
351       g_warning ("ffi_prep_closure failed: %d\n", status);
352       munmap(closure, sizeof (closure));
353       return NULL;
354     }
355
356   if (mprotect(closure, sizeof (closure), PROT_READ | PROT_EXEC) == -1)
357     {
358       g_warning ("ffi_prep_closure failed: %s\n", strerror(errno));
359       munmap(closure, sizeof (closure));
360       return NULL;
361     }
362   
363   return closure;
364 }
365
366 /**
367  * g_callable_info_free_closure:
368  * @callable_info: a callable info from a typelib
369  * @closure: ffi closure
370  *
371  * Frees a ffi_closure returned from g_callable_info_prepare_closure()
372  */
373 void
374 g_callable_info_free_closure (GICallableInfo *callable_info,
375                               ffi_closure    *closure)
376 {
377   munmap(closure, sizeof (closure));
378 }