123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961 |
- /* Interface between gdb and its extension languages.
- Copyright (C) 2014-2022 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/>. */
- /* Note: With few exceptions, external functions and variables in this file
- have "ext_lang" in the name, and no other symbol in gdb does. */
- #include "defs.h"
- #include <signal.h>
- #include "target.h"
- #include "auto-load.h"
- #include "breakpoint.h"
- #include "event-top.h"
- #include "extension.h"
- #include "extension-priv.h"
- #include "observable.h"
- #include "cli/cli-script.h"
- #include "python/python.h"
- #include "guile/guile.h"
- #include <array>
- static script_sourcer_func source_gdb_script;
- static objfile_script_sourcer_func source_gdb_objfile_script;
- /* GDB's own scripting language.
- This exists, in part, to support auto-loading ${prog}-gdb.gdb scripts. */
- static const struct extension_language_script_ops
- extension_language_gdb_script_ops =
- {
- source_gdb_script,
- source_gdb_objfile_script,
- NULL, /* objfile_script_executor */
- auto_load_gdb_scripts_enabled
- };
- const struct extension_language_defn extension_language_gdb =
- {
- EXT_LANG_GDB,
- "gdb",
- "GDB",
- /* We fall back to interpreting a script as a GDB script if it doesn't
- match the other scripting languages, but for consistency's sake
- give it a formal suffix. */
- ".gdb",
- "-gdb.gdb",
- /* cli_control_type: This is never used: GDB's own scripting language
- has a variety of control types (if, while, etc.). */
- commands_control,
- &extension_language_gdb_script_ops,
- /* The rest of the extension language interface isn't supported by GDB's own
- extension/scripting language. */
- NULL
- };
- /* NULL-terminated table of all external (non-native) extension languages.
- The order of appearance in the table is important.
- When multiple extension languages provide the same feature, for example
- a pretty-printer for a particular type, which one gets used?
- The algorithm employed here is "the first one wins". For example, in
- the case of pretty-printers this means the first one to provide a
- pretty-printed value is the one that is used. This algorithm is employed
- throughout. */
- static const std::array<const extension_language_defn *, 2> extension_languages
- {
- /* To preserve existing behaviour, python should always appear first. */
- &extension_language_python,
- &extension_language_guile,
- };
- /* Return a pointer to the struct extension_language_defn object of
- extension language LANG.
- This always returns a non-NULL pointer, even if support for the language
- is not compiled into this copy of GDB. */
- const struct extension_language_defn *
- get_ext_lang_defn (enum extension_language lang)
- {
- gdb_assert (lang != EXT_LANG_NONE);
- if (lang == EXT_LANG_GDB)
- return &extension_language_gdb;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->language == lang)
- return extlang;
- }
- gdb_assert_not_reached ("unable to find extension_language_defn");
- }
- /* Return TRUE if FILE has extension EXTENSION. */
- static int
- has_extension (const char *file, const char *extension)
- {
- int file_len = strlen (file);
- int extension_len = strlen (extension);
- return (file_len > extension_len
- && strcmp (&file[file_len - extension_len], extension) == 0);
- }
- /* Return the extension language of FILE, or NULL if
- the extension language of FILE is not recognized.
- This is done by looking at the file's suffix. */
- const struct extension_language_defn *
- get_ext_lang_of_file (const char *file)
- {
- if (has_extension (file, extension_language_gdb.suffix))
- return &extension_language_gdb;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (has_extension (file, extlang->suffix))
- return extlang;
- }
- return NULL;
- }
- /* Return non-zero if support for the specified extension language
- is compiled in. */
- int
- ext_lang_present_p (const struct extension_language_defn *extlang)
- {
- return extlang->script_ops != NULL;
- }
- /* Return non-zero if the specified extension language has successfully
- initialized. */
- int
- ext_lang_initialized_p (const struct extension_language_defn *extlang)
- {
- if (extlang->ops != NULL)
- {
- /* This method is required. */
- gdb_assert (extlang->ops->initialized != NULL);
- return extlang->ops->initialized (extlang);
- }
- return 0;
- }
- /* Throw an error indicating EXTLANG is not supported in this copy of GDB. */
- void
- throw_ext_lang_unsupported (const struct extension_language_defn *extlang)
- {
- error (_("Scripting in the \"%s\" language is not supported"
- " in this copy of GDB."),
- ext_lang_capitalized_name (extlang));
- }
- /* Methods for GDB's own extension/scripting language. */
- /* The extension_language_script_ops.script_sourcer "method". */
- static void
- source_gdb_script (const struct extension_language_defn *extlang,
- FILE *stream, const char *file)
- {
- script_from_file (stream, file);
- }
- /* The extension_language_script_ops.objfile_script_sourcer "method". */
- static void
- source_gdb_objfile_script (const struct extension_language_defn *extlang,
- struct objfile *objfile,
- FILE *stream, const char *file)
- {
- script_from_file (stream, file);
- }
- /* Accessors for "public" attributes of struct extension_language. */
- /* Return the "name" field of EXTLANG. */
- const char *
- ext_lang_name (const struct extension_language_defn *extlang)
- {
- return extlang->name;
- }
- /* Return the "capitalized_name" field of EXTLANG. */
- const char *
- ext_lang_capitalized_name (const struct extension_language_defn *extlang)
- {
- return extlang->capitalized_name;
- }
- /* Return the "suffix" field of EXTLANG. */
- const char *
- ext_lang_suffix (const struct extension_language_defn *extlang)
- {
- return extlang->suffix;
- }
- /* Return the "auto_load_suffix" field of EXTLANG. */
- const char *
- ext_lang_auto_load_suffix (const struct extension_language_defn *extlang)
- {
- return extlang->auto_load_suffix;
- }
- /* extension_language_script_ops wrappers. */
- /* Return the script "sourcer" function for EXTLANG.
- This is the function that loads and processes a script.
- If support for this language isn't compiled in, NULL is returned. */
- script_sourcer_func *
- ext_lang_script_sourcer (const struct extension_language_defn *extlang)
- {
- if (extlang->script_ops == NULL)
- return NULL;
- /* The extension language is required to implement this function. */
- gdb_assert (extlang->script_ops->script_sourcer != NULL);
- return extlang->script_ops->script_sourcer;
- }
- /* Return the objfile script "sourcer" function for EXTLANG.
- This is the function that loads and processes a script for a particular
- objfile.
- If support for this language isn't compiled in, NULL is returned. */
- objfile_script_sourcer_func *
- ext_lang_objfile_script_sourcer (const struct extension_language_defn *extlang)
- {
- if (extlang->script_ops == NULL)
- return NULL;
- /* The extension language is required to implement this function. */
- gdb_assert (extlang->script_ops->objfile_script_sourcer != NULL);
- return extlang->script_ops->objfile_script_sourcer;
- }
- /* Return the objfile script "executor" function for EXTLANG.
- This is the function that executes a script for a particular objfile.
- If support for this language isn't compiled in, NULL is returned.
- The extension language is not required to implement this function. */
- objfile_script_executor_func *
- ext_lang_objfile_script_executor
- (const struct extension_language_defn *extlang)
- {
- if (extlang->script_ops == NULL)
- return NULL;
- return extlang->script_ops->objfile_script_executor;
- }
- /* See extension.h. */
- bool
- ext_lang_auto_load_enabled (const struct extension_language_defn *extlang)
- {
- if (extlang->script_ops == NULL)
- return false;
- /* The extension language is required to implement this function. */
- gdb_assert (extlang->script_ops->auto_load_enabled != NULL);
- return extlang->script_ops->auto_load_enabled (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>;
- /* Functions that iterate over all extension languages.
- These only iterate over external extension languages, not including
- GDB's own extension/scripting language, unless otherwise indicated. */
- /* Wrapper to call the extension_language_ops.initialize "method" for each
- compiled-in extension language. */
- void
- ext_lang_initialization (void)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->ops->initialize != NULL)
- {
- scoped_default_sigint set_sigint_to_default_handler;
- extlang->ops->initialize (extlang);
- }
- }
- }
- /* Invoke the appropriate extension_language_ops.eval_from_control_command
- method to perform CMD, which is a list of commands in an extension language.
- This function is what implements, for example:
- python
- print 42
- end
- in a GDB script. */
- void
- eval_ext_lang_from_control_command (struct command_line *cmd)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->cli_control_type == cmd->control_type)
- {
- if (extlang->ops != NULL
- && extlang->ops->eval_from_control_command != NULL)
- {
- extlang->ops->eval_from_control_command (extlang, cmd);
- return;
- }
- /* The requested extension language is not supported in this GDB. */
- throw_ext_lang_unsupported (extlang);
- }
- }
- gdb_assert_not_reached ("unknown extension language in command_line");
- }
- /* Search for and load scripts for OBJFILE written in extension languages.
- This includes GDB's own scripting language.
- This function is what implements the loading of OBJFILE-gdb.py and
- OBJFILE-gdb.gdb. */
- void
- auto_load_ext_lang_scripts_for_objfile (struct objfile *objfile)
- {
- const struct extension_language_defn *gdb = &extension_language_gdb;
- if (ext_lang_auto_load_enabled (gdb))
- auto_load_objfile_script (objfile, gdb);
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && ext_lang_auto_load_enabled (extlang))
- auto_load_objfile_script (objfile, extlang);
- }
- }
- /* Interface to type pretty-printers implemented in an extension language. */
- /* Call this at the start when preparing to pretty-print a type.
- The result is a pointer to an opaque object (to the caller) to be passed
- to apply_ext_lang_type_printers and free_ext_lang_type_printers.
- We don't know in advance which extension language will provide a
- pretty-printer for the type, so all are initialized. */
- ext_lang_type_printers::ext_lang_type_printers ()
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->ops->start_type_printers != NULL)
- extlang->ops->start_type_printers (extlang, this);
- }
- }
- /* Iteratively try the type pretty-printers specified by PRINTERS
- according to the standard search order (specified by extension_languages),
- returning the result of the first one that succeeds.
- If there was an error, or if no printer succeeds, then NULL is returned. */
- char *
- apply_ext_lang_type_printers (struct ext_lang_type_printers *printers,
- struct type *type)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- char *result = NULL;
- enum ext_lang_rc rc;
- if (extlang->ops == nullptr
- || extlang->ops->apply_type_printers == NULL)
- continue;
- rc = extlang->ops->apply_type_printers (extlang, printers, type,
- &result);
- switch (rc)
- {
- case EXT_LANG_RC_OK:
- gdb_assert (result != NULL);
- return result;
- case EXT_LANG_RC_ERROR:
- return NULL;
- case EXT_LANG_RC_NOP:
- break;
- default:
- gdb_assert_not_reached ("bad return from apply_type_printers");
- }
- }
- return NULL;
- }
- ext_lang_type_printers::~ext_lang_type_printers ()
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->ops->free_type_printers != NULL)
- extlang->ops->free_type_printers (extlang, this);
- }
- }
- /* Try to pretty-print a value onto stdio stream STREAM according to
- OPTIONS. VAL is the object to print. Returns non-zero if the
- value was successfully pretty-printed.
- Extension languages are tried in the order specified by
- extension_languages. The first one to provide a pretty-printed
- value "wins".
- If an error is encountered in a pretty-printer, no further extension
- languages are tried.
- Note: This is different than encountering a memory error trying to read a
- value for pretty-printing. Here we're referring to, e.g., programming
- errors that trigger an exception in the extension language. */
- int
- apply_ext_lang_val_pretty_printer (struct value *val,
- struct ui_file *stream, int recurse,
- const struct value_print_options *options,
- const struct language_defn *language)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- enum ext_lang_rc rc;
- if (extlang->ops == nullptr
- || extlang->ops->apply_val_pretty_printer == NULL)
- continue;
- rc = extlang->ops->apply_val_pretty_printer (extlang, val, stream,
- recurse, options, language);
- switch (rc)
- {
- case EXT_LANG_RC_OK:
- return 1;
- case EXT_LANG_RC_ERROR:
- return 0;
- case EXT_LANG_RC_NOP:
- break;
- default:
- gdb_assert_not_reached ("bad return from apply_val_pretty_printer");
- }
- }
- return 0;
- }
- /* GDB access to the "frame filter" feature.
- FRAME is the source frame to start frame-filter invocation. FLAGS is an
- integer holding the flags for printing. The following elements of
- the FRAME_FILTER_FLAGS enum denotes the make-up of FLAGS:
- PRINT_LEVEL is a flag indicating whether to print the frame's
- relative level in the output. PRINT_FRAME_INFO is a flag that
- indicates whether this function should print the frame
- information, PRINT_ARGS is a flag that indicates whether to print
- frame arguments, and PRINT_LOCALS, likewise, with frame local
- variables. ARGS_TYPE is an enumerator describing the argument
- format, OUT is the output stream to print. FRAME_LOW is the
- beginning of the slice of frames to print, and FRAME_HIGH is the
- upper limit of the frames to count. Returns EXT_LANG_BT_ERROR on error,
- or EXT_LANG_BT_COMPLETED on success.
- Extension languages are tried in the order specified by
- extension_languages. The first one to provide a filter "wins".
- If there is an error (EXT_LANG_BT_ERROR) it is reported immediately
- rather than trying filters in other extension languages. */
- enum ext_lang_bt_status
- apply_ext_lang_frame_filter (struct frame_info *frame,
- frame_filter_flags flags,
- enum ext_lang_frame_args args_type,
- struct ui_out *out,
- int frame_low, int frame_high)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- enum ext_lang_bt_status status;
- if (extlang->ops == nullptr
- || extlang->ops->apply_frame_filter == NULL)
- continue;
- status = extlang->ops->apply_frame_filter (extlang, frame, flags,
- args_type, out,
- frame_low, frame_high);
- /* We use the filters from the first extension language that has
- applicable filters. Also, an error is reported immediately
- rather than continue trying. */
- if (status != EXT_LANG_BT_NO_FILTERS)
- return status;
- }
- return EXT_LANG_BT_NO_FILTERS;
- }
- /* Update values held by the extension language when OBJFILE is discarded.
- New global types must be created for every such value, which must then be
- updated to use the new types.
- The function typically just iterates over all appropriate values and
- calls preserve_one_value for each one.
- COPIED_TYPES is used to prevent cycles / duplicates and is passed to
- preserve_one_value. */
- void
- preserve_ext_lang_values (struct objfile *objfile, htab_t copied_types)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->ops->preserve_values != NULL)
- extlang->ops->preserve_values (extlang, objfile, copied_types);
- }
- }
- /* If there is a stop condition implemented in an extension language for
- breakpoint B, return a pointer to the extension language's definition.
- Otherwise return NULL.
- If SKIP_LANG is not EXT_LANG_NONE, skip checking this language.
- This is for the case where we're setting a new condition: Only one
- condition is allowed, so when setting a condition for any particular
- extension language, we need to check if any other extension language
- already has a condition set. */
- const struct extension_language_defn *
- get_breakpoint_cond_ext_lang (struct breakpoint *b,
- enum extension_language skip_lang)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->language != skip_lang
- && extlang->ops->breakpoint_has_cond != NULL
- && extlang->ops->breakpoint_has_cond (extlang, b))
- return extlang;
- }
- return NULL;
- }
- /* Return whether a stop condition for breakpoint B says to stop.
- True is also returned if there is no stop condition for B. */
- int
- breakpoint_ext_lang_cond_says_stop (struct breakpoint *b)
- {
- enum ext_lang_bp_stop stop = EXT_LANG_BP_STOP_UNSET;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- /* There is a rule that a breakpoint can have at most one of any of a
- CLI or extension language condition. However, Python hacks in "finish
- breakpoints" on top of the "stop" check, so we have to call this for
- every language, even if we could first determine whether a "stop"
- method exists. */
- if (extlang->ops != nullptr
- && extlang->ops->breakpoint_cond_says_stop != NULL)
- {
- enum ext_lang_bp_stop this_stop
- = extlang->ops->breakpoint_cond_says_stop (extlang, b);
- if (this_stop != EXT_LANG_BP_STOP_UNSET)
- {
- /* Even though we have to check every extension language, only
- one of them can return yes/no (because only one of them
- can have a "stop" condition). */
- gdb_assert (stop == EXT_LANG_BP_STOP_UNSET);
- stop = this_stop;
- }
- }
- }
- return stop == EXT_LANG_BP_STOP_NO ? 0 : 1;
- }
- /* ^C/SIGINT support.
- This requires cooperation with the extension languages so the support
- is defined here. */
- /* This flag tracks quit requests when we haven't called out to an
- extension language. it also holds quit requests when we transition to
- an extension language that doesn't have cooperative SIGINT handling. */
- static int quit_flag;
- /* The current extension language we've called out to, or
- extension_language_gdb if there isn't one.
- This must be set everytime we call out to an extension language, and reset
- to the previous value when it returns. Note that the previous value may
- be a different (or the same) extension language. */
- static const struct extension_language_defn *active_ext_lang
- = &extension_language_gdb;
- /* Return the currently active extension language. */
- const struct extension_language_defn *
- get_active_ext_lang (void)
- {
- return active_ext_lang;
- }
- /* Install a SIGINT handler. */
- static void
- install_sigint_handler (const struct signal_handler *handler_state)
- {
- gdb_assert (handler_state->handler_saved);
- signal (SIGINT, handler_state->handler);
- }
- /* Install GDB's SIGINT handler, storing the previous version in *PREVIOUS.
- As a simple optimization, if the previous version was GDB's SIGINT handler
- then mark the previous handler as not having been saved, and thus it won't
- be restored. */
- static void
- install_gdb_sigint_handler (struct signal_handler *previous)
- {
- /* Save here to simplify comparison. */
- sighandler_t handle_sigint_for_compare = handle_sigint;
- previous->handler = signal (SIGINT, handle_sigint);
- if (previous->handler != handle_sigint_for_compare)
- previous->handler_saved = 1;
- else
- previous->handler_saved = 0;
- }
- #if GDB_SELF_TEST
- namespace selftests {
- void (*hook_set_active_ext_lang) () = nullptr;
- }
- #endif
- /* Set the currently active extension language to NOW_ACTIVE.
- The result is a pointer to a malloc'd block of memory to pass to
- restore_active_ext_lang.
- N.B. This function must be called every time we call out to an extension
- language, and the result must be passed to restore_active_ext_lang
- afterwards.
- If there is a pending SIGINT it is "moved" to the now active extension
- language, if it supports cooperative SIGINT handling (i.e., it provides
- {clear,set,check}_quit_flag methods). If the extension language does not
- support cooperative SIGINT handling, then the SIGINT is left queued and
- we require the non-cooperative extension language to call check_quit_flag
- at appropriate times.
- It is important for the extension language to call check_quit_flag if it
- installs its own SIGINT handler to prevent the situation where a SIGINT
- is queued on entry, extension language code runs for a "long" time possibly
- serving one or more SIGINTs, and then returns. Upon return, if
- check_quit_flag is not called, the original SIGINT will be thrown.
- Non-cooperative extension languages are free to install their own SIGINT
- handler but the original must be restored upon return, either itself
- or via restore_active_ext_lang. */
- struct active_ext_lang_state *
- set_active_ext_lang (const struct extension_language_defn *now_active)
- {
- #if GDB_SELF_TEST
- if (selftests::hook_set_active_ext_lang)
- selftests::hook_set_active_ext_lang ();
- #endif
- struct active_ext_lang_state *previous
- = XCNEW (struct active_ext_lang_state);
- previous->ext_lang = active_ext_lang;
- previous->sigint_handler.handler_saved = 0;
- active_ext_lang = now_active;
- if (target_terminal::is_ours ())
- {
- /* If the newly active extension language uses cooperative SIGINT
- handling then ensure GDB's SIGINT handler is installed. */
- if (now_active->language == EXT_LANG_GDB
- || now_active->ops->check_quit_flag != NULL)
- install_gdb_sigint_handler (&previous->sigint_handler);
- /* If there's a SIGINT recorded in the cooperative extension languages,
- move it to the new language, or save it in GDB's global flag if the
- newly active extension language doesn't use cooperative SIGINT
- handling. */
- if (check_quit_flag ())
- set_quit_flag ();
- }
- return previous;
- }
- /* Restore active extension language from PREVIOUS. */
- void
- restore_active_ext_lang (struct active_ext_lang_state *previous)
- {
- active_ext_lang = previous->ext_lang;
- if (target_terminal::is_ours ())
- {
- /* Restore the previous SIGINT handler if one was saved. */
- if (previous->sigint_handler.handler_saved)
- install_sigint_handler (&previous->sigint_handler);
- /* If there's a SIGINT recorded in the cooperative extension languages,
- move it to the new language, or save it in GDB's global flag if the
- newly active extension language doesn't use cooperative SIGINT
- handling. */
- if (check_quit_flag ())
- set_quit_flag ();
- }
- xfree (previous);
- }
- /* Set the quit flag.
- This only sets the flag in the currently active extension language.
- If the currently active extension language does not have cooperative
- SIGINT handling, then GDB's global flag is set, and it is up to the
- extension language to call check_quit_flag. The extension language
- is free to install its own SIGINT handler, but we still need to handle
- the transition. */
- void
- set_quit_flag (void)
- {
- if (active_ext_lang->ops != NULL
- && active_ext_lang->ops->set_quit_flag != NULL)
- active_ext_lang->ops->set_quit_flag (active_ext_lang);
- else
- {
- quit_flag = 1;
- /* Now wake up the event loop, or any interruptible_select. Do
- this after setting the flag, because signals on Windows
- actually run on a separate thread, and thus otherwise the
- main code could be woken up and find quit_flag still
- clear. */
- quit_serial_event_set ();
- }
- }
- /* Return true if the quit flag has been set, false otherwise.
- Note: The flag is cleared as a side-effect.
- The flag is checked in all extension languages that support cooperative
- SIGINT handling, not just the current one. This simplifies transitions. */
- int
- check_quit_flag (void)
- {
- int result = 0;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops != nullptr
- && extlang->ops->check_quit_flag != NULL)
- if (extlang->ops->check_quit_flag (extlang) != 0)
- result = 1;
- }
- /* This is written in a particular way to avoid races. */
- if (quit_flag)
- {
- /* No longer need to wake up the event loop or any
- interruptible_select. The caller handles the quit
- request. */
- quit_serial_event_clear ();
- quit_flag = 0;
- result = 1;
- }
- return result;
- }
- /* See extension.h. */
- void
- get_matching_xmethod_workers (struct type *type, const char *method_name,
- std::vector<xmethod_worker_up> *workers)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- enum ext_lang_rc rc;
- /* If an extension language does not support xmethods, ignore
- it. */
- if (extlang->ops == nullptr
- || extlang->ops->get_matching_xmethod_workers == NULL)
- continue;
- rc = extlang->ops->get_matching_xmethod_workers (extlang,
- type, method_name,
- workers);
- if (rc == EXT_LANG_RC_ERROR)
- error (_("Error while looking for matching xmethod workers "
- "defined in %s."), extlang->capitalized_name);
- }
- }
- /* See extension.h. */
- std::vector<type *>
- xmethod_worker::get_arg_types ()
- {
- std::vector<type *> type_array;
- ext_lang_rc rc = do_get_arg_types (&type_array);
- if (rc == EXT_LANG_RC_ERROR)
- error (_("Error while looking for arg types of a xmethod worker "
- "defined in %s."), m_extlang->capitalized_name);
- return type_array;
- }
- /* See extension.h. */
- struct type *
- xmethod_worker::get_result_type (value *object, gdb::array_view<value *> args)
- {
- type *result_type;
- ext_lang_rc rc = do_get_result_type (object, args, &result_type);
- if (rc == EXT_LANG_RC_ERROR)
- {
- error (_("Error while fetching result type of an xmethod worker "
- "defined in %s."), m_extlang->capitalized_name);
- }
- return result_type;
- }
- /* See extension.h. */
- gdb::optional<std::string>
- ext_lang_colorize (const std::string &filename, const std::string &contents)
- {
- gdb::optional<std::string> result;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops == nullptr
- || extlang->ops->colorize == nullptr)
- continue;
- result = extlang->ops->colorize (filename, contents);
- if (result.has_value ())
- return result;
- }
- return result;
- }
- /* See extension.h. */
- gdb::optional<std::string>
- ext_lang_colorize_disasm (const std::string &content, gdbarch *gdbarch)
- {
- gdb::optional<std::string> result;
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- if (extlang->ops == nullptr
- || extlang->ops->colorize_disasm == nullptr)
- continue;
- result = extlang->ops->colorize_disasm (content, gdbarch);
- if (result.has_value ())
- return result;
- }
- return result;
- }
- /* Called via an observer before gdb prints its prompt.
- Iterate over the extension languages giving them a chance to
- change the prompt. The first one to change the prompt wins,
- and no further languages are tried. */
- static void
- ext_lang_before_prompt (const char *current_gdb_prompt)
- {
- for (const struct extension_language_defn *extlang : extension_languages)
- {
- enum ext_lang_rc rc;
- if (extlang->ops == nullptr
- || extlang->ops->before_prompt == NULL)
- continue;
- rc = extlang->ops->before_prompt (extlang, current_gdb_prompt);
- switch (rc)
- {
- case EXT_LANG_RC_OK:
- case EXT_LANG_RC_ERROR:
- return;
- case EXT_LANG_RC_NOP:
- break;
- default:
- gdb_assert_not_reached ("bad return from before_prompt");
- }
- }
- }
- void _initialize_extension ();
- void
- _initialize_extension ()
- {
- gdb::observers::before_prompt.attach (ext_lang_before_prompt, "extension");
- }
|