Home | History | Annotate | Line # | Download | only in guile
scm-safe-call.c revision 1.1
      1  1.1  christos /* GDB/Scheme support for safe calls into the Guile interpreter.
      2  1.1  christos 
      3  1.1  christos    Copyright (C) 2014-2015 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    This file is part of GDB.
      6  1.1  christos 
      7  1.1  christos    This program is free software; you can redistribute it and/or modify
      8  1.1  christos    it under the terms of the GNU General Public License as published by
      9  1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10  1.1  christos    (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos    This program is distributed in the hope that it will be useful,
     13  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1  christos    GNU General Public License for more details.
     16  1.1  christos 
     17  1.1  christos    You should have received a copy of the GNU General Public License
     18  1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19  1.1  christos 
     20  1.1  christos /* See README file in this directory for implementation notes, coding
     21  1.1  christos    conventions, et.al.  */
     22  1.1  christos 
     23  1.1  christos #include "defs.h"
     24  1.1  christos #include "filenames.h"
     25  1.1  christos #include "guile-internal.h"
     26  1.1  christos 
     27  1.1  christos /* Struct to marshall args to scscm_safe_call_body.  */
     28  1.1  christos 
     29  1.1  christos struct c_data
     30  1.1  christos {
     31  1.1  christos   void *(*func) (void *);
     32  1.1  christos   void *data;
     33  1.1  christos   /* An error message or NULL for success.  */
     34  1.1  christos   void *result;
     35  1.1  christos };
     36  1.1  christos 
     37  1.1  christos /* Struct to marshall args through gdbscm_with_catch.  */
     38  1.1  christos 
     39  1.1  christos struct with_catch_data
     40  1.1  christos {
     41  1.1  christos   scm_t_catch_body func;
     42  1.1  christos   void *data;
     43  1.1  christos   scm_t_catch_handler unwind_handler;
     44  1.1  christos   scm_t_catch_handler pre_unwind_handler;
     45  1.1  christos 
     46  1.1  christos   /* If EXCP_MATCHER is non-NULL, it is an excp_matcher_func function.
     47  1.1  christos      If the exception is recognized by it, the exception is recorded as is,
     48  1.1  christos      without wrapping it in gdb:with-stack.  */
     49  1.1  christos   excp_matcher_func *excp_matcher;
     50  1.1  christos 
     51  1.1  christos   SCM stack;
     52  1.1  christos   SCM catch_result;
     53  1.1  christos };
     54  1.1  christos 
     55  1.1  christos /* The "body" argument to scm_i_with_continuation_barrier.
     56  1.1  christos    Invoke the user-supplied function.  */
     57  1.1  christos 
     58  1.1  christos static SCM
     59  1.1  christos scscm_safe_call_body (void *d)
     60  1.1  christos {
     61  1.1  christos   struct c_data *data = (struct c_data *) d;
     62  1.1  christos 
     63  1.1  christos   data->result = data->func (data->data);
     64  1.1  christos 
     65  1.1  christos   return SCM_UNSPECIFIED;
     66  1.1  christos }
     67  1.1  christos 
     68  1.1  christos /* A "pre-unwind handler" to scm_c_catch that prints the exception
     69  1.1  christos    according to "set guile print-stack".  */
     70  1.1  christos 
     71  1.1  christos static SCM
     72  1.1  christos scscm_printing_pre_unwind_handler (void *data, SCM key, SCM args)
     73  1.1  christos {
     74  1.1  christos   SCM stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
     75  1.1  christos 
     76  1.1  christos   gdbscm_print_exception_with_stack (SCM_BOOL_F, stack, key, args);
     77  1.1  christos 
     78  1.1  christos   return SCM_UNSPECIFIED;
     79  1.1  christos }
     80  1.1  christos 
     81  1.1  christos /* A no-op unwind handler.  */
     82  1.1  christos 
     83  1.1  christos static SCM
     84  1.1  christos scscm_nop_unwind_handler (void *data, SCM key, SCM args)
     85  1.1  christos {
     86  1.1  christos   return SCM_UNSPECIFIED;
     87  1.1  christos }
     88  1.1  christos 
     89  1.1  christos /* The "pre-unwind handler" to scm_c_catch that records the exception
     90  1.1  christos    for possible later printing.  We do this in the pre-unwind handler because
     91  1.1  christos    we want the stack to include point where the exception occurred.
     92  1.1  christos 
     93  1.1  christos    If DATA is non-NULL, it is an excp_matcher_func function.
     94  1.1  christos    If the exception is recognized by it, the exception is recorded as is,
     95  1.1  christos    without wrapping it in gdb:with-stack.  */
     96  1.1  christos 
     97  1.1  christos static SCM
     98  1.1  christos scscm_recording_pre_unwind_handler (void *datap, SCM key, SCM args)
     99  1.1  christos {
    100  1.1  christos   struct with_catch_data *data = datap;
    101  1.1  christos   excp_matcher_func *matcher = data->excp_matcher;
    102  1.1  christos 
    103  1.1  christos   if (matcher != NULL && matcher (key))
    104  1.1  christos     return SCM_UNSPECIFIED;
    105  1.1  christos 
    106  1.1  christos   /* There's no need to record the whole stack if we're not going to print it.
    107  1.1  christos      However, convention is to still print the stack frame in which the
    108  1.1  christos      exception occurred, even if we're not going to print a full backtrace.
    109  1.1  christos      For now, keep it simple.  */
    110  1.1  christos 
    111  1.1  christos   data->stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
    112  1.1  christos 
    113  1.1  christos   /* IWBN if we could return the <gdb:exception> here and skip the unwind
    114  1.1  christos      handler, but it doesn't work that way.  If we want to return a
    115  1.1  christos      <gdb:exception> object from the catch it needs to come from the unwind
    116  1.1  christos      handler.  So what we do is save the stack for later use by the unwind
    117  1.1  christos      handler.  */
    118  1.1  christos 
    119  1.1  christos   return SCM_UNSPECIFIED;
    120  1.1  christos }
    121  1.1  christos 
    122  1.1  christos /* Part two of the recording unwind handler.
    123  1.1  christos    Here we take the stack saved from the pre-unwind handler and create
    124  1.1  christos    the <gdb:exception> object.  */
    125  1.1  christos 
    126  1.1  christos static SCM
    127  1.1  christos scscm_recording_unwind_handler (void *datap, SCM key, SCM args)
    128  1.1  christos {
    129  1.1  christos   struct with_catch_data *data = datap;
    130  1.1  christos 
    131  1.1  christos   /* We need to record the stack in the exception since we're about to
    132  1.1  christos      throw and lose the location that got the exception.  We do this by
    133  1.1  christos      wrapping the exception + stack in a new exception.  */
    134  1.1  christos 
    135  1.1  christos   if (gdbscm_is_true (data->stack))
    136  1.1  christos     return gdbscm_make_exception_with_stack (key, args, data->stack);
    137  1.1  christos 
    138  1.1  christos   return gdbscm_make_exception (key, args);
    139  1.1  christos }
    140  1.1  christos 
    141  1.1  christos /* Ugh. :-(
    142  1.1  christos    Guile doesn't export scm_i_with_continuation_barrier which is exactly
    143  1.1  christos    what we need.  To cope, have our own wrapper around scm_c_catch and
    144  1.1  christos    pass this as the "body" argument to scm_c_with_continuation_barrier.
    145  1.1  christos    Darn darn darn.  */
    146  1.1  christos 
    147  1.1  christos static void *
    148  1.1  christos gdbscm_with_catch (void *data)
    149  1.1  christos {
    150  1.1  christos   struct with_catch_data *d = data;
    151  1.1  christos 
    152  1.1  christos   d->catch_result
    153  1.1  christos     = scm_c_catch (SCM_BOOL_T,
    154  1.1  christos 		   d->func, d->data,
    155  1.1  christos 		   d->unwind_handler, d,
    156  1.1  christos 		   d->pre_unwind_handler, d);
    157  1.1  christos 
    158  1.1  christos   return NULL;
    159  1.1  christos }
    160  1.1  christos 
    161  1.1  christos /* A wrapper around scm_with_guile that prints backtraces and exceptions
    162  1.1  christos    according to "set guile print-stack".
    163  1.1  christos    The result if NULL if no exception occurred, otherwise it is a statically
    164  1.1  christos    allocated error message (caller must *not* free).  */
    165  1.1  christos 
    166  1.1  christos void *
    167  1.1  christos gdbscm_with_guile (void *(*func) (void *), void *data)
    168  1.1  christos {
    169  1.1  christos   struct c_data c_data;
    170  1.1  christos   struct with_catch_data catch_data;
    171  1.1  christos 
    172  1.1  christos   c_data.func = func;
    173  1.1  christos   c_data.data = data;
    174  1.1  christos   /* Set this now in case an exception is thrown.  */
    175  1.1  christos   c_data.result = _("Error while executing Scheme code.");
    176  1.1  christos 
    177  1.1  christos   catch_data.func = scscm_safe_call_body;
    178  1.1  christos   catch_data.data = &c_data;
    179  1.1  christos   catch_data.unwind_handler = scscm_nop_unwind_handler;
    180  1.1  christos   catch_data.pre_unwind_handler = scscm_printing_pre_unwind_handler;
    181  1.1  christos   catch_data.excp_matcher = NULL;
    182  1.1  christos   catch_data.stack = SCM_BOOL_F;
    183  1.1  christos   catch_data.catch_result = SCM_UNSPECIFIED;
    184  1.1  christos 
    185  1.1  christos   scm_with_guile (gdbscm_with_catch, &catch_data);
    186  1.1  christos 
    187  1.1  christos   return c_data.result;
    188  1.1  christos }
    189  1.1  christos 
    190  1.1  christos /* Another wrapper of scm_with_guile for use by the safe call/apply routines
    191  1.1  christos    in this file, as well as for general purpose calling other functions safely.
    192  1.1  christos    For these we want to record the exception, but leave the possible printing
    193  1.1  christos    of it to later.  */
    194  1.1  christos 
    195  1.1  christos SCM
    196  1.1  christos gdbscm_call_guile (SCM (*func) (void *), void *data,
    197  1.1  christos 		   excp_matcher_func *ok_excps)
    198  1.1  christos {
    199  1.1  christos   struct with_catch_data catch_data;
    200  1.1  christos 
    201  1.1  christos   catch_data.func = func;
    202  1.1  christos   catch_data.data = data;
    203  1.1  christos   catch_data.unwind_handler = scscm_recording_unwind_handler;
    204  1.1  christos   catch_data.pre_unwind_handler = scscm_recording_pre_unwind_handler;
    205  1.1  christos   catch_data.excp_matcher = ok_excps;
    206  1.1  christos   catch_data.stack = SCM_BOOL_F;
    207  1.1  christos   catch_data.catch_result = SCM_UNSPECIFIED;
    208  1.1  christos 
    209  1.1  christos #if 0
    210  1.1  christos   scm_c_with_continuation_barrier (gdbscm_with_catch, &catch_data);
    211  1.1  christos #else
    212  1.1  christos   scm_with_guile (gdbscm_with_catch, &catch_data);
    213  1.1  christos #endif
    214  1.1  christos 
    215  1.1  christos   return catch_data.catch_result;
    216  1.1  christos }
    217  1.1  christos 
    218  1.1  christos /* Utilities to safely call Scheme code, catching all exceptions, and
    220  1.1  christos    preventing continuation capture.
    221  1.1  christos    The result is the result of calling the function, or if an exception occurs
    222  1.1  christos    then the result is a <gdb:exception> smob, which can be tested for with
    223  1.1  christos    gdbscm_is_exception.  */
    224  1.1  christos 
    225  1.1  christos /* Helper for gdbscm_safe_call_0.  */
    226  1.1  christos 
    227  1.1  christos static SCM
    228  1.1  christos scscm_call_0_body (void *argsp)
    229  1.1  christos {
    230  1.1  christos   SCM *args = argsp;
    231  1.1  christos 
    232  1.1  christos   return scm_call_0 (args[0]);
    233  1.1  christos }
    234  1.1  christos 
    235  1.1  christos SCM
    236  1.1  christos gdbscm_safe_call_0 (SCM proc, excp_matcher_func *ok_excps)
    237  1.1  christos {
    238  1.1  christos   SCM args[] = { proc };
    239  1.1  christos 
    240  1.1  christos   return gdbscm_call_guile (scscm_call_0_body, args, ok_excps);
    241  1.1  christos }
    242  1.1  christos 
    243  1.1  christos /* Helper for gdbscm_safe_call_1.  */
    244  1.1  christos 
    245  1.1  christos static SCM
    246  1.1  christos scscm_call_1_body (void *argsp)
    247  1.1  christos {
    248  1.1  christos   SCM *args = argsp;
    249  1.1  christos 
    250  1.1  christos   return scm_call_1 (args[0], args[1]);
    251  1.1  christos }
    252  1.1  christos 
    253  1.1  christos SCM
    254  1.1  christos gdbscm_safe_call_1 (SCM proc, SCM arg0, excp_matcher_func *ok_excps)
    255  1.1  christos {
    256  1.1  christos   SCM args[] = { proc, arg0 };
    257  1.1  christos 
    258  1.1  christos   return gdbscm_call_guile (scscm_call_1_body, args, ok_excps);
    259  1.1  christos }
    260  1.1  christos 
    261  1.1  christos /* Helper for gdbscm_safe_call_2.  */
    262  1.1  christos 
    263  1.1  christos static SCM
    264  1.1  christos scscm_call_2_body (void *argsp)
    265  1.1  christos {
    266  1.1  christos   SCM *args = argsp;
    267  1.1  christos 
    268  1.1  christos   return scm_call_2 (args[0], args[1], args[2]);
    269  1.1  christos }
    270  1.1  christos 
    271  1.1  christos SCM
    272  1.1  christos gdbscm_safe_call_2 (SCM proc, SCM arg0, SCM arg1, excp_matcher_func *ok_excps)
    273  1.1  christos {
    274  1.1  christos   SCM args[] = { proc, arg0, arg1 };
    275  1.1  christos 
    276  1.1  christos   return gdbscm_call_guile (scscm_call_2_body, args, ok_excps);
    277  1.1  christos }
    278  1.1  christos 
    279  1.1  christos /* Helper for gdbscm_safe_call_3.  */
    280  1.1  christos 
    281  1.1  christos static SCM
    282  1.1  christos scscm_call_3_body (void *argsp)
    283  1.1  christos {
    284  1.1  christos   SCM *args = argsp;
    285  1.1  christos 
    286  1.1  christos   return scm_call_3 (args[0], args[1], args[2], args[3]);
    287  1.1  christos }
    288  1.1  christos 
    289  1.1  christos SCM
    290  1.1  christos gdbscm_safe_call_3 (SCM proc, SCM arg1, SCM arg2, SCM arg3,
    291  1.1  christos 		    excp_matcher_func *ok_excps)
    292  1.1  christos {
    293  1.1  christos   SCM args[] = { proc, arg1, arg2, arg3 };
    294  1.1  christos 
    295  1.1  christos   return gdbscm_call_guile (scscm_call_3_body, args, ok_excps);
    296  1.1  christos }
    297  1.1  christos 
    298  1.1  christos /* Helper for gdbscm_safe_call_4.  */
    299  1.1  christos 
    300  1.1  christos static SCM
    301  1.1  christos scscm_call_4_body (void *argsp)
    302  1.1  christos {
    303  1.1  christos   SCM *args = argsp;
    304  1.1  christos 
    305  1.1  christos   return scm_call_4 (args[0], args[1], args[2], args[3], args[4]);
    306  1.1  christos }
    307  1.1  christos 
    308  1.1  christos SCM
    309  1.1  christos gdbscm_safe_call_4 (SCM proc, SCM arg1, SCM arg2, SCM arg3, SCM arg4,
    310  1.1  christos 		    excp_matcher_func *ok_excps)
    311  1.1  christos {
    312  1.1  christos   SCM args[] = { proc, arg1, arg2, arg3, arg4 };
    313  1.1  christos 
    314  1.1  christos   return gdbscm_call_guile (scscm_call_4_body, args, ok_excps);
    315  1.1  christos }
    316  1.1  christos 
    317  1.1  christos /* Helper for gdbscm_safe_apply_1.  */
    318  1.1  christos 
    319  1.1  christos static SCM
    320  1.1  christos scscm_apply_1_body (void *argsp)
    321  1.1  christos {
    322  1.1  christos   SCM *args = argsp;
    323  1.1  christos 
    324  1.1  christos   return scm_apply_1 (args[0], args[1], args[2]);
    325  1.1  christos }
    326  1.1  christos 
    327  1.1  christos SCM
    328  1.1  christos gdbscm_safe_apply_1 (SCM proc, SCM arg0, SCM rest, excp_matcher_func *ok_excps)
    329  1.1  christos {
    330  1.1  christos   SCM args[] = { proc, arg0, rest };
    331  1.1  christos 
    332  1.1  christos   return gdbscm_call_guile (scscm_apply_1_body, args, ok_excps);
    333  1.1  christos }
    334  1.1  christos 
    335  1.1  christos /* Utilities to call Scheme code, not catching exceptions, and
    337  1.1  christos    not preventing continuation capture.
    338  1.1  christos    The result is the result of calling the function.
    339  1.1  christos    If an exception occurs then Guile is left to handle the exception,
    340  1.1  christos    unwinding the stack as appropriate.
    341  1.1  christos 
    342  1.1  christos    USE THESE WITH CARE.
    343  1.1  christos    Typically these are called from functions that implement Scheme procedures,
    344  1.1  christos    and we don't want to catch the exception; otherwise it will get printed
    345  1.1  christos    twice: once when first caught and once if it ends up being rethrown and the
    346  1.1  christos    rethrow reaches the top repl, which will confuse the user.
    347  1.1  christos 
    348  1.1  christos    While these calls just pass the call off to the corresponding Guile
    349  1.1  christos    procedure, all such calls are routed through these ones to:
    350  1.1  christos    a) provide a place to put hooks or whatnot in if we need to,
    351  1.1  christos    b) add "unsafe" to the name to alert the reader.  */
    352  1.1  christos 
    353  1.1  christos SCM
    354  1.1  christos gdbscm_unsafe_call_1 (SCM proc, SCM arg0)
    355  1.1  christos {
    356  1.1  christos   return scm_call_1 (proc, arg0);
    357  1.1  christos }
    358  1.1  christos 
    359  1.1  christos /* Utilities for safely evaluating a Scheme expression string.  */
    361  1.1  christos 
    362  1.1  christos struct eval_scheme_string_data
    363  1.1  christos {
    364  1.1  christos   const char *string;
    365  1.1  christos   int display_result;
    366  1.1  christos };
    367  1.1  christos 
    368  1.1  christos /* Wrapper to eval a C string in the Guile interpreter.
    369  1.1  christos    This is passed to gdbscm_with_guile.  */
    370  1.1  christos 
    371  1.1  christos static void *
    372  1.1  christos scscm_eval_scheme_string (void *datap)
    373  1.1  christos {
    374  1.1  christos   struct eval_scheme_string_data *data = datap;
    375  1.1  christos   SCM result = scm_c_eval_string (data->string);
    376  1.1  christos 
    377  1.1  christos   if (data->display_result && !scm_is_eq (result, SCM_UNSPECIFIED))
    378  1.1  christos     {
    379  1.1  christos       SCM port = scm_current_output_port ();
    380  1.1  christos 
    381  1.1  christos       scm_write (result, port);
    382  1.1  christos       scm_newline (port);
    383  1.1  christos     }
    384  1.1  christos 
    385  1.1  christos   /* If we get here the eval succeeded.  */
    386  1.1  christos   return NULL;
    387  1.1  christos }
    388  1.1  christos 
    389  1.1  christos /* Evaluate EXPR in the Guile interpreter, catching all exceptions
    390  1.1  christos    and preventing continuation capture.
    391  1.1  christos    The result is NULL if no exception occurred.  Otherwise, the exception is
    392  1.1  christos    printed according to "set guile print-stack" and the result is an error
    393  1.1  christos    message allocated with malloc, caller must free.  */
    394  1.1  christos 
    395  1.1  christos char *
    396  1.1  christos gdbscm_safe_eval_string (const char *string, int display_result)
    397  1.1  christos {
    398  1.1  christos   struct eval_scheme_string_data data = { string, display_result };
    399  1.1  christos   void *result;
    400  1.1  christos 
    401  1.1  christos   result = gdbscm_with_guile (scscm_eval_scheme_string, (void *) &data);
    402  1.1  christos 
    403  1.1  christos   if (result != NULL)
    404  1.1  christos     return xstrdup (result);
    405  1.1  christos   return NULL;
    406  1.1  christos }
    407  1.1  christos 
    408  1.1  christos /* Utilities for safely loading Scheme scripts.  */
    410  1.1  christos 
    411  1.1  christos /* Helper function for gdbscm_safe_source_scheme_script.  */
    412  1.1  christos 
    413  1.1  christos static void *
    414  1.1  christos scscm_source_scheme_script (void *data)
    415  1.1  christos {
    416  1.1  christos   const char *filename = data;
    417  1.1  christos 
    418  1.1  christos   /* The Guile docs don't specify what the result is.
    419  1.1  christos      Maybe it's SCM_UNSPECIFIED, but the docs should specify that. :-) */
    420  1.1  christos   scm_c_primitive_load_path (filename);
    421  1.1  christos 
    422  1.1  christos   /* If we get here the load succeeded.  */
    423  1.1  christos   return NULL;
    424  1.1  christos }
    425  1.1  christos 
    426  1.1  christos /* Try to load a script, catching all exceptions,
    427  1.1  christos    and preventing continuation capture.
    428  1.1  christos    The result is NULL if the load succeeded.  Otherwise, the exception is
    429  1.1  christos    printed according to "set guile print-stack" and the result is an error
    430  1.1  christos    message allocated with malloc, caller must free.  */
    431  1.1  christos 
    432  1.1  christos char *
    433  1.1  christos gdbscm_safe_source_script (const char *filename)
    434  1.1  christos {
    435  1.1  christos   /* scm_c_primitive_load_path only looks in %load-path for files with
    436  1.1  christos      relative paths.  An alternative could be to temporarily add "." to
    437  1.1  christos      %load-path, but we don't want %load-path to be searched.  At least not
    438  1.1  christos      by default.  This function is invoked by the "source" GDB command which
    439  1.1  christos      already has its own path search support.  */
    440  1.1  christos   char *abs_filename = NULL;
    441  1.1  christos   void *result;
    442  1.1  christos 
    443  1.1  christos   if (!IS_ABSOLUTE_PATH (filename))
    444  1.1  christos     {
    445  1.1  christos       abs_filename = gdb_realpath (filename);
    446  1.1  christos       filename = abs_filename;
    447  1.1  christos     }
    448  1.1  christos 
    449  1.1  christos   result = gdbscm_with_guile (scscm_source_scheme_script,
    450  1.1  christos 			      (void *) filename);
    451  1.1  christos 
    452  1.1  christos   xfree (abs_filename);
    453  1.1  christos   if (result != NULL)
    454  1.1  christos     return xstrdup (result);
    455  1.1  christos   return NULL;
    456  1.1  christos }
    457  1.1  christos 
    458  1.1  christos /* Utility for entering an interactive Guile repl.  */
    460  1.1  christos 
    461  1.1  christos void
    462  1.1  christos gdbscm_enter_repl (void)
    463  1.1  christos {
    464                  /* It's unfortunate to have to resort to something like this, but
    465                     scm_shell doesn't return.  :-(  I found this code on guile-user@.  */
    466                  gdbscm_safe_call_1 (scm_c_public_ref ("system repl repl", "start-repl"),
    467                		      scm_from_latin1_symbol ("scheme"), NULL);
    468                }
    469