[PINGv2][PATCH v3] gdb: Introduce RAII signal handler setter

Guinevere Larsen guinevere@redhat.com
Wed Sep 25 15:34:42 GMT 2024


Ping :)

On 9/16/24 10:30 AM, Guinevere Larsen wrote:
> Ping :)
>
> On 8/27/24 7:52 AM, Guinevere Larsen wrote:
>> This patch is motivated by the wait function for the record-full target,
>> that would install a custom signal handler for SIGINT, but could throw
>> an exception and never reset the SIGINT handler.  This is clearly a bad
>> idea, so this patch introduces the class scoped_signal_handler in a new
>> .h file.  The file is added to gdbsupport, even though only gdb code is
>> using it, because it feels like an addition that would be useful for
>> more than just directly gdb.
>>
>> There are 3 places where this class can just be dropped in,
>> gdb/record-full.c, gdb/utils.c and gdb/extension.c. This third place
>> already had a specialized RAII signal handler setter, but it is
>> substituted for the new general purpose one.
>> ---
>>   gdb/extension.c                    | 21 ++----------
>>   gdb/record-full.c                  |  5 ++-
>>   gdb/utils.c                        |  7 ++--
>>   gdbsupport/scoped_signal_handler.h | 52 ++++++++++++++++++++++++++++++
>>   4 files changed, 58 insertions(+), 27 deletions(-)
>>   create mode 100644 gdbsupport/scoped_signal_handler.h
>>
>> diff --git a/gdb/extension.c b/gdb/extension.c
>> index c488fc77494..b1396928456 100644
>> --- a/gdb/extension.c
>> +++ b/gdb/extension.c
>> @@ -33,6 +33,7 @@
>>   #include "guile/guile.h"
>>   #include <array>
>>   #include "inferior.h"
>> +#include "gdbsupport/scoped_signal_handler.h"
>>     static script_sourcer_func source_gdb_script;
>>   static objfile_script_sourcer_func source_gdb_objfile_script;
>> @@ -297,27 +298,9 @@ ext_lang_auto_load_enabled (const struct 
>> extension_language_defn *extlang)
>>   }
>>   

>>   -/* RAII class used to temporarily return SIG to its default 
>> handler.  */
>> -
>> -template<int SIG>
>> -struct scoped_default_signal
>> -{
>> -  scoped_default_signal ()
>> -  { m_old_sig_handler = signal (SIG, SIG_DFL); }
>> -
>> -  ~scoped_default_signal ()
>> -  { signal (SIG, m_old_sig_handler); }
>> -
>> -  DISABLE_COPY_AND_ASSIGN (scoped_default_signal);
>> -
>> -private:
>> -  /* The previous signal handler that needs to be restored.  */
>> -  sighandler_t m_old_sig_handler;
>> -};
>> -
>>   /* Class to temporarily return SIGINT to its default handler. */
>>   -using scoped_default_sigint = scoped_default_signal<SIGINT>;
>> +using scoped_default_sigint = scoped_signal_handler(SIGINT, SIG_DFL);
>>     /* Functions that iterate over all extension languages.
>>      These only iterate over external extension languages, not including
>> diff --git a/gdb/record-full.c b/gdb/record-full.c
>> index ab854e0133f..91667d425f3 100644
>> --- a/gdb/record-full.c
>> +++ b/gdb/record-full.c
>> @@ -39,6 +39,7 @@
>>   #include "infrun.h"
>>   #include "gdbsupport/gdb_unlinker.h"
>>   #include "gdbsupport/byte-vector.h"
>> +#include "gdbsupport/scoped_signal_handler.h"
>>   #include "async-event.h"
>>   #include "top.h"
>>   #include "valprint.h"
>> @@ -1150,6 +1151,7 @@ record_full_wait_1 (struct target_ops *ops,
>>   {
>>     scoped_restore restore_operation_disable
>>       = record_full_gdb_operation_disable_set ();
>> +  scoped_signal_handler interrupt_handler(SIGINT, 
>> record_full_sig_handler);
>>       if (record_debug)
>>       gdb_printf (gdb_stdlog,
>> @@ -1170,7 +1172,6 @@ record_full_wait_1 (struct target_ops *ops,
>>       }
>>       record_full_get_sig = 0;
>> -  signal (SIGINT, record_full_sig_handler);
>>       record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
>>   @@ -1459,8 +1460,6 @@ record_full_wait_1 (struct target_ops *ops,
>>       }
>>       }
>>   -  signal (SIGINT, handle_sigint);
>> -
>>     return inferior_ptid;
>>   }
>>   diff --git a/gdb/utils.c b/gdb/utils.c
>> index 94310300fb5..4cff0b2b141 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -19,6 +19,7 @@
>>     #include <ctype.h>
>>   #include "gdbsupport/gdb_wait.h"
>> +#include "gdbsupport/scoped_signal_handler.h"
>>   #include "event-top.h"
>>   #include "gdbthread.h"
>>   #include "fnmatch.h"
>> @@ -3424,9 +3425,7 @@ wait_to_die_with_timeout (pid_t pid, int 
>> *status, int timeout)
>>         sa.sa_flags = 0;
>>         sigaction (SIGALRM, &sa, &old_sa);
>>   #else
>> -      sighandler_t ofunc;
>> -
>> -      ofunc = signal (SIGALRM, sigalrm_handler);
>> +      scoped_signal_handler alarm_restore(SIGALRM, sigalrm_handler);
>>   #endif
>>           alarm (timeout);
>> @@ -3438,8 +3437,6 @@ wait_to_die_with_timeout (pid_t pid, int 
>> *status, int timeout)
>>         alarm (0);
>>   #if defined (HAVE_SIGACTION) && defined (SA_RESTART)
>>         sigaction (SIGALRM, &old_sa, NULL);
>> -#else
>> -      signal (SIGALRM, ofunc);
>>   #endif
>>   #endif
>>       }
>> diff --git a/gdbsupport/scoped_signal_handler.h 
>> b/gdbsupport/scoped_signal_handler.h
>> new file mode 100644
>> index 00000000000..4b5c8bb67e7
>> --- /dev/null
>> +++ b/gdbsupport/scoped_signal_handler.h
>> @@ -0,0 +1,52 @@
>> +/* RAII class to install a separate handler for a given signal
>> +
>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see 
>> <http://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef SCOPED_SIGNAL_HANDLER_H
>> +#define SCOPED_SIGNAL_HANDLER_H
>> +
>> +#include <signal.h>
>> +
>> +class scoped_signal_handler
>> +{
>> +public:
>> +  scoped_signal_handler (int sig, sighandler_t handler)
>> +    : m_sig(sig)
>> +  {
>> +    /* The return of the function call is the previous signal 
>> handler, or
>> +       SIG_ERR if the function doesn't succeed.  */
>> +    m_prev_handler = signal (sig, handler);
>> +    /* According to the GNU libc manual, the only way signal fails 
>> is if
>> +       the signum given is invalid, so we should be safe to assert.  */
>> +    gdb_assert (m_prev_handler != SIG_ERR);
>> +  }
>> +
>> +  ~scoped_signal_handler ()
>> +  {
>> +    /* No need to save previous handler, and per the comment on the 
>> previous
>> +       assert, there should be no way this call fails here.  */
>> +    signal (m_sig, m_prev_handler);
>> +  }
>> +
>> +  DISABLE_COPY_AND_ASSIGN (scoped_signal_handler);
>> +private:
>> +  sighandler_t m_prev_handler;
>> +  int m_sig;
>> +};
>> +
>> +#endif /* SCOPED_SIGNAL_HANDLER_H  */
>
>

-- 
Cheers,
Guinevere Larsen
She/Her/Hers



More information about the Gdb-patches mailing list