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