public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v1 02/13] script language API for GDB: scripting.[ch]
@ 2013-12-06  5:52 xdje42
  2013-12-06 12:26 ` Phil Muldoon
  0 siblings, 1 reply; 3+ messages in thread
From: xdje42 @ 2013-12-06  5:52 UTC (permalink / raw)
  To: gdb-patches

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

scripting.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.

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

scripting.c defines script_language_gdb for GDB's own scripting language,
and provides the functions GDB calls to call into a scripting language.

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

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

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index be30dfd..a859ffc 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -757,7 +757,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	proc-service.list progspace.c \
 	prologue-value.c psymtab.c \
 	regcache.c reggroups.c remote.c remote-fileio.c remote-notif.c reverse.c \
-	sentinel-frame.c \
+	scripting.c sentinel-frame.c \
 	serial.c ser-base.c ser-unix.c skip.c \
 	solib.c solib-target.c source.c \
 	stabsread.c stack.c probe.c stap-probe.c std-regs.c \
@@ -842,6 +842,7 @@ config/nm-nto.h config/sparc/nm-sol2.h config/nm-linux.h \
 top.h bsd-kvm.h gdb-stabs.h reggroups.h \
 annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h	\
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
+scripting.h scripting-priv.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h \
 psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h \
@@ -934,6 +935,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	go-lang.o go-valprint.o go-typeprint.o \
 	jv-lang.o jv-valprint.o jv-typeprint.o jv-varobj.o \
 	m2-lang.o opencl-lang.o p-lang.o p-typeprint.o p-valprint.o \
+	scripting.o \
 	sentinel-frame.o \
 	complaints.o typeprint.o \
 	ada-typeprint.o c-typeprint.o f-typeprint.o m2-typeprint.o \
diff --git a/gdb/scripting-priv.h b/gdb/scripting-priv.h
new file mode 100644
index 0000000..f839d8c
--- /dev/null
+++ b/gdb/scripting-priv.h
@@ -0,0 +1,191 @@
+/* Private implementation details of interface between gdb and its
+   scripting 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 SCRIPTING_PRIV_H
+#define SCRIPTING_PRIV_H
+
+#include "scripting.h"
+
+/* High level description of a 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 script_language_defn
+{
+  /* Enum of the scripting language.  */
+  enum script_language language;
+
+  /* The name of the scripting language, lowercase.  E.g., python.  */
+  const char *name;
+
+  /* The capitalized name of the scripting language.  E.g., Python.  */
+  const char *capitalized_name;
+
+  /* The file suffix for this scripting language.  E.g., ".py".  */
+  const char *suffix;
+
+  /* The suffix of per-objfile scripts to auto-load scripts.
+     E.g., When the program loads libfoo.so, look for libfoo.so-gdb.py.  */
+  const char *auto_load_suffix;
+
+  /* We support embedding external scripting language code in GDB's own
+     scripting language.  We do this by having a special command that begins
+     the external 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 script_language_script_ops *script_ops;
+
+  /* Either a pointer to the "methods" of the scripting 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 script_language_ops *ops;
+};
+
+/* The interface for loading scripts from external scripting languages,
+   as well as GDB's own scripting language.  */
+
+struct script_language_script_ops
+{
+  /* Load a script.  This is called, e.g., via the "source" command.  */
+  script_sourcer_func *script_sourcer;
+
+  /* Load a script attached to an objfile.  */
+  objfile_script_sourcer_func *objfile_script_sourcer;
+
+  /* Return non-zero if auto-loading scripts in this scripting language
+     is enabled.  */
+  int (*auto_load_enabled) (const struct script_language_defn *);
+};
+
+/* The interface for making calls from GDB to an external scripting
+   language.  This is for non-script-loading related functionality,
+   like pretty-printing, etc.  The reason these are separated out as
+   GDB's own scripting language makes use of script_language_script_opts,
+   but it makes no use of these.  There is no (current) intention to split
+   script_language_ops up any further.  */
+
+struct script_language_ops
+{
+  /* Called at the end of gdb initialization to give the scripting 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 script_language_defn *);
+
+  /* Return non-zero if the scripting language successfully initialized.  */
+  int (*initialized) (const struct script_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 script_language_defn *,
+				     struct command_line *);
+
+  /* Called before printing a type.  */
+  void (*start_type_printers) (const struct script_language_defn *,
+			       struct script_type_printers *);
+
+  /* Try to pretty-print TYPE.  If successful the pretty-printed type is
+     returned.  Otherwise NULL is returned.
+     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.  */
+  char *(*apply_type_printers) (const struct script_language_defn *,
+				const struct script_type_printers *,
+				struct 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 script_language_defn *,
+			      struct script_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 non-zero if the value was successfully pretty-printed.  */
+  int (*apply_val_pretty_printer)
+    (const struct script_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 script_bt_status (*apply_frame_filter)
+    (const struct script_language_defn *,
+     struct frame_info *frame, int flags, enum script_frame_args args_type,
+     struct ui_out *out, int frame_low, int frame_high);
+
+  /* Update values held by the scripting 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_values) (const struct script_language_defn *,
+			   struct objfile *objfile, htab_t copied_types);
+
+  /* Return non-zero if there is a stop condition for the breakpoint.  */
+  int (*breakpoint_has_cond) (const struct script_language_defn *,
+			      struct breakpoint *);
+
+  /* Return non-zero if there is a stop condition for the breakpoint,
+     and it indicates the program should stop.  */
+  enum scr_bp_stop (*breakpoint_cond_says_stop)
+    (const struct script_language_defn *, struct breakpoint *);
+
+  /* The next three are used to connect gdb's SIGINT handling with the
+     scripting language's.  */
+
+  /* Clear the SIGINT indicator.  */
+  void (*clear_quit_flag) (const struct script_language_defn *);
+
+  /* Set the SIGINT indicator.  */
+  void (*set_quit_flag) (const struct script_language_defn *);
+
+  /* Return non-zero if a SIGINT has occurred.
+     This is expected to also clear the indicator.  */
+  int (*check_quit_flag) (const struct script_language_defn *);
+};
+
+#endif /* SCRIPTING_PRIV_H */
diff --git a/gdb/scripting.c b/gdb/scripting.c
new file mode 100644
index 0000000..f63edf8
--- /dev/null
+++ b/gdb/scripting.c
@@ -0,0 +1,621 @@
+/* Interface between gdb and its scripting 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 "script" in the name, and no other symbol in gdb does.  */
+
+#include "defs.h"
+#include "auto-load.h"
+#include "breakpoint.h"
+#include "scripting.h"
+#include "scripting-priv.h"
+#include "cli/cli-script.h"
+#include "python/python.h"
+
+/* Iterate over all external scripting languages, regardless of whether the
+   support has been compiled in or not.  */
+#define ALL_EXT_SCRIPTING_LANGUAGES(i, slang) \
+  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
+       slang != NULL; \
+       slang = external_scripting_languages[++i])
+
+/* Iterate over all external scripting languages that are supported.  */
+#define ALL_ENABLED_EXT_SCRIPTING_LANGUAGES(i, slang) \
+  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
+       slang != NULL; \
+       slang = external_scripting_languages[++i]) \
+    if (slang->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 script_language_script_ops script_lang_gdb_script_ops =
+{
+  source_gdb_script,
+  source_gdb_objfile_script,
+  auto_load_gdb_scripts_enabled
+};
+
+const struct script_language_defn script_language_gdb =
+{
+  SCRIPT_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,
+
+  &script_lang_gdb_script_ops,
+
+  /* The rest of the scripting interface isn't supported by GDB's own
+     scripting language.  */
+  NULL
+};
+
+/* Table of all external (non-native) scripting languages.  */
+
+static const struct script_language_defn * const
+  external_scripting_languages[] =
+{
+  &script_language_python,
+  NULL
+};
+\f
+/* Methods for GDB's own scripting language.  */
+
+/* The script_language_script_ops.script_sourcer "method".  */
+
+static void
+source_gdb_script (const struct script_language_defn *slang,
+		   FILE *stream, const char *file)
+{
+  script_from_file (stream, file);
+}
+
+/* The script_language_script_ops.objfile_script_sourcer "method".  */
+
+static void
+source_gdb_objfile_script (const struct script_language_defn *slang,
+			   struct objfile *objfile,
+			   FILE *stream, const char *file)
+{
+  script_from_file (stream, file);
+}
+\f
+/* Accessors for "public" attributes of struct script_language.
+
+   IWBN if we could use slang_foo here and elsewhere, but we can't for fear of
+   confusing someone into thinking we might be referring to the Slang
+   programming language.  */
+
+/* Return the "name" field of SLANG.  */
+
+const char *
+script_lang_name (const struct script_language_defn *slang)
+{
+  return slang->name;
+}
+
+/* Return the "capitalized_name" field of SLANG.  */
+
+const char *
+script_lang_capitalized_name (const struct script_language_defn *slang)
+{
+  return slang->capitalized_name;
+}
+
+/* Return the "suffix" field of SLANG.  */
+
+const char *
+script_lang_suffix (const struct script_language_defn *slang)
+{
+  return slang->suffix;
+}
+
+/* Return the "auto_load_suffix" field of SLANG.  */
+
+const char *
+script_lang_auto_load_suffix (const struct script_language_defn *slang)
+{
+  return slang->auto_load_suffix;
+}
+\f
+/* script_language_script_ops wrappers.  */
+
+static void
+throw_unsupported (const struct script_language_defn *slang)
+{
+  throw_error (UNSUPPORTED_ERROR,
+	       _("Scripting in the \"%s\" language is not supported"
+		 " in this copy of GDB."),
+	       slang->capitalized_name);
+}
+
+/* Throw UNSUPPORTED_ERROR if called.
+   This is used to implement script_ext_{soft,hard}.  */
+
+static void
+source_script_unsupported (const struct script_language_defn *slang,
+			   FILE *stream, const char *file)
+{
+  throw_unsupported (slang);
+}
+
+/* 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 a function to load FILE.
+   If FILE specifies a scripting language we support then the script language
+   definition is stored in *SLANG_PTR.
+   If FILE specifies a scripting language we support but which is not
+   enabled then return a function that throws UNSUPPORTED_ERROR.
+   Otherwise return NULL.
+
+   Note: This could be a lot cleaner if not for script_ext_soft.  */
+
+script_sourcer_func *
+get_script_sourcer (const char *file,
+		    const struct script_language_defn **slang_ptr)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  *slang_ptr = NULL;
+
+  ALL_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (has_extension (file, slang->suffix))
+	{
+	  script_sourcer_func *func = script_lang_sourcer (slang);
+
+	  *slang_ptr = slang;
+	  if (func != NULL)
+	    return func;
+	  return source_script_unsupported;
+	}
+    }
+
+  return NULL;
+}
+
+/* Return the script "sourcer" function for SLANG.
+   This is the function that loads and processes a script.  */
+
+script_sourcer_func *
+script_lang_sourcer (const struct script_language_defn *slang)
+{
+  if (slang->script_ops == NULL)
+    return NULL;
+  return slang->script_ops->script_sourcer;
+}
+
+/* Return the objfile script "sourcer" function for SLANG.
+   This is the function that loads and processes a script for a particular
+   objfile.  */
+
+objfile_script_sourcer_func *
+script_lang_objfile_sourcer (const struct script_language_defn *slang)
+{
+  if (slang->script_ops == NULL)
+    return NULL;
+  return slang->script_ops->objfile_script_sourcer;
+}
+
+/* Return non-zero if auto-loading of SLANG scripts is enabled.  */
+
+int
+script_lang_auto_load_enabled (const struct script_language_defn *slang)
+{
+  if (slang->script_ops == NULL)
+    return 0;
+  return slang->script_ops->auto_load_enabled (slang);
+}
+\f
+/* Functions that iterate over all (external) scripting languages.  */
+
+/* Wrapper to call the script_language_ops.finish_initialization "method"
+   for each compiled-in scripting language.  */
+
+void
+finish_script_initialization (void)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->finish_initialization != NULL)
+	slang->ops->finish_initialization (slang);
+    }
+}
+
+/* Return the scripting language specified by CMD.
+   Note the difference between this function and
+   eval_script_from_control_command is that we loop on
+   ALL_EXT_SCRIPTING_LANGUAGES whereas the latter loops on
+   ALL_ENABLED_EXT_SCRIPTING_LANGUAGES.  */
+
+static const struct script_language_defn *
+script_lang_from_control_command (struct command_line *cmd)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->cli_control_type == cmd->control_type)
+	return slang;
+    }
+
+  gdb_assert_not_reached ("invalid scripting language in cli command");
+}
+
+/* Evaluate the commands in CMD, which specifies a sequence of commands
+   in an external scripting language.  */
+
+void
+eval_script_from_control_command (struct command_line *cmd)
+{
+  int i;
+  const struct script_language_defn *slang;
+  const char *script_lang_name;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->cli_control_type == cmd->control_type
+	  && slang->ops->eval_from_control_command != NULL)
+	{
+	  slang->ops->eval_from_control_command (slang, cmd);
+	  return;
+	}
+    }
+
+  /* The requested scripting language is not supported in this GDB.  */
+  throw_unsupported (script_lang_from_control_command (cmd));
+}
+
+/* Load scripts for OBJFILE written in external languages.  */
+
+void
+auto_load_scripts_for_objfile (struct objfile *objfile)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  slang = &script_language_gdb;
+  if (script_lang_auto_load_enabled (slang))
+    auto_load_objfile_script (objfile, slang);
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (script_lang_auto_load_enabled (slang))
+	auto_load_objfile_script (objfile, slang);
+    }
+}
+\f
+/* Interface to type pretty-printers implemented in an external
+   scripting 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_script_type_printers and free_script_type_printers.  */
+
+struct script_type_printers *
+start_script_type_printers (void)
+{
+  struct script_type_printers *printers
+    = XZALLOC (struct script_type_printers);
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->start_type_printers != NULL)
+	slang->ops->start_type_printers (slang, printers);
+    }
+
+  return printers;
+}
+
+/* Iteratively try the type pretty-printers specified by PRINTERS,
+   returning the result of the first one that succeeds.  If no printer
+   succeeds then NULL is returned.  */
+
+char *
+apply_script_type_printers (struct script_type_printers *printers,
+			    struct type *type)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      char *result = NULL;
+
+      if (slang->ops->apply_type_printers != NULL)
+	result = slang->ops->apply_type_printers (slang, printers, type);
+
+      if (result != NULL)
+	return result;
+    }
+
+  return NULL;
+}
+
+/* Call this after pretty-printing a type to release all memory held
+   by PRINTERS.  */
+
+void
+free_script_type_printers (struct script_type_printers *printers)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->free_type_printers != NULL)
+	slang->ops->free_type_printers (slang, printers);
+    }
+
+  xfree (printers);
+}
+\f
+/* 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.  */
+
+int
+apply_val_script_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 script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->apply_val_pretty_printer (slang, type, valaddr,
+						embedded_offset, address,
+						stream, recurse, val,
+						options, language))
+	return 1;
+    }
+
+  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 SCR_BT_ERROR on error,
+   or SCR_BT_COMPLETED on success.  */
+
+enum script_bt_status
+apply_script_frame_filter (struct frame_info *frame, int flags,
+			   enum script_frame_args args_type,
+			   struct ui_out *out,
+			   int frame_low, int frame_high)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      enum script_bt_status status;
+
+      if (slang->ops->apply_frame_filter == NULL)
+	continue;
+      status = slang->ops->apply_frame_filter (slang, frame, flags,
+					       args_type, out,
+					       frame_low, frame_high);
+      /* We use the filters from the first scripting language that has
+	 applicable filters.  */
+      if (status != SCR_BT_NO_FILTERS)
+	return status;
+    }
+
+  return SCR_BT_NO_FILTERS;
+}
+
+/* Update values held by the scripting 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_script_values (struct objfile *objfile, htab_t copied_types)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->preserve_values != NULL)
+	slang->ops->preserve_values (slang, objfile, copied_types);
+    }
+}
+
+/* Return non-zero if there is a stop condition for the breakpoint.
+   If SKIP_LANG is not SCRIPT_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
+   scripting language, we need to check if any other already has a
+   condition set.  */
+
+int
+breakpoint_has_script_cond (struct breakpoint *b,
+			    enum script_language skip_lang)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->language != skip_lang
+	  && slang->ops->breakpoint_has_cond != NULL
+	  && slang->ops->breakpoint_has_cond (slang, b))
+	return 1;
+    }
+
+  return 0;
+}
+
+/* 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_script_cond_says_stop (struct breakpoint *b)
+{
+  int i;
+  const struct script_language_defn *slang;
+  enum scr_bp_stop stop = SCR_BP_STOP_UNSET;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      /* There is a rule that a breakpoint can have at most one of any of a
+	 CLI or script 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 (slang->ops->breakpoint_cond_says_stop != NULL)
+	{
+	  enum scr_bp_stop this_stop
+	    = slang->ops->breakpoint_cond_says_stop (slang, b);
+
+	  if (this_stop != SCR_BP_STOP_UNSET)
+	    {
+	      /* Even though we have to check every scripting language, only
+		 one of them can return yes/no (because only one of them
+		 can have a "stop" condition.  */
+	      gdb_assert (stop == SCR_BP_STOP_UNSET);
+	      stop = this_stop;
+	    }
+	}
+    }
+
+  return stop == SCR_BP_STOP_NO ? 0 : 1;
+}
+\f
+/* ^C/SIGINT support.
+   This requires cooperation with the scripting 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 scripting language
+   doesn't provide the necessary support.  */
+static int quit_flag;
+
+/* Clear the quit flag.  */
+
+void
+clear_quit_flag (void)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->clear_quit_flag != NULL)
+	slang->ops->clear_quit_flag (slang);
+    }
+
+  quit_flag = 0;
+}
+
+/* Set the quit flag.  */
+
+void
+set_quit_flag (void)
+{
+  int i;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->set_quit_flag != NULL)
+	slang->ops->set_quit_flag (slang);
+    }
+
+  quit_flag = 1;
+}
+
+/* Return true if the quit flag has been set, false otherwise.
+   Scripting languages may need their own control over whether SIGINT has
+   been seen.  */
+
+int
+check_quit_flag (void)
+{
+  int i, result = 0;
+  const struct script_language_defn *slang;
+
+  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
+    {
+      if (slang->ops->check_quit_flag != NULL)
+	if (slang->ops->check_quit_flag (slang) != 0)
+	  result = 1;
+    }
+
+  /* This is written in a particular way to avoid races.  */
+  if (quit_flag)
+    {
+      quit_flag = 0;
+      result = 1;
+    }
+
+  return result;
+}
diff --git a/gdb/scripting.h b/gdb/scripting.h
new file mode 100644
index 0000000..4307bb0
--- /dev/null
+++ b/gdb/scripting.h
@@ -0,0 +1,204 @@
+/* Interface between gdb and its scripting 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 SCRIPTING_H
+#define SCRIPTING_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 script_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 script_language_defn *,
+				  FILE *, const char *);
+
+/* 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 script_language_defn *,
+					  struct objfile *,
+					  FILE *, const char *);
+
+/* Enum of each scripting language.  */
+
+enum script_language
+  {
+    SCRIPT_LANG_NONE,
+    SCRIPT_LANG_GDB,
+    SCRIPT_LANG_PYTHON
+  };
+
+/* Script frame-filter status return values.  */
+
+enum script_bt_status
+  {
+    /* Return when an error has occurred in processing frame filters,
+       or when printing the stack.  */
+    SCR_BT_ERROR = -1,
+
+    /* Return from internal routines to indicate that the function
+       succeeded.  */
+    SCR_BT_OK = 1,
+
+    /* Return when the frame filter process is complete, and all
+       operations have succeeded.  */
+    SCR_BT_COMPLETED = 2,
+
+    /* Return when the frame filter process is complete, but there
+       were no filter registered and enabled to process. */
+    SCR_BT_NO_FILTERS = 3
+  };
+
+/* Flags to pass to apply_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 script_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 script_language_ops.breakpoint_cond_says_stop.  */
+
+enum scr_bp_stop
+  {
+    /* No "stop" condition is set.  */
+    SCR_BP_STOP_UNSET,
+
+    /* A "stop" condition is set, and it says "don't stop".  */
+    SCR_BP_STOP_NO,
+
+    /* A "stop" condition is set, and it says "stop".  */
+    SCR_BP_STOP_YES
+  };
+
+/* Table of type printers associated with the global typedef table.  */
+
+struct script_type_printers
+{
+  /* Type-printers from Python.  */
+  void *py_type_printers;
+};
+\f
+/* The interface for gdb's own scripting language.  */
+extern const struct script_language_defn script_language_gdb;
+
+/* Accessors for "public" attributes of the scripting language definition.  */
+
+extern enum script_language script_lang_kind
+  (const struct script_language_defn *);
+
+extern const char *script_lang_name (const struct script_language_defn *);
+
+extern const char *script_lang_capitalized_name
+  (const struct script_language_defn *);
+
+extern const char *script_lang_suffix (const struct script_language_defn *);
+
+extern const char *script_lang_auto_load_suffix
+  (const struct script_language_defn *);
+
+extern script_sourcer_func *script_lang_sourcer
+   (const struct script_language_defn *);
+
+extern objfile_script_sourcer_func *script_lang_objfile_sourcer
+   (const struct script_language_defn *);
+
+extern int script_lang_auto_load_enabled (const struct script_language_defn *);
+
+/* Return the function that can load(source) FILE.  */
+extern script_sourcer_func *get_script_sourcer
+  (const char *file, const struct script_language_defn **slang_ptr);
+
+/* Wrappers for each scripting API function that iterate over all
+   (external) scripting languages.  */
+
+extern void finish_script_initialization (void);
+
+extern void eval_script_from_control_command (struct command_line *cmd);
+
+extern void auto_load_scripts_for_objfile (struct objfile *);
+
+extern struct script_type_printers *start_script_type_printers (void);
+
+extern char *apply_script_type_printers (struct script_type_printers *,
+					 struct type *);
+
+extern void free_script_type_printers (struct script_type_printers *);
+
+extern int apply_val_script_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 script_bt_status apply_script_frame_filter
+  (struct frame_info *frame, int flags, enum script_frame_args args_type,
+   struct ui_out *out, int frame_low, int frame_high);
+
+extern void preserve_script_values (struct objfile *, htab_t copied_types);
+
+extern int breakpoint_has_script_cond (struct breakpoint *b,
+				       enum script_language skip_lang);
+
+extern int breakpoint_script_cond_says_stop (struct breakpoint *);
+
+#endif /* SCRIPTING_H */

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v1 02/13] script language API for GDB: scripting.[ch]
  2013-12-06  5:52 [PATCH v1 02/13] script language API for GDB: scripting.[ch] xdje42
@ 2013-12-06 12:26 ` Phil Muldoon
  2013-12-06 17:17   ` Doug Evans
  0 siblings, 1 reply; 3+ messages in thread
From: Phil Muldoon @ 2013-12-06 12:26 UTC (permalink / raw)
  To: xdje42, gdb-patches

On 06/12/13 05:52, xdje42@gmail.com wrote:

> +struct script_language_defn
> +{
> +  /* Enum of the scripting language.  */
> +  enum script_language language;
> +
> +  /* The name of the scripting language, lowercase.  E.g., python.  */
> +  const char *name;
> +
> +  /* The capitalized name of the scripting language.  E.g., Python.  */
> +  const char *capitalized_name;

Why do we need a capitalized name and a lowercase name?  I am sure
there is a purpose in mind, but I could not see in the patch the
reason for both.

> +  /* The file suffix for this scripting language.  E.g., ".py".  */
> +  const char *suffix;

I am undecided if this should be an array.  I have seen .python
(though .py is far more common).  What do you think?

> +/* The interface for making calls from GDB to an external scripting
> +   language.  This is for non-script-loading related functionality,
> +   like pretty-printing, etc.  The reason these are separated out as
> +   GDB's own scripting language makes use of script_language_script_opts,
> +   but it makes no use of these.  There is no (current) intention to split
> +   script_language_ops up any further.  */

> +  /* Called before printing a type.  */
> +  void (*start_type_printers) (const struct script_language_defn *,
> +			       struct script_type_printers *);
> +
> +  /* Try to pretty-print TYPE.  If successful the pretty-printed type is
> +     returned.  Otherwise NULL is returned.
> +     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.  */
> +  char *(*apply_type_printers) (const struct script_language_defn *,
> +				const struct script_type_printers *,
> +				struct 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 script_language_defn *,
> +			      struct script_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 non-zero if the value was successfully pretty-printed.  */
> +  int (*apply_val_pretty_printer)
> +    (const struct script_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 script_bt_status (*apply_frame_filter)
> +    (const struct script_language_defn *,
> +     struct frame_info *frame, int flags, enum script_frame_args args_type,
> +     struct ui_out *out, int frame_low, int frame_high);
> +
> +  /* Update values held by the scripting 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_values) (const struct script_language_defn *,
> +			   struct objfile *objfile, htab_t copied_types);
> +
> +  /* Return non-zero if there is a stop condition for the breakpoint.  */
> +  int (*breakpoint_has_cond) (const struct script_language_defn *,
> +			      struct breakpoint *);

These features seem arbitrarily divided? Why no extended prompt
support here for example? I would have thought that callback would
have been something all of the languages would want access too.  I
guess I don't understand why some features are included here,
formally, and some are ad-hoc hooks? I understand that things like
convenience functions etc are not called via a central dispatch
(like the above), but I am unsure of having half the features formally
defined here, and the other half just left silently undeclared.

It gives me pause on the design.  If we are going to have a formalized
interface to scripting in GDB it seems it would be best to either be
ad-hoc, or completely formal.  Right now it feels in-between?

Anyway, I think a lot more documentation is needed regarding the
expectations of the API and the requirements to the scripting author.
Are all of these functions mandatory and need to be fully implemented?
Are NULLs allowed where the author has chosen not to implement that
feature if they are not mandatory? What about the behavior of NOOP
functions? (IE, the frame filter functions say for guile just returns
NO_FILTERS.  Will that deny the other scripting language the chance to
run their frame filters?

> +  /* Return non-zero if there is a stop condition for the breakpoint,
> +     and it indicates the program should stop.  */
> +  enum scr_bp_stop (*breakpoint_cond_says_stop)
> +    (const struct script_language_defn *, struct breakpoint *);

Why "scr" over script?


> +#include "defs.h"
> +#include "auto-load.h"
> +#include "breakpoint.h"
> +#include "scripting.h"
> +#include "scripting-priv.h"
> +#include "cli/cli-script.h"
> +#include "python/python.h"
> +
> +/* Iterate over all external scripting languages, regardless of whether the
> +   support has been compiled in or not.  */
> +#define ALL_EXT_SCRIPTING_LANGUAGES(i, slang) \
> +  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
> +       slang != NULL; \
> +       slang = external_scripting_languages[++i])
> +
> +/* Iterate over all external scripting languages that are supported.  */
> +#define ALL_ENABLED_EXT_SCRIPTING_LANGUAGES(i, slang) \
> +  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
> +       slang != NULL; \
> +       slang = external_scripting_languages[++i]) \
> +    if (slang->ops != NULL)

Tiny nit, and it is a personal thing.  If we are now asking for spaces
between function names and comments, surely these same should apply
for MACROS that are defined as, and called as, functions? Like I said,
tiny style issue.

> +/* Table of all external (non-native) scripting languages.  */
> +
> +static const struct script_language_defn * const
> +  external_scripting_languages[] =
> +{
> +  &script_language_python,
> +  NULL
> +};

Small comment.  If NULL is the sentinel value indicating the end of a
sequence, I normally put a comment saying so.  Otherwise it can get
replaced accidentally with the next entry.  Something like: "NULL /*
Sentinel */" so it is absolutely clear.

> +\f
> +/* Accessors for "public" attributes of struct script_language.
> +
> +   IWBN if we could use slang_foo here and elsewhere, but we can't for fear of
> +   confusing someone into thinking we might be referring to the Slang
> +   programming language.  */
> +
> +/* Return the "name" field of SLANG.  */

> +
> +const char *
> +script_lang_name (const struct script_language_defn *slang)
> +{
> +  return slang->name;
> +}

I'd go even further and remove all references to slang, and replace
them with scripting_lang, including parameters and variables.  It
would be more consistent. That's just my choice though, it is really
up to you.

> +
> +/* Return the "capitalized_name" field of SLANG.  */
> +
> +const char *
> +script_lang_capitalized_name (const struct script_language_defn *slang)
> +{
> +  return slang->capitalized_name;
> +}

I mentioned this earlier.  Not sure why we need it.  Perhaps instead
of capitalized name, you really mean the proper noun of the scripting
language? Still not sure why we need this and the lower-case version.
If terms of upper-case and lower-case, the lower-case can just be
extracted by conversion?  This might be a comment issue, and
these have real uses.  Maybe "generic" and "proper" or
something like this.

> +/* Return the "suffix" field of SLANG.  */

This is going to get really confusing if we ever have slang scripting
support ;)

> +
> +/* Return the script "sourcer" function for SLANG.
> +   This is the function that loads and processes a script.  */

The more I read the more I think which should be consistent with
script_* over slang.

> +/* Return the scripting language specified by CMD.
> +   Note the difference between this function and
> +   eval_script_from_control_command is that we loop on
> +   ALL_EXT_SCRIPTING_LANGUAGES whereas the latter loops on
> +   ALL_ENABLED_EXT_SCRIPTING_LANGUAGES.  */
> +
> +static const struct script_language_defn *
> +script_lang_from_control_command (struct command_line *cmd)
> +{
> +  int i;
> +  const struct script_language_defn *slang;
> +
> +  ALL_EXT_SCRIPTING_LANGUAGES (i, slang)
> +    {
> +      if (slang->cli_control_type == cmd->control_type)
> +	return slang;
> +    }

It is hard to work this out as there is only one language supported,
which is Python.  But are you planning to add info scripting_languages
and other assorted information commands?

It might even be that we need to add a priority to the language if
they exist in mutual exclusion for shared features.  (IE, if Python
has a pretty printer for std::list, and so does guile, which gets to
run?)


> +  struct script_type_printers *printers
> +    = XZALLOC (struct script_type_printers);
> +  int i;
> +  const struct script_language_defn *slang;
> +
> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
> +    {
> +      if (slang->ops->start_type_printers != NULL)
> +	slang->ops->start_type_printers (slang, printers);
> +    }
> +
> +  return printers;
> +}

I think this will run all type printers from all scripting languages.
If Python has already pretty printed a type does it make sense to run
it through other scripting languages (as an example)?

> +/* 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.  */
> +
> +int
> +apply_val_script_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 script_language_defn *slang;
> +
> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
> +    {
> +      if (slang->ops->apply_val_pretty_printer (slang, type, valaddr,
> +						embedded_offset, address,
> +						stream, recurse, val,
> +						options, language))
> +	return 1;
> +    }
> +
> +  return 0;
> +}

I think we definitely need a priority system for scripting languages.
If the user cannot define priority, it would seem chaotic when
multiple scripting languages are supported that have similar features
supported. I think it would be ideal if the user could specify which
scripting language has priority for printing a value where one or more
printers/frame-filters exist over the other.

I thought at first that the existing priority system in place for
frame-filters/type and value pretty printers would work.  But it
occurs to me it won't.  Each scripting language I presume keeps their
own list of printers.  (I don't see guile, for example, adding to a
python list).  These lists are compartmentalized to each language. So
the situation right now would be, if guile was listed above python,
and guile had a pretty printer for foo, and so did Python, there is
currently no way to use the Python pretty printer.  And vice
versa. And there is not way to get a grand list of pretty printers for
all implemented scripting languages.

In some distributions pretty/type/frame-filters are distributed via a
package, where the feature package installs the relevant bits. (IE in
Fedora libstdc++.rpm installs the libstdc++ pretty printers).  So in
these cases, the user might be unaware, and have no control over what
printers are installed.


> +/* 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 script_bt_status
> +apply_script_frame_filter (struct frame_info *frame, int flags,
> +			   enum script_frame_args args_type,
> +			   struct ui_out *out,
> +			   int frame_low, int frame_high)
> +{
> +  int i;
> +  const struct script_language_defn *slang;
> +
> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
> +    {
> +      enum script_bt_status status;
> +
> +      if (slang->ops->apply_frame_filter == NULL)
> +	continue;

I notice this can be NULL, but it seems type and value printers
cannot? Why?

> +      status = slang->ops->apply_frame_filter (slang, frame, flags,
> +					       args_type, out,
> +					       frame_low, frame_high);
> +      /* We use the filters from the first scripting language that has
> +	 applicable filters.  */
> +      if (status != SCR_BT_NO_FILTERS)
> +	return status;

Not sure why you use SCR here instead of SCRIPT

> +enum script_language
> +  {
> +    SCRIPT_LANG_NONE,
> +    SCRIPT_LANG_GDB,
> +    SCRIPT_LANG_PYTHON
> +  };
> +
> +/* Script frame-filter status return values.  */
> +
> +enum script_bt_status
> +  {
> +    /* Return when an error has occurred in processing frame filters,
> +       or when printing the stack.  */
> +    SCR_BT_ERROR = -1,

The enum name is script, but the constants are SCR_*

But in the enum script_language above the constants are SCRIPT.  I
think we should finalize on one name throughout the code.

> +/* Flags to pass to apply_frame_filter.  */
> +
> +enum frame_filter_flags
> +  {

Why no SCRIPT tag on the name?

> +    /* 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 script_frame_args
> +  {
> +    /* Print no values for arguments when invoked from the MI. */

> +
> +/* The possible results of script_language_ops.breakpoint_cond_says_stop.  */
> +
> +enum scr_bp_stop
> +  {

SCRIPT. And others.
> +    /* No "stop" condition is set.  */
> +    SCR_BP_STOP_UNSET,

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v1 02/13] script language API for GDB: scripting.[ch]
  2013-12-06 12:26 ` Phil Muldoon
@ 2013-12-06 17:17   ` Doug Evans
  0 siblings, 0 replies; 3+ messages in thread
From: Doug Evans @ 2013-12-06 17:17 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gdb-patches

Phil Muldoon <pmuldoon@redhat.com> writes:

> On 06/12/13 05:52, xdje42@gmail.com wrote:
>
>> +struct script_language_defn
>> +{
>> +  /* Enum of the scripting language.  */
>> +  enum script_language language;
>> +
>> +  /* The name of the scripting language, lowercase.  E.g., python.  */
>> +  const char *name;
>> +
>> +  /* The capitalized name of the scripting language.  E.g., Python.  */
>> +  const char *capitalized_name;
>
> Why do we need a capitalized name and a lowercase name?  I am sure
> there is a purpose in mind, but I could not see in the patch the
> reason for both.

For gdb's own scripting language it's "GDB".
For python it's "Python".

>> +  /* The file suffix for this scripting language.  E.g., ".py".  */
>> +  const char *suffix;
>
> I am undecided if this should be an array.  I have seen .python
> (though .py is far more common).  What do you think?

I think we can stick with just one suffix for now,
no need to add the feature at this point.

>> +/* The interface for making calls from GDB to an external scripting
>> +   language.  This is for non-script-loading related functionality,
>> +   like pretty-printing, etc.  The reason these are separated out as
>> +   GDB's own scripting language makes use of script_language_script_opts,
>> +   but it makes no use of these.  There is no (current) intention to split
>> +   script_language_ops up any further.  */
>
>> +  /* Called before printing a type.  */
>> +  void (*start_type_printers) (const struct script_language_defn *,
>> +			       struct script_type_printers *);
>> +
>> +  /* Try to pretty-print TYPE.  If successful the pretty-printed type is
>> +     returned.  Otherwise NULL is returned.
>> +     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.  */
>> +  char *(*apply_type_printers) (const struct script_language_defn *,
>> +				const struct script_type_printers *,
>> +				struct 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 script_language_defn *,
>> +			      struct script_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 non-zero if the value was successfully pretty-printed.  */
>> +  int (*apply_val_pretty_printer)
>> +    (const struct script_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 script_bt_status (*apply_frame_filter)
>> +    (const struct script_language_defn *,
>> +     struct frame_info *frame, int flags, enum script_frame_args args_type,
>> +     struct ui_out *out, int frame_low, int frame_high);
>> +
>> +  /* Update values held by the scripting 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_values) (const struct script_language_defn *,
>> +			   struct objfile *objfile, htab_t copied_types);
>> +
>> +  /* Return non-zero if there is a stop condition for the breakpoint.  */
>> +  int (*breakpoint_has_cond) (const struct script_language_defn *,
>> +			      struct breakpoint *);
>
> These features seem arbitrarily divided? Why no extended prompt
> support here for example?

My intention is that they are not arbitrarily divided.

Any time gdb needs to call into a scripting language, there's an ops method.
Another way of looking at it is: the only things exported from the
scripting language is scriping-priv.h, and ultimately just
script_language_defn.
[Plus the one "is python present" predicate for MI.
More on that in another email.]

Extended prompt support is missing only because of oversight.
Thanks for pointing it out!

> I would have thought that callback would
> have been something all of the languages would want access too.  I
> guess I don't understand why some features are included here,
> formally, and some are ad-hoc hooks? I understand that things like
> convenience functions etc are not called via a central dispatch
> (like the above), but I am unsure of having half the features formally
> defined here, and the other half just left silently undeclared.

Lots of features exist without needing an "ops" method.
I was wondering about adding them, but there's no need so I kept it simple.

> It gives me pause on the design.  If we are going to have a formalized
> interface to scripting in GDB it seems it would be best to either be
> ad-hoc, or completely formal.  Right now it feels in-between?

I think it is quite formal.
All python is intended to export to gdb is struct script_language_defn.
[Plus the one function for MI ... one could certainly do that different:
script_lang_initialized_p (SCRIPT_LANG_PYTHON), which is better anyway.
Thanks!]

> Anyway, I think a lot more documentation is needed regarding the
> expectations of the API and the requirements to the scripting author.
> Are all of these functions mandatory and need to be fully implemented?
> Are NULLs allowed where the author has chosen not to implement that
> feature if they are not mandatory? What about the behavior of NOOP
> functions? (IE, the frame filter functions say for guile just returns
> NO_FILTERS.  Will that deny the other scripting language the chance to
> run their frame filters?

Righto.

>> +  /* Return non-zero if there is a stop condition for the breakpoint,
>> +     and it indicates the program should stop.  */
>> +  enum scr_bp_stop (*breakpoint_cond_says_stop)
>> +    (const struct script_language_defn *, struct breakpoint *);
>
> Why "scr" over script?

script "works for me".

>> +#include "defs.h"
>> +#include "auto-load.h"
>> +#include "breakpoint.h"
>> +#include "scripting.h"
>> +#include "scripting-priv.h"
>> +#include "cli/cli-script.h"
>> +#include "python/python.h"
>> +
>> +/* Iterate over all external scripting languages, regardless of whether the
>> +   support has been compiled in or not.  */
>> +#define ALL_EXT_SCRIPTING_LANGUAGES(i, slang) \
>> +  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
>> +       slang != NULL; \
>> +       slang = external_scripting_languages[++i])
>> +
>> +/* Iterate over all external scripting languages that are supported.  */
>> +#define ALL_ENABLED_EXT_SCRIPTING_LANGUAGES(i, slang) \
>> +  for (/*int*/ i = 0, slang = external_scripting_languages[0]; \
>> +       slang != NULL; \
>> +       slang = external_scripting_languages[++i]) \
>> +    if (slang->ops != NULL)
>
> Tiny nit, and it is a personal thing.  If we are now asking for spaces
> between function names and comments, surely these same should apply
> for MACROS that are defined as, and called as, functions? Like I said,
> tiny style issue.

"works for me", I don't have a strong preference.

[Nit: We've always asked for spaces between function names and
comments.  It's only now that we enforce that.]

>> +/* Table of all external (non-native) scripting languages.  */
>> +
>> +static const struct script_language_defn * const
>> +  external_scripting_languages[] =
>> +{
>> +  &script_language_python,
>> +  NULL
>> +};
>
> Small comment.  If NULL is the sentinel value indicating the end of a
> sequence, I normally put a comment saying so.  Otherwise it can get
> replaced accidentally with the next entry.  Something like: "NULL /*
> Sentinel */" so it is absolutely clear.

Done.
But if we do this here I think it needs to formalized and done
everywhere from now on.  I'm happy to add a section to the manual
if people want this.

>> +\f
>> +/* Accessors for "public" attributes of struct script_language.
>> +
>> +   IWBN if we could use slang_foo here and elsewhere, but we can't for fear of
>> +   confusing someone into thinking we might be referring to the Slang
>> +   programming language.  */
>> +
>> +/* Return the "name" field of SLANG.  */
>
>> +
>> +const char *
>> +script_lang_name (const struct script_language_defn *slang)
>> +{
>> +  return slang->name;
>> +}
>
> I'd go even further and remove all references to slang, and replace
> them with scripting_lang, including parameters and variables.  It
> would be more consistent. That's just my choice though, it is really
> up to you.

It's a local variable name, but if it's still confusing I'm
happy to change it.  OTOH, what I'm doing know *is* consistent.
In breakpoint.c it's b or bp or bl (for breakpoint_location).
In frame.c it's often just frame or fi instead of frame_info.
(it's also this_frame, next_frame, but my point is a shorter
variable name is consistent - I'm doing the same thing here).
I think it's totally ok to use something shorter for local variable
names as long as it's reasonable and consistent.

sl?

>> +
>> +/* Return the "capitalized_name" field of SLANG.  */
>> +
>> +const char *
>> +script_lang_capitalized_name (const struct script_language_defn *slang)
>> +{
>> +  return slang->capitalized_name;
>> +}

> I mentioned this earlier.  Not sure why we need it.  Perhaps instead
> of capitalized name, you really mean the proper noun of the scripting
> language? Still not sure why we need this and the lower-case version.

I want to have something simple to handle gdb vs GDB and python vs Python.

> If terms of upper-case and lower-case, the lower-case can just be
> extracted by conversion?  This might be a comment issue, and
> these have real uses.  Maybe "generic" and "proper" or
> something like this.

What's "generic" and "proper" might be in the eye of the reader.
It's not critical of course.

>> +/* Return the "suffix" field of SLANG.  */
>
> This is going to get really confusing if we ever have slang scripting
> support ;)

It's just a local variable name.

sl?

>> +
>> +/* Return the script "sourcer" function for SLANG.
>> +   This is the function that loads and processes a script.  */
>
> The more I read the more I think which should be consistent with
> script_* over slang.

I like the consistency of "sl".  How about that?

>> +/* Return the scripting language specified by CMD.
>> +   Note the difference between this function and
>> +   eval_script_from_control_command is that we loop on
>> +   ALL_EXT_SCRIPTING_LANGUAGES whereas the latter loops on
>> +   ALL_ENABLED_EXT_SCRIPTING_LANGUAGES.  */
>> +
>> +static const struct script_language_defn *
>> +script_lang_from_control_command (struct command_line *cmd)
>> +{
>> +  int i;
>> +  const struct script_language_defn *slang;
>> +
>> +  ALL_EXT_SCRIPTING_LANGUAGES (i, slang)
>> +    {
>> +      if (slang->cli_control_type == cmd->control_type)
>> +	return slang;
>> +    }
>
> It is hard to work this out as there is only one language supported,
> which is Python.  But are you planning to add info scripting_languages
> and other assorted information commands?

I hadn't gotten that far yet, but sounds reasonable to me.

> It might even be that we need to add a priority to the language if
> they exist in mutual exclusion for shared features.  (IE, if Python
> has a pretty printer for std::list, and so does guile, which gets to
> run?)

That's intended to be solved by the first-one-wins principle,
and keeping Python first in the list.

>> +  struct script_type_printers *printers
>> +    = XZALLOC (struct script_type_printers);
>> +  int i;
>> +  const struct script_language_defn *slang;
>> +
>> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
>> +    {
>> +      if (slang->ops->start_type_printers != NULL)
>> +	slang->ops->start_type_printers (slang, printers);
>> +    }
>> +
>> +  return printers;
>> +}
>
> I think this will run all type printers from all scripting languages.
> If Python has already pretty printed a type does it make sense to run
> it through other scripting languages (as an example)?

Hmmm, this is the "start" method that just initializes things
for the subsequent call to the apply_type_printers method.  [Right?]

>> +/* 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.  */
>> +
>> +int
>> +apply_val_script_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 script_language_defn *slang;
>> +
>> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
>> +    {
>> +      if (slang->ops->apply_val_pretty_printer (slang, type, valaddr,
>> +						embedded_offset, address,
>> +						stream, recurse, val,
>> +						options, language))
>> +	return 1;
>> +    }
>> +
>> +  return 0;
>> +}
>
> I think we definitely need a priority system for scripting languages.
> If the user cannot define priority, it would seem chaotic when
> multiple scripting languages are supported that have similar features
> supported. I think it would be ideal if the user could specify which
> scripting language has priority for printing a value where one or more
> printers/frame-filters exist over the other.

There's the basic priority system in place now.
One could give the user control on a per-command basis,
but I don't see a need for it yet.

> I thought at first that the existing priority system in place for
> frame-filters/type and value pretty printers would work.  But it
> occurs to me it won't.  Each scripting language I presume keeps their
> own list of printers.  (I don't see guile, for example, adding to a
> python list).  These lists are compartmentalized to each language. So
> the situation right now would be, if guile was listed above python,
> and guile had a pretty printer for foo, and so did Python, there is
> currently no way to use the Python pretty printer.  And vice
> versa. And there is not way to get a grand list of pretty printers for
> all implemented scripting languages.

I wasn't intending to have guile ahead of python in the list,
but if it were, for the sake of discussion, one could just disable
the guile pretty-printer (or all of them).
Something like "disable guile pretty-printer .*" or some such.

It's easy enough to get a list of all pretty-printers.
We know how to print the list for each language and we know
all the languages.

> In some distributions pretty/type/frame-filters are distributed via a
> package, where the feature package installs the relevant bits. (IE in
> Fedora libstdc++.rpm installs the libstdc++ pretty printers).  So in
> these cases, the user might be unaware, and have no control over what
> printers are installed.

yep.

>> +/* 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 script_bt_status
>> +apply_script_frame_filter (struct frame_info *frame, int flags,
>> +			   enum script_frame_args args_type,
>> +			   struct ui_out *out,
>> +			   int frame_low, int frame_high)
>> +{
>> +  int i;
>> +  const struct script_language_defn *slang;
>> +
>> +  ALL_ENABLED_EXT_SCRIPTING_LANGUAGES (i, slang)
>> +    {
>> +      enum script_bt_status status;
>> +
>> +      if (slang->ops->apply_frame_filter == NULL)
>> +	continue;
>
> I notice this can be NULL, but it seems type and value printers
> cannot? Why?

Just oversight.

>> +      status = slang->ops->apply_frame_filter (slang, frame, flags,
>> +					       args_type, out,
>> +					       frame_low, frame_high);
>> +      /* We use the filters from the first scripting language that has
>> +	 applicable filters.  */
>> +      if (status != SCR_BT_NO_FILTERS)
>> +	return status;
>
> Not sure why you use SCR here instead of SCRIPT

Just going with the flow having converted it from PY_BT_NO_FILTERS.
SCRIPT_ is fine with me.

>> +enum script_language
>> +  {
>> +    SCRIPT_LANG_NONE,
>> +    SCRIPT_LANG_GDB,
>> +    SCRIPT_LANG_PYTHON
>> +  };
>> +
>> +/* Script frame-filter status return values.  */
>> +
>> +enum script_bt_status
>> +  {
>> +    /* Return when an error has occurred in processing frame filters,
>> +       or when printing the stack.  */
>> +    SCR_BT_ERROR = -1,
>
> The enum name is script, but the constants are SCR_*
>
> But in the enum script_language above the constants are SCRIPT.  I
> think we should finalize on one name throughout the code.

yeah.

>> +/* Flags to pass to apply_frame_filter.  */
>> +
>> +enum frame_filter_flags
>> +  {
>
> Why no SCRIPT tag on the name?

Move here from python/python.h as is.
I can certainly add a follow-on patch to add a prefix.

>> +    /* 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 script_frame_args
>> +  {
>> +    /* Print no values for arguments when invoked from the MI. */
>
>> +
>> +/* The possible results of script_language_ops.breakpoint_cond_says_stop.  */
>> +
>> +enum scr_bp_stop
>> +  {
>
> SCRIPT. And others.

Righto.

>> +    /* No "stop" condition is set.  */
>> +    SCR_BP_STOP_UNSET,

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-12-06 17:17 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-06  5:52 [PATCH v1 02/13] script language API for GDB: scripting.[ch] xdje42
2013-12-06 12:26 ` Phil Muldoon
2013-12-06 17:17   ` Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).