This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v3 02/15] extension language API for GDB: extension.[ch]


This patch adds extension.h, extension.c and extension-priv.h.

extension.h provides the public API.
The enums that were in python.h have been moved here and any py_,PY_ part
of the name has been replaced to be non-python-specific.

extension-priv.h provides the "private" API.
This is what Python exports to GDB.

extension.c defines extension_language_gdb for GDB's own extension/scripting
language, and provides the functions GDB calls to call into an extension
language.

Changes from v2:
- new enum ext_lang_rc
- "methods" apply_type_printers, apply_val_printer, before_prompt updated
  to use it
- function breakpoint_has_ext_lang_cond renamed to get_breakpoint_cond_ext_lang

Changes from v1:
- I renamed the files from scripting.[ch] per suggestion
- more comments
- more consistent enum prefixes
  [I'm still leaving off prefixes of values carried over as is from Python.
   A later pass can add them.]

2013-12-24  Doug Evans  <xdje42@gmail.com>

	* Makefile.in (SFILES): Add extension.c.
	(HFILES_NO_SRCDIR): Add extension.h, extension-priv.h
	(COMMON_OBS): Add extension.o.
	* extension.h: New file.
	* extension-priv.h: New file.
	* extension.c: New file.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index be30dfd..838f27a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -733,7 +733,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
 	dwarf2-frame-tailcall.c \
 	elfread.c environ.c eval.c event-loop.c event-top.c \
-	exceptions.c expprint.c \
+	exceptions.c expprint.c extension.c \
 	f-exp.y f-lang.c f-typeprint.c f-valprint.c filesystem.c \
 	findcmd.c findvar.c frame.c frame-base.c frame-unwind.c \
 	gdbarch.c arch-utils.c gdb_bfd.c gdb_obstack.c \
@@ -820,6 +820,7 @@ tui/tui-windata.h tui/tui-data.h tui/tui-win.h tui/tui-stack.h \
 tui/tui-winsource.h tui/tui-regs.h tui/tui-io.h tui/tui-layout.h \
 tui/tui-source.h sol2-tdep.h gregset.h sh-tdep.h sh64-tdep.h \
 expression.h score-tdep.h gdb_select.h ser-tcp.h \
+extension.h extension-priv.h \
 build-id.h buildsym.h valprint.h \
 typeprint.h mi/mi-getopt.h mi/mi-parse.h mi/mi-console.h \
 mi/mi-out.h mi/mi-main.h mi/mi-common.h mi/mi-cmds.h linux-nat.h \
@@ -906,6 +907,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	infcmd.o infrun.o \
 	expprint.o environ.o stack.o thread.o \
 	exceptions.o \
+	extension.o \
 	filesystem.o \
 	filestuff.o \
 	inf-child.o \
diff --git a/gdb/extension.h b/gdb/extension.h
new file mode 100644
index 0000000..b80c5ff
--- /dev/null
+++ b/gdb/extension.h
@@ -0,0 +1,214 @@
+/* Interface between gdb and its extension languages.
+
+   Copyright (C) 2013 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 EXTENSION_H
+#define EXTENSION_H
+
+#include "mi/mi-cmds.h" /* For PRINT_NO_VALUES, etc.  */
+
+struct breakpoint;
+struct command_line;
+struct frame_info;
+struct language_defn;
+struct objfile;
+struct extension_language_defn;
+struct type;
+struct ui_file;
+struct ui_out;
+struct value;
+struct value_print_options;
+
+/* A function to load and process a script file.
+   The file has been opened and is ready to be read from the beginning.
+   Any exceptions are not caught, and are passed to the caller.  */
+typedef void script_sourcer_func (const struct extension_language_defn *,
+				  FILE *stream, const char *filename);
+
+/* A function to load and process a script for an objfile.
+   The file has been opened and is ready to be read from the beginning.
+   Any exceptions are not caught, and are passed to the caller.  */
+typedef void objfile_script_sourcer_func
+  (const struct extension_language_defn *,
+   struct objfile *, FILE *stream, const char *filename);
+
+/* Enum of each extension(/scripting) language.  */
+
+enum extension_language
+  {
+    EXT_LANG_NONE,
+    EXT_LANG_GDB,
+    EXT_LANG_PYTHON
+  };
+
+/* Extension language frame-filter status return values.  */
+
+enum ext_lang_bt_status
+  {
+    /* Return when an error has occurred in processing frame filters,
+       or when printing the stack.  */
+    EXT_LANG_BT_ERROR = -1,
+
+    /* Return from internal routines to indicate that the function
+       succeeded.  */
+    EXT_LANG_BT_OK = 1,
+
+    /* Return when the frame filter process is complete, and all
+       operations have succeeded.  */
+    EXT_LANG_BT_COMPLETED = 2,
+
+    /* Return when the frame filter process is complete, but there
+       were no filter registered and enabled to process.  */
+    EXT_LANG_BT_NO_FILTERS = 3
+  };
+
+/* Flags to pass to apply_extlang_frame_filter.  */
+
+enum frame_filter_flags
+  {
+    /* Set this flag if frame level is to be printed.  */
+    PRINT_LEVEL = 1,
+
+    /* Set this flag if frame information is to be printed.  */
+    PRINT_FRAME_INFO = 2,
+
+    /* Set this flag if frame arguments are to be printed.  */
+    PRINT_ARGS = 4,
+
+    /* Set this flag if frame locals are to be printed.  */
+    PRINT_LOCALS = 8,
+  };
+
+/* A choice of the different frame argument printing strategies that
+   can occur in different cases of frame filter instantiation.  */
+
+enum ext_lang_frame_args
+  {
+    /* Print no values for arguments when invoked from the MI. */
+    NO_VALUES = PRINT_NO_VALUES,
+
+    MI_PRINT_ALL_VALUES = PRINT_ALL_VALUES,
+
+    /* Print only simple values (what MI defines as "simple") for
+       arguments when invoked from the MI. */
+    MI_PRINT_SIMPLE_VALUES = PRINT_SIMPLE_VALUES,
+
+    /* Print only scalar values for arguments when invoked from the CLI. */
+    CLI_SCALAR_VALUES,
+
+    /* Print all values for arguments when invoked from the CLI. */
+    CLI_ALL_VALUES
+  };
+
+/* The possible results of
+   extension_language_ops.breakpoint_cond_says_stop.  */
+
+enum ext_lang_bp_stop
+  {
+    /* No "stop" condition is set.  */
+    EXT_LANG_BP_STOP_UNSET,
+
+    /* A "stop" condition is set, and it says "don't stop".  */
+    EXT_LANG_BP_STOP_NO,
+
+    /* A "stop" condition is set, and it says "stop".  */
+    EXT_LANG_BP_STOP_YES
+  };
+
+/* Table of type printers associated with the global typedef table.  */
+
+struct ext_lang_type_printers
+{
+  /* Type-printers from Python.  */
+  void *py_type_printers;
+};
+
+/* The interface for gdb's own extension(/scripting) language.  */
+extern const struct extension_language_defn extension_language_gdb;
+
+extern const struct extension_language_defn *get_ext_lang_defn
+  (enum extension_language lang);
+
+extern const struct extension_language_defn *get_ext_lang_of_file
+  (const char *file);
+
+extern int ext_lang_present_p (const struct extension_language_defn *);
+
+extern int ext_lang_initialized_p (const struct extension_language_defn *);
+
+extern void throw_ext_lang_unsupported
+  (const struct extension_language_defn *);
+
+/* Accessors for "public" attributes of the extension language definition.  */
+
+extern enum extension_language ext_lang_kind
+  (const struct extension_language_defn *);
+
+extern const char *ext_lang_name (const struct extension_language_defn *);
+
+extern const char *ext_lang_capitalized_name
+  (const struct extension_language_defn *);
+
+extern const char *ext_lang_suffix (const struct extension_language_defn *);
+
+extern const char *ext_lang_auto_load_suffix
+  (const struct extension_language_defn *);
+
+extern script_sourcer_func *ext_lang_script_sourcer
+  (const struct extension_language_defn *);
+
+extern objfile_script_sourcer_func *ext_lang_objfile_script_sourcer
+  (const struct extension_language_defn *);
+
+extern int ext_lang_auto_load_enabled (const struct extension_language_defn *);
+
+/* Wrappers for each extension language API function that iterate over all
+   extension languages.  */
+
+extern void finish_ext_lang_initialization (void);
+
+extern void eval_ext_lang_from_control_command (struct command_line *cmd);
+
+extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *);
+
+extern struct ext_lang_type_printers *start_ext_lang_type_printers (void);
+
+extern char *apply_ext_lang_type_printers (struct ext_lang_type_printers *,
+					   struct type *);
+
+extern void free_ext_lang_type_printers (struct ext_lang_type_printers *);
+
+extern int apply_ext_lang_val_pretty_printer
+  (struct type *type, const gdb_byte *valaddr,
+   int embedded_offset, CORE_ADDR address,
+   struct ui_file *stream, int recurse,
+   const struct value *val, const struct value_print_options *options,
+   const struct language_defn *language);
+
+extern enum ext_lang_bt_status apply_ext_lang_frame_filter
+  (struct frame_info *frame, int flags, enum ext_lang_frame_args args_type,
+   struct ui_out *out, int frame_low, int frame_high);
+
+extern void preserve_ext_lang_values (struct objfile *, htab_t copied_types);
+
+extern const struct extension_language_defn *get_breakpoint_cond_ext_lang
+  (struct breakpoint *b, enum extension_language skip_lang);
+
+extern int breakpoint_ext_lang_cond_says_stop (struct breakpoint *);
+
+#endif /* EXTENSION_H */
diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h
new file mode 100644
index 0000000..5455161
--- /dev/null
+++ b/gdb/extension-priv.h
@@ -0,0 +1,249 @@
+/* Private implementation details of interface between gdb and its
+   extension languages.
+
+   Copyright (C) 2013 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 EXTENSION_PRIV_H
+#define EXTENSION_PRIV_H
+
+#include "extension.h"
+
+/* The return code for some API calls.  */
+
+enum ext_lang_rc
+  {
+    /* The operation completed successfully.  */
+    EXT_LANG_RC_OK,
+
+    /* The operation was not performed (e.g., no pretty-printer).  */
+    EXT_LANG_RC_NOP,
+
+    /* There was an error (e.g., Python error while printing a value).
+       When an error occurs no further extension languages are tried.
+       This is to preserve existing behaviour, and because it's convenient
+       for Python developers.
+       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.  */
+    EXT_LANG_RC_ERROR
+  };
+
+/* High level description of an extension/scripting language.
+   An entry for each is compiled into GDB regardless of whether the support
+   is present.  This is done so that we can issue meaningful errors if the
+   support is not compiled in.  */
+
+struct extension_language_defn
+{
+  /* Enum of the extension language.  */
+  enum extension_language language;
+
+  /* The name of the extension language, lowercase.  E.g., python.  */
+  const char *name;
+
+  /* The capitalized name of the extension language.
+     For python this is "Python".  For gdb this is "GDB".  */
+  const char *capitalized_name;
+
+  /* The file suffix of this extension language.  E.g., ".py".  */
+  const char *suffix;
+
+  /* The suffix of per-objfile scripts to auto-load.
+     E.g., When the program loads libfoo.so, look for libfoo.so-gdb.py.  */
+  const char *auto_load_suffix;
+
+  /* We support embedding external extension language code in GDB's own
+     scripting language.  We do this by having a special command that begins
+     the extension language snippet, and terminate it with "end".
+     This specifies the control type used to implement this.  */
+  enum command_control_type cli_control_type;
+
+  /* A pointer to the "methods" to load scripts in this language,
+     or NULL if the support is not compiled into GDB.  */
+  const struct extension_language_script_ops *script_ops;
+
+  /* Either a pointer to the "methods" of the extension language interface
+     or NULL if the support is not compiled into GDB.
+     This is also NULL for GDB's own scripting language which is relatively
+     primitive, and doesn't provide these features.  */
+  const struct extension_language_ops *ops;
+};
+
+/* The interface for loading scripts from external extension languages,
+   as well as GDB's own scripting language.
+   All of these methods are required to be implemented.  */
+
+struct extension_language_script_ops
+{
+  /* Load a script.  This is called, e.g., via the "source" command.
+     If there's an error while processing the script this function may,
+     but is not required to, throw an error.  */
+  script_sourcer_func *script_sourcer;
+
+  /* Load a script attached to an objfile.
+     If there's an error while processing the script this function may,
+     but is not required to, throw an error.  */
+  objfile_script_sourcer_func *objfile_script_sourcer;
+
+  /* Return non-zero if auto-loading scripts in this extension language
+     is enabled.  */
+  int (*auto_load_enabled) (const struct extension_language_defn *);
+};
+
+/* The interface for making calls from GDB to an external extension
+   language.  This is for non-script-loading related functionality, like
+   pretty-printing, etc.  The reason these are separated out is GDB's own
+   scripting language makes use of extension_language_script_opts, but it
+   makes no use of these.  There is no (current) intention to split
+   extension_language_ops up any further.
+   All of these methods are optional and may be NULL, except where
+   otherwise indicated.  */
+
+struct extension_language_ops
+{
+  /* Called at the end of gdb initialization to give the extension language
+     an opportunity to finish up.  This is useful for things like adding
+     new commands where one has to wait until gdb itself is initialized.  */
+  void (*finish_initialization) (const struct extension_language_defn *);
+
+  /* Return non-zero if the extension language successfully initialized.
+     This method is required.  */
+  int (*initialized) (const struct extension_language_defn *);
+
+  /* Process a sequence of commands embedded in GDB's own scripting language.
+     E.g.,
+     python
+     print 42
+     end  */
+  void (*eval_from_control_command) (const struct extension_language_defn *,
+				     struct command_line *);
+
+  /* Type-printing support:
+     start_type_printers, apply_type_printers, free_type_printers.
+     These methods are optional and may be NULL, but if one of them is
+     implemented then they all must be.  */
+
+  /* Called before printing a type.  */
+  void (*start_type_printers) (const struct extension_language_defn *,
+			       struct ext_lang_type_printers *);
+
+  /* Try to pretty-print TYPE.  If successful the pretty-printed type is
+     stored in *PRETTIED_TYPE, and the caller must free it.
+     Returns EXT_LANG_RC_OK upon success, EXT_LANG_RC_NOP if the type
+     is not recognized, and EXT_LANG_RC_ERROR if an error was encountered.
+     This function has a bit of a funny name, since it actually applies
+     recognizers, but this seemed clearer given the start_type_printers
+     and free_type_printers functions.  */
+  enum ext_lang_rc (*apply_type_printers)
+    (const struct extension_language_defn *,
+     const struct ext_lang_type_printers *,
+     struct type *, char **prettied_type);
+
+  /* Called after a type has been printed to give the type pretty-printer
+     mechanism an opportunity to clean up.  */
+  void (*free_type_printers) (const struct extension_language_defn *,
+			      struct ext_lang_type_printers *);
+
+  /* Try to pretty-print a value of type TYPE located at VALADDR
+     + EMBEDDED_OFFSET, which came from the inferior at address ADDRESS
+     + EMBEDDED_OFFSET, onto stdio stream STREAM according to OPTIONS.
+     VAL is the whole object that came from ADDRESS.  VALADDR must point to
+     the head of VAL's contents buffer.
+     Returns EXT_LANG_RC_OK upon success, EXT_LANG_RC_NOP if the value
+     is not recognized, and EXT_LANG_RC_ERROR if an error was encountered.  */
+  enum ext_lang_rc (*apply_val_pretty_printer)
+    (const struct extension_language_defn *,
+     struct type *type, const gdb_byte *valaddr,
+     int embedded_offset, CORE_ADDR address,
+     struct ui_file *stream, int recurse,
+     const struct value *val, const struct value_print_options *options,
+     const struct language_defn *language);
+
+  /* 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 SCR_BT_ERROR on error,
+     or SCR_BT_COMPLETED on success.  */
+  enum ext_lang_bt_status (*apply_frame_filter)
+    (const struct extension_language_defn *,
+     struct frame_info *frame, int flags, enum ext_lang_frame_args args_type,
+     struct ui_out *out, int frame_low, int frame_high);
+
+  /* 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.
+     This 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_values) (const struct extension_language_defn *,
+			   struct objfile *objfile, htab_t copied_types);
+
+  /* Return non-zero if there is a stop condition for the breakpoint.
+     This is used to implement the restriction that a breakpoint may have
+     at most one condition.  */
+  int (*breakpoint_has_cond) (const struct extension_language_defn *,
+			      struct breakpoint *);
+
+  /* Return a value of enum ext_lang_bp_stop indicating if there is a stop
+     condition for the breakpoint, and if so whether the program should
+     stop.  This is called when the program has stopped at the specified
+     breakpoint.
+     While breakpoints can have at most one condition, this is called for
+     every extension language, even if another extension language has a
+     "stop" method: other kinds of breakpoints may be implemented using
+     this method, e.g., "finish breakpoints" in Python.  */
+  enum ext_lang_bp_stop (*breakpoint_cond_says_stop)
+    (const struct extension_language_defn *, struct breakpoint *);
+
+  /* The next three are used to connect gdb's SIGINT handling with the
+     extension language's.
+     These need not be implemented, but if one of them is implemented
+     then they all must be.  */
+
+  /* Clear the SIGINT indicator.  */
+  void (*clear_quit_flag) (const struct extension_language_defn *);
+
+  /* Set the SIGINT indicator.  */
+  void (*set_quit_flag) (const struct extension_language_defn *);
+
+  /* Return non-zero if a SIGINT has occurred.
+     This is expected to also clear the indicator.  */
+  int (*check_quit_flag) (const struct extension_language_defn *);
+
+  /* Called before gdb prints its prompt, giving extension languages an
+     opportunity to change it with set_prompt.
+     Returns EXT_LANG_RC_OK if the prompt was changed, EXT_LANG_RC_NOP if
+     the prompt was not changed, and EXT_LANG_RC_ERROR if an error was
+     encountered.
+     Extension languages are called in order, and once the prompt is
+     changed or an error occurs no further languages are called.  */
+  enum ext_lang_rc (*before_prompt) (const struct extension_language_defn *,
+				     const char *current_gdb_prompt);
+};
+
+#endif /* EXTENSION_PRIV_H */
diff --git a/gdb/extension.c b/gdb/extension.c
new file mode 100644
index 0000000..36537c6
--- /dev/null
+++ b/gdb/extension.c
@@ -0,0 +1,753 @@
+/* Interface between gdb and its extension languages.
+
+   Copyright (C) 2013 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 "auto-load.h"
+#include "breakpoint.h"
+#include "extension.h"
+#include "extension-priv.h"
+#include "observer.h"
+#include "cli/cli-script.h"
+#include "python/python.h"
+
+/* Iterate over all external extension languages, regardless of whether the
+   support has been compiled in or not.
+   This does not include GDB's own scripting language.  */
+
+#define ALL_EXTENSION_LANGUAGES(i, extlang) \
+  for (/*int*/ i = 0, extlang = extension_languages[0]; \
+       extlang != NULL; \
+       extlang = extension_languages[++i])
+
+/* Iterate over all external extension languages that are supported.
+   This does not include GDB's own scripting language.  */
+
+#define ALL_ENABLED_EXTENSION_LANGUAGES(i, extlang) \
+  for (/*int*/ i = 0, extlang = extension_languages[0]; \
+       extlang != NULL; \
+       extlang = extension_languages[++i]) \
+    if (extlang->ops != NULL)
+
+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,
+  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 struct extension_language_defn * const extension_languages[] =
+{
+  /* To preserve existing behaviour, python should always appear first.  */
+  &extension_language_python,
+  NULL
+};
+
+/* 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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  gdb_assert (lang != EXT_LANG_NONE);
+
+  if (lang == EXT_LANG_GDB)
+    return &extension_language_gdb;
+
+  ALL_EXTENSION_LANGUAGES (i, extlang)
+    {
+      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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_EXTENSION_LANGUAGES (i, extlang)
+    {
+      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 non-zero if auto-loading of EXTLANG scripts is enabled.
+   Zero is returned if support for this language isn't compiled in.  */
+
+int
+ext_lang_auto_load_enabled (const struct extension_language_defn *extlang)
+{
+  if (extlang->script_ops == NULL)
+    return 0;
+
+  /* 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);
+}
+
+/* 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.finish_initialization "method"
+   for each compiled-in extension language.  */
+
+void
+finish_ext_lang_initialization (void)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->ops->finish_initialization != NULL)
+	extlang->ops->finish_initialization (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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->cli_control_type == cmd->control_type)
+	{
+	  if (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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  extlang = &extension_language_gdb;
+  if (ext_lang_auto_load_enabled (extlang))
+    auto_load_objfile_script (objfile, extlang);
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (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.  */
+
+struct ext_lang_type_printers *
+start_ext_lang_type_printers (void)
+{
+  struct ext_lang_type_printers *printers
+    = XZALLOC (struct ext_lang_type_printers);
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->ops->start_type_printers != NULL)
+	extlang->ops->start_type_printers (extlang, printers);
+    }
+
+  return printers;
+}
+
+/* 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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      char *result = NULL;
+      enum ext_lang_rc rc;
+
+      if (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;
+}
+
+/* Call this after pretty-printing a type to release all memory held
+   by PRINTERS.  */
+
+void
+free_ext_lang_type_printers (struct ext_lang_type_printers *printers)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->ops->free_type_printers != NULL)
+	extlang->ops->free_type_printers (extlang, printers);
+    }
+
+  xfree (printers);
+}
+
+/* Try to pretty-print a value of type TYPE located at VALADDR
+   + EMBEDDED_OFFSET, which came from the inferior at address ADDRESS
+   + EMBEDDED_OFFSET, onto stdio stream STREAM according to OPTIONS.
+   VAL is the whole object that came from ADDRESS.  VALADDR must point to
+   the head of VAL's contents buffer.
+   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 type *type, const gdb_byte *valaddr,
+				   int embedded_offset, CORE_ADDR address,
+				   struct ui_file *stream, int recurse,
+				   const struct value *val,
+				   const struct value_print_options *options,
+				   const struct language_defn *language)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      enum ext_lang_rc rc;
+
+      if (extlang->ops->apply_val_pretty_printer == NULL)
+	continue;
+      rc = extlang->ops->apply_val_pretty_printer (extlang, type, valaddr,
+						   embedded_offset, address,
+						   stream, recurse, val,
+						   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, int flags,
+			     enum ext_lang_frame_args args_type,
+			     struct ui_out *out,
+			     int frame_low, int frame_high)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      enum ext_lang_bt_status status;
+
+      if (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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+  enum ext_lang_bp_stop stop = EXT_LANG_BP_STOP_UNSET;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      /* 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->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.
+   The prototypes for these are in defs.h.  */
+
+/* Nonzero means a quit has been requested.
+   This flag tracks quit requests but it's only used if the extension language
+   doesn't provide the necessary support.  */
+static int quit_flag;
+
+/* Clear the quit flag.  */
+
+void
+clear_quit_flag (void)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->ops->clear_quit_flag != NULL)
+	extlang->ops->clear_quit_flag (extlang);
+    }
+
+  quit_flag = 0;
+}
+
+/* Set the quit flag.  */
+
+void
+set_quit_flag (void)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (extlang->ops->set_quit_flag != NULL)
+	extlang->ops->set_quit_flag (extlang);
+    }
+
+  quit_flag = 1;
+}
+
+/* Return true if the quit flag has been set, false otherwise.
+   Extension languages may need their own control over whether SIGINT has
+   been seen.  */
+
+int
+check_quit_flag (void)
+{
+  int i, result = 0;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      if (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)
+    {
+      quit_flag = 0;
+      result = 1;
+    }
+
+  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)
+{
+  int i;
+  const struct extension_language_defn *extlang;
+
+  ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
+    {
+      enum ext_lang_rc rc;
+
+      if (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");
+	}
+    }
+}
+
+extern initialize_file_ftype _initialize_extension;
+
+void
+_initialize_extension (void)
+{
+  observer_attach_before_prompt (ext_lang_before_prompt);
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]