[RFC][patch 1/9] initial Python support

Thiago Jung Bauermann
2008-04-29T15:59:29Z

[-- Attachment #1: python-basic.diff --]
[-- Type: text/plain, Size: 37752 bytes --]

This patch adds the initial code for Python scripting support in GDB,
and adapts the build system accordingly.

The Python support included in this patch was explained by Tromey thusly:

> You can evaluate python, either as a block, as a one-liner, or as an
> expression. I cleaned up the code so that it works properly in other
> block structures, like commands or loops. The expression evaluation
> code makes an attempt to convert python values to gdb values as
> appropriate (strings, ints, and floating-point types). Some contrived
> examples...
>
> Block form:
>
> python
> print 23
> end
>
> One liner:
>
> python print 23
>
> Expression:
>
> break foo if $(23 > 5)
>
> There's also a Python command to pass any string to the gdb CLI, and
> another one to get the value of any "set/show" variable.

Regarding changes to the building system, the patch adds the
--with-python option to configure. With the option set to yes or auto
(which is the default), configure will first search for -lpython2.5 and
failing that, -lpython2.4. If no Python library is found, or if the
--without-python option is given, GDB will be compiled without Python
scripting support.

There are two caveats with the configure.ac changes: one is that they
trigger a bug in autoconf 2.59 when library names contain a dot
(e.g., libpython2.5). I regenerated the configure script using
autoconf 2.61, but the proper way to fix this at the moment (since we
must use version 2.59) is to backport the fix using the
config/override.m4 mechanism. I didn't look into that yet.

The other caveat is that I had trouble with gnulib configure script
when using this patch. I didn't investigate the issue yet, and to test
this code I removed gnulib from the compilation. Maybe I didn't
regenerate the configure scripts properly.
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center

2008-04-29 Vladimir Prus <vladimir@codesourcery.com>
Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>

* Makefile.in (LIBPYTHON, SUBDIR_PYTHON_OBS, SUBDIR_PYTHON_SRCS,
SUBDIR_PYTHON_DEPS, SUBDIR_PYTHON_LDFLAGS, SUBDIR_PYTHON_CFLAGS,
PYTHON_CFLAGS): New.
(CLIBS): Add dependency on Python library.
(python_h, python_internal_h): New.
(cli-script.o): Depend on python.h
(python.o): New.
* ax-gdb.c (gen_expr): Handle OP_INTERNALFUNC.
* c-exp.y (yylex): Recognize $(...).
* cli/cli-script.c (print_command_lines): Handle python_control.
(execute_control_command): Handle python_control.
(read_next_line): Add new special_processing parameter. Update all
callers. Handle "python".
(recurse_read_control_structure): Handle python_control.
(read_command_lines): Add new special_processing parameter. Update
all callers. Handle python_control.
Include python.h.
* configure.ac: Add --with-python.
* defs.h (enum command_control_type) <python_control>: New
constant.
* eval.c (evaluate_subexp_standard): Handle OP_INTERNALFUNC.
* expprint.c (print_subexp_standard): Handle OP_INTERNALFUNC.
(op_name_standard): Likewise.
(dump_subexp_body_standard): Likewise.
* expression.h (enum exp_opcode): Add OP_INTERNALFUNC.
* parse.c (write_dollar_funcall): New function.
(operator_length_standard): Handle OP_INTERNALFUNC.
* parser-defs.h (write_dollar_funcall): Declare.
* python/python-internal.h: New file.
* python/python.c: New file.
* python/python.h: New file.
* value.h (value_of_python): Declare.

Index: tromey.git/gdb/Makefile.in
===================================================================
--- tromey.git.orig/gdb/Makefile.in 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/Makefile.in 2008-04-29 11:00:35.000000000 -0300
@@ -141,6 +141,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@
# Where is expat? This will be empty if expat was not available.
LIBEXPAT = @LIBEXPAT@

+# Where is python? This will be empty if python was not available.
+LIBPYTHON = @LIBPYTHON2_4@ @LIBPYTHON2_5@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -254,6 +257,17 @@ SUBDIR_TUI_LDFLAGS=
SUBDIR_TUI_CFLAGS= \
-DTUI=1

+#
+# python sub directory definitons
+#
+SUBDIR_PYTHON_OBS = \
+ python.o
+SUBDIR_PYTHON_SRCS = \
+ python/python.c
+SUBDIR_PYTHON_DEPS =
+SUBDIR_PYTHON_LDFLAGS=
+SUBDIR_PYTHON_CFLAGS=
+

# Opcodes currently live in one of two places. Either they are in the
# opcode library, typically ../opcodes, or they are in a header file
@@ -399,7 +413,7 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcode
-lintl -liberty $(LIBGNU)
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \
- $(LIBICONV) $(LIBEXPAT) \
+ $(LIBICONV) $(LIBEXPAT) $(LIBPYTHON) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
@@ -963,6 +977,13 @@ tui_wingeneral_h = $(srcdir)/tui/tui-win
tui_win_h = $(srcdir)/tui/tui-win.h $(tui_data_h)
tui_winsource_h = $(srcdir)/tui/tui-winsource.h $(tui_data_h)

+#
+# gdb/python/ headers
+#
+
+python_h = $(srcdir)/python/python.h $(defs_h) $(value_h)
+python_internal_h = $(srcdir)/python/python-internal.h
+
# gdb/features preparsed descriptions
features_headers = $(defs_h) $(gdbtypes_h) $(target_descriptions_h)
arm_with_iwmmxt_c = $(srcdir)/features/arm-with-iwmmxt.c $(features_headers)
@@ -3051,7 +3072,8 @@ cli-logging.o: $(srcdir)/cli/cli-logging
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-logging.c
cli-script.o: $(srcdir)/cli/cli-script.c $(defs_h) $(value_h) $(language_h) \
$(ui_out_h) $(gdb_string_h) $(exceptions_h) $(top_h) $(cli_cmds_h) \
- $(cli_decode_h) $(cli_script_h) $(gdb_assert_h) $(breakpoint_h)
+ $(cli_decode_h) $(cli_script_h) $(gdb_assert_h) $(breakpoint_h) \
+ $(python_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-script.c
cli-setshow.o: $(srcdir)/cli/cli-setshow.c $(defs_h) $(readline_tilde_h) \
$(value_h) $(gdb_string_h) $(ui_out_h) $(cli_decode_h) $(cli_cmds_h) \
@@ -3375,4 +3397,19 @@ tui-winsource.o: $(srcdir)/tui/tui-winso
$(gdb_curses_h) $(gdb_assert_h)
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/tui/tui-winsource.c

+#
+# gdb/python/ dependencies
+#
+# Need to explicitly specify the compile rule as make will do nothing
+# or try to compile the object file into the sub-directory.
+
+# Flags needed to compile Python code (taken from python-config --cflags)
+# FIXME: should we add -DNDEBUG? See CAUTION comment in Python.h.
+PYTHON_CFLAGS=-fno-strict-aliasing
+
+python.o: $(srcdir)/python/python.c $(defs_h) $(python_h) \
+ $(command_h) $(libiberty_h) $(cli_decode_h) $(charset_h) $(top_h) \
+ $(exceptions_h) $(python_internal_h) $(version_h)
+ $(CC) -c $(INTERNAL_CFLAGS) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
+
### end of the gdb Makefile.in.
Index: tromey.git/gdb/ax-gdb.c
===================================================================
--- tromey.git.orig/gdb/ax-gdb.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/ax-gdb.c 2008-04-29 10:58:06.000000000 -0300
@@ -1620,6 +1620,9 @@ gen_expr (union exp_element **pc, struct
case OP_INTERNALVAR:
error (_("GDB agent expressions cannot use convenience variables."));

+ case OP_INTERNALFUNC:
+ error (_("GDB agent expressions cannot use convenience functions."));
+
/* Weirdo operator: see comments for gen_repeat for details. */
case BINOP_REPEAT:
/* Note that gen_repeat handles its own argument evaluation. */
Index: tromey.git/gdb/breakpoint.c
===================================================================
--- tromey.git.orig/gdb/breakpoint.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/breakpoint.c 2008-04-29 10:58:06.000000000 -0300
@@ -671,7 +671,7 @@ commands_command (char *arg, int from_tt
char *tmpbuf = xstrprintf ("Type commands for when breakpoint %d is hit, one per line.",
bnum);
struct cleanup *cleanups = make_cleanup (xfree, tmpbuf);
- l = read_command_lines (tmpbuf, from_tty);
+ l = read_command_lines (tmpbuf, from_tty, 1);
do_cleanups (cleanups);
free_command_lines (&b->commands);
b->commands = l;
Index: tromey.git/gdb/c-exp.y
===================================================================
--- tromey.git.orig/gdb/c-exp.y 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/c-exp.y 2008-04-29 10:58:06.000000000 -0300
@@ -1636,6 +1636,31 @@ yylex ()
/* We must have come across a bad character (e.g. ';'). */
error ("Invalid character '%c' in expression.", c);

+ if (c == '$' && tokstart[1] == '(')
+ {
+ /* Convenience function call. */
+ int cparen_depth = 0;
+ int i;
+ for (i = 1; tokstart[i]; ++i)
+ {
+ if (tokstart[i] == '(')
+ ++cparen_depth;
+ else if (tokstart[i] == ')')
+ {
+ if (--cparen_depth == 0)
+ break;
+ }
+ }
+ if (cparen_depth != 0)
+ error ("Unmatched parentheses in convenience function invocation.");
+ yylval.sval.ptr = &tokstart[2];
+ yylval.sval.length = i - 2;
+ write_dollar_funcall (yylval.sval);
+ lexptr = &tokstart[i + 1];
+ /* FIXME: not exactly right. */
+ return VARIABLE;
+ }
+
/* It's a name. See how long it is. */
namelen = 0;
for (c = tokstart[namelen];
Index: tromey.git/gdb/cli/cli-script.c
===================================================================
--- tromey.git.orig/gdb/cli/cli-script.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/cli/cli-script.c 2008-04-29 11:03:58.000000000 -0300
@@ -34,6 +34,10 @@
#include "cli/cli-script.h"
#include "gdb_assert.h"

+#ifdef HAVE_PYTHON
+#include "python/python.h"
+#endif
+
/* Prototypes for local functions */

static enum command_control_type
@@ -225,6 +229,20 @@ print_command_lines (struct ui_out *uiou
continue;
}

+#ifdef HAVE_PYTHON
+ if (list->control_type == python_control)
+ {
+ ui_out_field_string (uiout, NULL, "python");
+ print_command_lines (uiout, *list->body_list, depth + 1);
+ if (depth)
+ ui_out_spaces (uiout, 2 * depth);
+ ui_out_field_string (uiout, NULL, "end");
+ ui_out_text (uiout, "\n");
+ list = list->next;
+ continue;
+ }
+#endif
+
/* ignore illegal command type and try next */
list = list->next;
} /* while (list) */
@@ -527,6 +545,17 @@ execute_control_command (struct command_
ret = commands_from_control_command (new_line, cmd);
break;
}
+ case python_control:
+#ifdef HAVE_PYTHON
+ {
+ eval_python_from_control_command (cmd);
+ ret = simple_control;
+ break;
+ }
+#else
+ warning (_("Python scripting is not supported in this copy of GDB."));
+ break;
+#endif

default:
warning (_("Invalid control type in canned commands structure."));
@@ -812,10 +841,11 @@ realloc_body_list (struct command_line *
"end", return such an indication to the caller. */

static enum misc_command_type
-read_next_line (struct command_line **command)
+read_next_line (struct command_line **command, int special_processing)
{
char *p, *p1, *prompt_ptr, control_prompt[256];
int i = 0;
+ int not_handled = 0;

if (control_level >= 254)
error (_("Control nesting too deep!"));
@@ -838,13 +868,20 @@ read_next_line (struct command_line **co
if (p == NULL)
return end_command;

- /* Strip leading and trailing whitespace. */
- while (*p == ' ' || *p == '\t')
- p++;
-
- p1 = p + strlen (p);
- while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t'))
- p1--;
+ if (special_processing)
+ {
+ /* Strip leading and trailing whitespace. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ p1 = p + strlen (p);
+ while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t'))
+ p1--;
+ }
+ else
+ {
+ p1 = p + strlen (p);
+ }

/* Blanks and comments don't really do anything, but we need to
distinguish them from else, end and other commands which can be
@@ -856,57 +893,71 @@ read_next_line (struct command_line **co
if (p1 - p == 3 && !strncmp (p, "end", 3))
return end_command;

- /* Is the else clause of an if control structure? */
- if (p1 - p == 4 && !strncmp (p, "else", 4))
- return else_command;
-
- /* Check for while, if, break, continue, etc and build a new command
- line structure for them. */
- if (p1 - p > 5 && !strncmp (p, "while", 5))
- {
- char *first_arg;
- first_arg = p + 5;
- while (first_arg < p1 && isspace (*first_arg))
- first_arg++;
- *command = build_command_line (while_control, first_arg);
- }
- else if (p1 - p > 2 && !strncmp (p, "if", 2))
- {
- char *first_arg;
- first_arg = p + 2;
- while (first_arg < p1 && isspace (*first_arg))
- first_arg++;
- *command = build_command_line (if_control, first_arg);
- }
- else if (p1 - p >= 8 && !strncmp (p, "commands", 8))
- {
- char *first_arg;
- first_arg = p + 8;
- while (first_arg < p1 && isspace (*first_arg))
- first_arg++;
- *command = build_command_line (commands_control, first_arg);
- }
- else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
- {
- *command = (struct command_line *)
- xmalloc (sizeof (struct command_line));
- (*command)->next = NULL;
- (*command)->line = NULL;
- (*command)->control_type = break_control;
- (*command)->body_count = 0;
- (*command)->body_list = NULL;
- }
- else if (p1 - p == 13 && !strncmp (p, "loop_continue", 13))
+ if (special_processing)
{
- *command = (struct command_line *)
- xmalloc (sizeof (struct command_line));
- (*command)->next = NULL;
- (*command)->line = NULL;
- (*command)->control_type = continue_control;
- (*command)->body_count = 0;
- (*command)->body_list = NULL;
+ /* Is the else clause of an if control structure? */
+ if (p1 - p == 4 && !strncmp (p, "else", 4))
+ return else_command;
+
+ /* Check for while, if, break, continue, etc and build a new command
+ line structure for them. */
+ if (p1 - p > 5 && !strncmp (p, "while", 5))
+ {
+ char *first_arg;
+ first_arg = p + 5;
+ while (first_arg < p1 && isspace (*first_arg))
+ first_arg++;
+ *command = build_command_line (while_control, first_arg);
+ }
+ else if (p1 - p > 2 && !strncmp (p, "if", 2))
+ {
+ char *first_arg;
+ first_arg = p + 2;
+ while (first_arg < p1 && isspace (*first_arg))
+ first_arg++;
+ *command = build_command_line (if_control, first_arg);
+ }
+ else if (p1 - p >= 8 && !strncmp (p, "commands", 8))
+ {
+ char *first_arg;
+ first_arg = p + 8;
+ while (first_arg < p1 && isspace (*first_arg))
+ first_arg++;
+ *command = build_command_line (commands_control, first_arg);
+ }
+#ifdef HAVE_PYTHON
+ else if (p1 - p == 6 && !strncmp (p, "python", 6))
+ {
+ /* Note that we ignore the inline "python command" form
+ here. */
+ *command = build_command_line (python_control, "");
+ }
+#endif
+ else if (p1 - p == 10 && !strncmp (p, "loop_break", 10))
+ {
+ *command = (struct command_line *)
+ xmalloc (sizeof (struct command_line));
+ (*command)->next = NULL;
+ (*command)->line = NULL;
+ (*command)->control_type = break_control;
+ (*command)->body_count = 0;
+ (*command)->body_list = NULL;
+ }
+ else if (p1 - p == 13 && !strncmp (p, "loop_continue", 13))
+ {
+ *command = (struct command_line *)
+ xmalloc (sizeof (struct command_line));
+ (*command)->next = NULL;
+ (*command)->line = NULL;
+ (*command)->control_type = continue_control;
+ (*command)->body_count = 0;
+ (*command)->body_list = NULL;
+ }
+ else
+ not_handled = 1;
}
- else
+
+ if (!special_processing || not_handled)
{
/* A normal command. */
*command = (struct command_line *)
@@ -952,7 +1003,7 @@ recurse_read_control_structure (struct c
dont_repeat ();

next = NULL;
- val = read_next_line (&next);
+ val = read_next_line (&next, 1);

/* Just skip blanks and comments. */
if (val == nop_command)
@@ -962,6 +1013,9 @@ recurse_read_control_structure (struct c
{
if (current_cmd->control_type == while_control
|| current_cmd->control_type == if_control
+#ifdef HAVE_PYTHON
+ || current_cmd->control_type == python_control
+#endif
|| current_cmd->control_type == commands_control)
{
/* Success reading an entire canned sequence of commands. */
@@ -1013,6 +1067,9 @@ recurse_read_control_structure (struct c
on it. */
if (next->control_type == while_control
|| next->control_type == if_control
+#ifdef HAVE_PYTHON
+ || next->control_type == python_control
+#endif
|| next->control_type == commands_control)
{
control_level++;
@@ -1037,7 +1094,7 @@ recurse_read_control_structure (struct c
#define END_MESSAGE "End with a line saying just \"end\"."

struct command_line *
-read_command_lines (char *prompt_arg, int from_tty)
+read_command_lines (char *prompt_arg, int from_tty, int special_processing)
{
struct command_line *head, *tail, *next;
struct cleanup *old_chain;
@@ -1066,7 +1123,7 @@ read_command_lines (char *prompt_arg, in
while (1)
{
dont_repeat ();
- val = read_next_line (&next);
+ val = read_next_line (&next, special_processing);

/* Ignore blank lines or comments. */
if (val == nop_command)
@@ -1086,6 +1143,9 @@ read_command_lines (char *prompt_arg, in

if (next->control_type == while_control
|| next->control_type == if_control
+#ifdef HAVE_PYTHON
+ || next->control_type == python_control
+#endif
|| next->control_type == commands_control)
{
control_level++;
@@ -1299,7 +1359,7 @@ define_command (char *comname, int from_
*tem = tolower (*tem);

sprintf (tmpbuf, "Type commands for definition of \"%s\".", comname);
- cmds = read_command_lines (tmpbuf, from_tty);
+ cmds = read_command_lines (tmpbuf, from_tty, 1);

if (c && c->class == class_user)
free_command_lines (&c->user_commands);
@@ -1346,7 +1406,7 @@ document_command (char *comname, int fro
error (_("Command \"%s\" is built-in."), comname);

sprintf (tmpbuf, "Type documentation for \"%s\".", comname);
- doclines = read_command_lines (tmpbuf, from_tty);
+ doclines = read_command_lines (tmpbuf, from_tty, 0);

if (c->doc)
xfree (c->doc);
Index: tromey.git/gdb/configure.ac
===================================================================
--- tromey.git.orig/gdb/configure.ac 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/configure.ac 2008-04-29 10:58:06.000000000 -0300
@@ -485,6 +485,41 @@ else
fi
fi

+AC_ARG_WITH(python,
+ AS_HELP_STRING([--with-python], [include python support (auto/yes/no)]),
+ [], [with_python=auto])
+AC_MSG_CHECKING([whether to use python])
+AC_MSG_RESULT([$with_python])
+
+if test "${with_python}" = no; then
+ AC_MSG_WARN([python support disabled; some features may be unavailable.])
+ HAVE_LIBPYTHON2_5=no
+ HAVE_LIBPYTHON2_4=no
+else
+ AC_LIB_HAVE_LINKFLAGS([python2.5], [], [#include "python2.5/Python.h"],
+ [Py_Initialize ();])
+ if test "$HAVE_LIBPYTHON2_5" != yes; then
+ AC_LIB_HAVE_LINKFLAGS([python2.4], [], [#include "python2.4/Python.h"],
+ [Py_Initialize ();])
+ if test "$HAVE_LIBPYTHON2_4" != yes; then
+ if test "$with_python" = yes; then
+ AC_MSG_ERROR([python is missing or unusable])
+ else
+ AC_MSG_WARN([python is missing or unusable; some features may be unavailable.])
+ fi
+ fi
+ fi
+fi
+
+if test "$HAVE_LIBPYTHON2_4" = yes || test "$HAVE_LIBPYTHON2_5" == yes; then
+ AC_DEFINE(HAVE_PYTHON, 1, [Define if Python interpreter is being linked in.])
+ CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)"
+ CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)"
+ CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)"
+ CONFIG_INITS="$CONFIG_INITS \$(SUBDIR_PYTHON_INITS)"
+ ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)"
+fi
+
# ------------------------- #
# Checks for header files. #
# ------------------------- #
Index: tromey.git/gdb/defs.h
===================================================================
--- tromey.git.orig/gdb/defs.h 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/defs.h 2008-04-29 10:58:06.000000000 -0300
@@ -642,6 +642,7 @@ enum command_control_type
while_control,
if_control,
commands_control,
+ python_control,
invalid_control
};

@@ -657,7 +658,7 @@ struct command_line
struct command_line **body_list;
};

-extern struct command_line *read_command_lines (char *, int);
+extern struct command_line *read_command_lines (char *, int, int);

extern void free_command_lines (struct command_line **);

Index: tromey.git/gdb/eval.c
===================================================================
--- tromey.git.orig/gdb/eval.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/eval.c 2008-04-29 10:58:06.000000000 -0300
@@ -538,6 +538,18 @@ evaluate_subexp_standard (struct type *e
(*pos) += 2;
return value_of_internalvar (exp->elts[pc + 1].internalvar);

+ case OP_INTERNALFUNC:
+#ifdef HAVE_PYTHON
+ tem = longest_to_int (exp->elts[pc + 1].longconst);
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+ /* FIXME: handling noside == EVAL_AVOID_SIDE_EFFECTS? */
+ if (noside == EVAL_SKIP)
+ goto nosideret;
+ return value_of_python (&exp->elts[pc + 2].string, tem);
+#else
+ error (_("Python scripting is not supported in this copy of GDB."));
+#endif
+
case OP_STRING:
tem = longest_to_int (exp->elts[pc + 1].longconst);
(*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
Index: tromey.git/gdb/expprint.c
===================================================================
--- tromey.git.orig/gdb/expprint.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/expprint.c 2008-04-29 10:58:06.000000000 -0300
@@ -148,6 +148,14 @@ print_subexp_standard (struct expression
internalvar_name (exp->elts[pc + 1].internalvar));
return;

+ case OP_INTERNALFUNC:
+ {
+ const char *name = &exp->elts[pc + 2].string;
+ (*pos) += 3 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
+ fprintf_filtered (stream, "$(%s)", name);
+ return;
+ }
+
case OP_FUNCALL:
(*pos) += 2;
nargs = longest_to_int (exp->elts[pc + 1].longconst);
@@ -692,6 +700,8 @@ op_name_standard (enum exp_opcode opcode
return "OP_REGISTER";
case OP_INTERNALVAR:
return "OP_INTERNALVAR";
+ case OP_INTERNALFUNC:
+ return "OP_INTERNALFUNC";
case OP_FUNCALL:
return "OP_FUNCALL";
case OP_STRING:
@@ -973,6 +983,11 @@ dump_subexp_body_standard (struct expres
exp->elts[elt].internalvar->name);
elt += 2;
break;
+ case OP_INTERNALFUNC:
+ fprintf_filtered (stream, "Internal function call $(%s)",
+ &exp->elts[elt + 1].string);
+ elt += 3 + BYTES_TO_EXP_ELEM (exp->elts[elt].longconst + 1);
+ break;
case OP_FUNCALL:
{
int i, nargs;
Index: tromey.git/gdb/expression.h
===================================================================
--- tromey.git.orig/gdb/expression.h 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/expression.h 2008-04-29 10:58:06.000000000 -0300
@@ -172,6 +172,12 @@ enum exp_opcode
With another OP_INTERNALVAR at the end, this makes three exp_elements. */
OP_INTERNALVAR,

+ /* OP_INTERNALFUNC represents a call to a gdb-internal
+ "convenience function". Its format is the same as that of a
+ STRUCTOP, but the string data is evaluated as a call to a
+ gdb-provided function. */
+ OP_INTERNALFUNC,
+
/* OP_FUNCALL is followed by an integer in the next exp_element.
The integer is the number of args to the function call.
That many plus one values from following subexpressions
Index: tromey.git/gdb/parse.c
===================================================================
--- tromey.git.orig/gdb/parse.c 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/parse.c 2008-04-29 10:58:06.000000000 -0300
@@ -295,7 +295,7 @@ write_exp_elt_intern (struct internalvar
strings with embedded null bytes, as is required for some languages.

Don't be fooled by the fact that the string is null byte terminated,
- this is strictly for the convenience of debugging gdb itself. Gdb
+ this is strictly for the convenience of debugging gdb itself.
Gdb does not depend up the string being null terminated, since the
actual length is recorded in expression elements at each end of the
string. The null byte is taken into consideration when computing how
@@ -574,6 +574,14 @@ handle_register:
return;
}

+void
+write_dollar_funcall (struct stoken str)
+{
+ write_exp_elt_opcode (OP_INTERNALFUNC);
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_INTERNALFUNC);
+}
+

char *
find_template_name_end (char *p)
@@ -798,6 +806,7 @@ operator_length_standard (struct express
case OP_OBJC_NSSTRING: /* Objective C Foundation Class NSString constant */
case OP_OBJC_SELECTOR: /* Objective C "@selector" pseudo-op */
case OP_NAME:
+ case OP_INTERNALFUNC:
oplen = longest_to_int (expr->elts[endpos - 2].longconst);
oplen = 4 + BYTES_TO_EXP_ELEM (oplen + 1);
break;
Index: tromey.git/gdb/parser-defs.h
===================================================================
--- tromey.git.orig/gdb/parser-defs.h 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/parser-defs.h 2008-04-29 10:58:06.000000000 -0300
@@ -136,6 +136,8 @@ extern void write_exp_elt_objfile (struc
extern void write_exp_msymbol (struct minimal_symbol *,
struct type *, struct type *);

+extern void write_dollar_funcall (struct stoken str);
+
extern void write_dollar_variable (struct stoken str);

extern char *find_template_name_end (char *);
Index: tromey.git/gdb/python/python-internal.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/python-internal.h 2008-04-29 10:58:06.000000000 -0300
@@ -0,0 +1,42 @@
+/* Gdb/Python header for private use by Python module.
+
+ Copyright (C) 2008 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 GDB_PYTHON_INTERNAL_H
+#define GDB_PYTHON_INTERNAL_H
+
+#if HAVE_LIBPYTHON2_4
+#include "python2.4/Python.h"
+#elif HAVE_LIBPYTHON2_5
+#include "python2.5/Python.h"
+#endif
+
+extern PyObject *gdb_module;
+
+/* Use this after a TRY_EXCEPT to throw the appropriate Python
+ exception. FIXME: throw different errors depending on
+ Exception.error? */
+#define GDB_PY_HANDLE_EXCEPTION(Exception) \
+ do { \
+ if (Exception.reason < 0) \
+ return PyErr_Format (Exception.reason == RETURN_QUIT \
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
+ "%s", Exception.message); \
+ } while (0)
+
+#endif /* GDB_PYTHON_INTERNAL_H */
Index: tromey.git/gdb/python/python.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/python.c 2008-04-29 11:03:46.000000000 -0300
@@ -0,0 +1,327 @@
+/* General python/gdb code
+
+ Copyright (C) 2008 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/>. */
+
+#include "defs.h"
+#include "python.h"
+#include "command.h"
+#include "libiberty.h"
+#include "cli/cli-decode.h"
+#include "charset.h"
+#include "top.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "version.h"
+
+#include <ctype.h>
+
+PyObject *gdb_module;
+
+static PyObject *get_show_variable (PyObject *, PyObject *);
+static PyObject *execute_gdb_command (PyObject *, PyObject *);
+
+
+void
+demand_python ()
+{
+ static int initialized = 0;
+
+ if (!initialized)
+ {
+ static PyMethodDef GdbMethods[] = {
+ { "execute", execute_gdb_command, METH_VARARGS,
+ "Execute a gdb command" },
+ { "show", get_show_variable, METH_VARARGS,
+ "Return a gdb setting's value" },
+
+ {NULL, NULL, 0, NULL}
+ };
+
+ Py_Initialize ();
+
+ gdb_module = Py_InitModule ("gdb", GdbMethods);
+
+ PyModule_AddStringConstant (gdb_module, "VERSION", version);
+ PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", host_name);
+ PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", target_name);
+
+ PyRun_SimpleString ("import gdb");
+
+ initialized = 1;
+ }
+}
+
+static char *
+compute_python_string (struct command_line *l)
+{
+ char *script = NULL;
+ for (;l; l = l->next)
+ {
+ /* FIXME: inefficient. */
+ if (script)
+ {
+ char *save = script;
+ script = concat (script, l->line, "\n", NULL);
+ xfree (save);
+ }
+ else
+ script = concat (l->line, "\n", NULL);
+ }
+ return script;
+}
+
+void
+eval_python_from_control_command (struct command_line *cmd)
+{
+ char *script;
+
+ if (cmd->body_count != 1)
+ error (_("Invalid \"python\" block structure."));
+
+ demand_python ();
+
+ script = compute_python_string (cmd->body_list[0]);
+ PyRun_SimpleString (script);
+ xfree (script);
+ if (PyErr_Occurred ())
+ {
+ PyErr_Print ();
+ error ("error while executing Python code");
+ }
+}
+
+static void
+python_command (char *arg, int from_tty)
+{
+ char *script;
+ struct cleanup *cleanups = NULL;
+
+ while (arg && *arg && isspace (*arg))
+ ++arg;
+ if (arg && *arg)
+ script = arg;
+ else
+ {
+ struct command_line *l;
+ char *tmpbuf = xstrprintf ("Type python script");
+ cleanups = make_cleanup (xfree, tmpbuf);
+ l = read_command_lines (tmpbuf, from_tty, 0);
+ script = compute_python_string (l);
+ free_command_lines (&l);
+ }
+
+ /* This was observed on the following code in .gdbinit:
+ python
+ #
+ */
+ if (!script)
+ error ("empty Python script specified");
+
+ demand_python ();
+
+ PyRun_SimpleString (script);
+ if (script != arg)
+ xfree (script);
+ if (PyErr_Occurred ())
+ {
+ PyErr_Print ();
+ error ("error while executing Python code");
+ }
+
+ if (cleanups)
+ do_cleanups (cleanups);
+}
+
+\f
+
+/* Transform a gdb variable's value into a Python value. May return
+ NULL (and set a Python exception) on error. */
+
+PyObject *
+variable_to_python (struct cmd_list_element *cmd)
+{
+ switch (cmd->var_type)
+ {
+ case var_string:
+ case var_string_noescape:
+ case var_optional_filename:
+ case var_filename:
+ case var_enum:
+ {
+ char *str = * (char **) cmd->var;
+ if (! str)
+ str = "";
+ return PyString_Decode (str, strlen (str), host_charset (),
+ NULL /* FIXME */);
+ }
+
+ case var_boolean:
+ {
+ if (* (int *) cmd->var)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }
+
+ case var_auto_boolean:
+ {
+ enum auto_boolean ab = * (enum auto_boolean *) cmd->var;
+ if (ab == AUTO_BOOLEAN_TRUE)
+ Py_RETURN_TRUE;
+ else if (ab == AUTO_BOOLEAN_FALSE)
+ Py_RETURN_FALSE;
+ else
+ Py_RETURN_NONE;
+ }
+
+ case var_integer:
+ case var_zinteger:
+ return PyLong_FromLong (* (int *) cmd->var);
+
+ case var_uinteger:
+ return PyLong_FromUnsignedLong (* (unsigned int *) cmd->var);
+ }
+
+ return PyErr_Format (PyExc_RuntimeError, "programmer error: unhandled type");
+}
+
+static PyObject *
+get_show_variable (PyObject *self, PyObject *args)
+{
+ struct cmd_list_element *alias, *prefix, *cmd;
+ char *arg, *newarg;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "s", &arg))
+ return NULL;
+
+ newarg = concat ("show ", arg, (char *) NULL);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (! lookup_cmd_composition (newarg, &alias, &prefix, &cmd))
+ {
+ xfree (newarg);
+ return PyErr_Format (PyExc_RuntimeError,
+ "could not find variable `%s'", arg);
+ }
+ }
+ xfree (newarg);
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (! cmd->var)
+ return PyErr_Format (PyExc_RuntimeError, "`%s' is not a variable", arg);
+ return variable_to_python (cmd);
+}
+
+static PyObject *
+execute_gdb_command (PyObject *self, PyObject *args)
+{
+ struct cmd_list_element *alias, *prefix, *cmd;
+ char *arg, *newarg;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "s", &arg))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ execute_command (arg, 0);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ /* gdbtk does bpstat_do_actions here... */
+
+ Py_RETURN_NONE;
+}
+
+/* Call a python function and return the result. EXPR is the command
+ string. LENGTH is the length of the string. */
+
+struct value *
+value_of_python (char *expr, int length)
+{
+ PyObject *result, *python_main, *global;
+ struct value *value = NULL;
+
+ demand_python ();
+
+ expr = xstrndup (expr, length);
+ make_cleanup (xfree, expr);
+
+ python_main = PyImport_ImportModule ("__main__");
+ global = PyModule_GetDict (python_main);
+
+ result = PyRun_String (expr, Py_eval_input, global, NULL);
+ /* FIXME: do we need a decref here? */
+ if (PyErr_Occurred ())
+ {
+ /* FIXME -- probably should not do this. */
+ PyErr_Print ();
+ error ("python error while evaluating expression");
+ }
+
+ if (PyBool_Check (result))
+ value = value_from_longest (builtin_type_bool, result == Py_True);
+ else if (PyInt_Check (result))
+ {
+ /* FIXME: type mapping. */
+ value = value_from_longest (builtin_type_int, PyInt_AsLong (result));
+ }
+ else if (PyLong_Check (result))
+ {
+ /* FIXME: longest -vs- long long. */
+ LONGEST l = PyLong_AsLongLong (result);
+ if (! PyErr_Occurred ())
+ value = value_from_longest (builtin_type_long, l);
+ }
+ else if (PyFloat_Check (result))
+ {
+ double d = PyFloat_AsDouble (result);
+ if (! PyErr_Occurred ())
+ value = value_from_double (builtin_type_double, d);
+ }
+ else if (PyString_Check (result))
+ {
+ /* FIXME: encoding */
+ char *s = PyString_AsString (result);
+ return value_from_string (s);
+ }
+ else
+ error ("could not convert python result: %s",
+ PyString_AsString (PyObject_Str (result)));
+
+ if (PyErr_Occurred ())
+ {
+ PyErr_Print ();
+ error ("error converting python value");
+ }
+
+ return value;
+}
+
+\f
+
+void
+_initialize_python (void)
+{
+ add_com ("python", class_obscure, python_command, _("\
+Blah, blah, blah."));
+
+ demand_python ();
+}
Index: tromey.git/gdb/python/python.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ tromey.git/gdb/python/python.h 2008-04-29 10:58:06.000000000 -0300
@@ -0,0 +1,29 @@
+/* Python/gdb header for generic use in gdb
+
+ Copyright (C) 2008 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 GDB_PYTHON_H
+#define GDB_PYTHON_H
+
+#include "defs.h"
+#include "value.h"
+#include "python-internal.h"
+
+void eval_python_from_control_command (struct command_line *);
+
+#endif /* GDB_PYTHON_H */
Index: tromey.git/gdb/value.h
===================================================================
--- tromey.git.orig/gdb/value.h 2008-04-29 10:57:39.000000000 -0300
+++ tromey.git/gdb/value.h 2008-04-29 10:58:06.000000000 -0300
@@ -434,6 +434,8 @@ extern LONGEST parse_and_eval_long (char

extern struct value *access_value_history (int num);

+extern struct value *value_of_python (char *exp, int length);
+
extern struct value *value_of_internalvar (struct internalvar *var);

extern void set_internalvar (struct internalvar *var, struct value *val);

--
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center