aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Muldoon <pmuldoon@redhat.com>2011-07-21 11:03:48 +0000
committerPhil Muldoon <pmuldoon@redhat.com>2011-07-21 11:03:48 +0000
commitd17b6f81012b6844de08934193fe7cb7db8cbd5f (patch)
tree38de35dc7c7f44f1f76fbe6af3bed4037b600e00
parent3779080d04bb9504542076e02969f77dff46ae63 (diff)
downloadgdb-d17b6f81012b6844de08934193fe7cb7db8cbd5f.zip
gdb-d17b6f81012b6844de08934193fe7cb7db8cbd5f.tar.gz
gdb-d17b6f81012b6844de08934193fe7cb7db8cbd5f.tar.bz2
2011-07-21 Phil Muldoon <pmuldoon@redhat.com>
Tom Tromey <tromey@redhat.com> * top.c (set_prompt): Rewrite to free previous prompt, free asynch_new_prompt and set both on new prompts. * event-top.c (display_gdb_prompt): Add prompt substitution logic. * python/python.c (before_prompt_hook): New function. 2011-07-21 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/python.exp: Add prompt substitution tests. 2011-07-21 Phil Muldoon <pmuldoon@redhat.com> * observer.texi (GDB Observers): Add before_prompt observer. * gdb.texinfo (Basic Python): Add documentation for prompt substitution.
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/doc/ChangeLog6
-rw-r--r--gdb/doc/gdb.texinfo16
-rw-r--r--gdb/doc/observer.texi5
-rw-r--r--gdb/event-top.c62
-rw-r--r--gdb/python/python.c80
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.python/python.exp82
-rw-r--r--gdb/top.c17
-rw-r--r--gdb/top.h2
10 files changed, 258 insertions, 25 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5e4ab8c..7b0b3b0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2011-07-21 Phil Muldoon <pmuldoon@redhat.com>
+ Tom Tromey <tromey@redhat.com>
+
+ * top.c (set_prompt): Rewrite to free previous prompt, free
+ asynch_new_prompt and set both on new prompts.
+ * event-top.c (display_gdb_prompt): Add prompt substitution
+ logic.
+ * python/python.c (before_prompt_hook): New function.
+
2011-07-20 Matt Rice <ratmice@gmail.com>
* bfin-tdep.c (bfin_extract_return_value): Fix swapped
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 4a2d015..e3e02c8 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,9 @@
+2011-07-21 Phil Muldoon <pmuldoon@redhat.com>
+
+ * observer.texi (GDB Observers): Add before_prompt observer.
+ * gdb.texinfo (Basic Python): Add documentation for prompt
+ substitution.
+
2011-07-11 Phil Muldoon <pmuldoon@redhat.com>
PR python/12438
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3a3a9fb..5b26bbb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -21080,6 +21080,22 @@ provided, it is decoded the way that @value{GDBN}'s inbuilt
@code{break} or @code{edit} commands do (@pxref{Specify Location}).
@end defun
+@defop Operation {@value{GDBN}} prompt_hook current_prompt
+If @var{prompt_hook} is callable, @value{GDBN} will call the method
+assigned to this operation before a prompt is displayed by
+@value{GDBN}.
+
+The parameter @code{current_prompt} contains the current @value{GDBN}
+prompt. This method must return a Python string, or @code{None}. If
+a string is returned, the @value{GDBN} prompt will be set to that
+string. If @code{None} is returned, @value{GDBN} will continue to use
+the current prompt.
+
+Some prompts cannot be substituted in @value{GDBN}. Secondary prompts
+such as those used by readline for command input, and annotation
+related prompts are prohibited from being changed.
+@end defop
+
@node Exception Handling
@subsubsection Exception Handling
@cindex python exceptions
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index d8c3924..689b303 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -222,6 +222,11 @@ Bytes from @var{data} to @var{data} + @var{len} have been written
to the current inferior at @var{addr}.
@end deftypefun
+@deftypefun void before_prompt (const char *@var{current_prompt})
+Called before a top-level prompt is displayed. @var{current_prompt} is
+the current top-level prompt.
+@end deftypefun
+
@deftypefun void test_notification (int @var{somearg})
This observer is used for internal testing. Do not use.
See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 72cbfdc..22f9440 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -33,6 +33,7 @@
#include "cli/cli-script.h" /* for reset_command_nest_depth */
#include "main.h"
#include "gdbthread.h"
+#include "observer.h"
#include "continuations.h"
#include "gdbcmd.h" /* for dont_repeat() */
@@ -258,7 +259,7 @@ void
display_gdb_prompt (char *new_prompt)
{
int prompt_length = 0;
- char *gdb_prompt = get_prompt ();
+ char *actual_gdb_prompt = NULL;
/* Reset the nesting depth used when trace-commands is set. */
reset_command_nest_depth ();
@@ -268,6 +269,25 @@ display_gdb_prompt (char *new_prompt)
if (!current_interp_display_prompt_p ())
return;
+ /* Get the prompt before the observers are called as observer hook
+ functions may change the prompt. Do not call observers on an
+ explicit prompt change as passed to this function, as this forms
+ a temporary prompt, IE, displayed but not set. */
+ if (! new_prompt)
+ {
+ char *post_gdb_prompt = NULL;
+ char *pre_gdb_prompt = xstrdup (get_prompt ());
+
+ observer_notify_before_prompt (pre_gdb_prompt);
+ post_gdb_prompt = get_prompt ();
+
+ /* If the observer changed the prompt, use that prompt. */
+ if (strcmp (pre_gdb_prompt, post_gdb_prompt) != 0)
+ actual_gdb_prompt = post_gdb_prompt;
+
+ xfree (pre_gdb_prompt);
+ }
+
if (sync_execution && is_running (inferior_ptid))
{
/* This is to trick readline into not trying to display the
@@ -289,27 +309,35 @@ display_gdb_prompt (char *new_prompt)
return;
}
- if (!new_prompt)
+ /* If the observer changed the prompt, ACTUAL_GDB_PROMPT will not be
+ NULL. Otherwise, either copy the existing prompt, or set it to
+ NEW_PROMPT. */
+ if (! actual_gdb_prompt)
{
- /* Just use the top of the prompt stack. */
- prompt_length = strlen (PREFIX (0)) +
- strlen (SUFFIX (0)) +
- strlen (gdb_prompt) + 1;
-
- new_prompt = (char *) alloca (prompt_length);
-
- /* Prefix needs to have new line at end. */
- strcpy (new_prompt, PREFIX (0));
- strcat (new_prompt, gdb_prompt);
- /* Suffix needs to have a new line at end and \032 \032 at
- beginning. */
- strcat (new_prompt, SUFFIX (0));
+ if (! new_prompt)
+ {
+ /* Just use the top of the prompt stack. */
+ prompt_length = strlen (PREFIX (0)) +
+ strlen (SUFFIX (0)) +
+ strlen (get_prompt()) + 1;
+
+ actual_gdb_prompt = (char *) alloca (prompt_length);
+
+ /* Prefix needs to have new line at end. */
+ strcpy (actual_gdb_prompt, PREFIX (0));
+ strcat (actual_gdb_prompt, get_prompt());
+ /* Suffix needs to have a new line at end and \032 \032 at
+ beginning. */
+ strcat (actual_gdb_prompt, SUFFIX (0));
+ }
+ else
+ actual_gdb_prompt = new_prompt;;
}
if (async_command_editing_p)
{
rl_callback_handler_remove ();
- rl_callback_handler_install (new_prompt, input_handler);
+ rl_callback_handler_install (actual_gdb_prompt, input_handler);
}
/* new_prompt at this point can be the top of the stack or the one
passed in. It can't be NULL. */
@@ -318,7 +346,7 @@ display_gdb_prompt (char *new_prompt)
/* Don't use a _filtered function here. It causes the assumed
character position to be off, since the newline we read from
the user is not accounted for. */
- fputs_unfiltered (new_prompt, gdb_stdout);
+ fputs_unfiltered (actual_gdb_prompt, gdb_stdout);
gdb_flush (gdb_stdout);
}
}
diff --git a/gdb/python/python.c b/gdb/python/python.c
index f15936d..e3a8d19 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -51,6 +51,7 @@ static int gdbpy_should_print_stack = 0;
#include "version.h"
#include "target.h"
#include "gdbthread.h"
+#include "observer.h"
static PyMethodDef GdbMethods[];
@@ -682,6 +683,81 @@ gdbpy_initialize_events (void)
}
}
+
+
+static void
+before_prompt_hook (const char *current_gdb_prompt)
+{
+ struct cleanup *cleanup;
+ char *prompt = NULL;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ if (PyObject_HasAttrString (gdb_module, "prompt_hook"))
+ {
+ PyObject *hook;
+
+ hook = PyObject_GetAttrString (gdb_module, "prompt_hook");
+ if (hook == NULL)
+ goto fail;
+
+ if (PyCallable_Check (hook))
+ {
+ PyObject *result;
+ PyObject *current_prompt;
+
+ current_prompt = PyString_FromString (current_gdb_prompt);
+ if (current_prompt == NULL)
+ goto fail;
+
+ result = PyObject_CallFunctionObjArgs (hook, current_prompt, NULL);
+
+ Py_DECREF (current_prompt);
+
+ if (result == NULL)
+ goto fail;
+
+ make_cleanup_py_decref (result);
+
+ /* Return type should be None, or a String. If it is None,
+ fall through, we will not set a prompt. If it is a
+ string, set PROMPT. Anything else, set an exception. */
+ if (result != Py_None && ! PyString_Check (result))
+ {
+ PyErr_Format (PyExc_RuntimeError,
+ _("Return from prompt_hook must " \
+ "be either a Python string, or None"));
+ goto fail;
+ }
+
+ if (result != Py_None)
+ {
+ prompt = python_string_to_host_string (result);
+
+ if (prompt == NULL)
+ goto fail;
+ else
+ make_cleanup (xfree, prompt);
+ }
+ }
+ }
+
+ /* If a prompt has been set, PROMPT will not be NULL. If it is
+ NULL, do not set the prompt. */
+ if (prompt != NULL)
+ set_prompt (prompt);
+
+ do_cleanups (cleanup);
+ return;
+
+ fail:
+ gdbpy_print_stack ();
+ do_cleanups (cleanup);
+ return;
+}
+
+
+
/* Printing. */
/* A python function to write a single string using gdb's filtered
@@ -1134,6 +1210,8 @@ Enables or disables printing of Python stack traces."),
gdbpy_initialize_exited_event ();
gdbpy_initialize_thread_event ();
+ observer_attach_before_prompt (before_prompt_hook);
+
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
@@ -1236,6 +1314,8 @@ def GdbSetPythonDirectory (dir):\n\
\n\
# Install the default gdb.PYTHONDIR.\n\
GdbSetPythonDirectory (gdb.PYTHONDIR)\n\
+# Default prompt hook does nothing.\n\
+prompt_hook = None\n\
");
do_cleanups (cleanup);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index e3b3adb..ac815ca 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2011-07-21 Phil Muldoon <pmuldoon@redhat.com>
+
+ * gdb.python/python.exp: Add prompt substitution tests.
+
2011-07-19 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix crash if referenced CU is aged out.
diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp
index 8906bbc..832afc0 100644
--- a/gdb/testsuite/gdb.python/python.exp
+++ b/gdb/testsuite/gdb.python/python.exp
@@ -193,3 +193,85 @@ gdb_py_test_silent_cmd "set python print-stack on" \
"Test print-backtrace set setting" 1
gdb_test "show python print-stack" \
"Whether Python stack will be printed on error is on.*" \
+
+# Test prompt substituion
+
+gdb_py_test_multiple "prompt substitution" \
+ "python" "" \
+ "someCounter = 0" "" \
+ "def prompt(current):" "" \
+ " global someCounter" "" \
+ " if (current == \"testfake \"):" "" \
+ " return None" "" \
+ " someCounter = someCounter + 1" "" \
+ " return \"py prompt \" + str (someCounter) + \" \"" "" \
+ "end" ""
+
+gdb_py_test_multiple "prompt substitution readline" \
+ "python" "" \
+ "pCounter = 0" "" \
+ "def program_prompt(current):" "" \
+ " global pCounter" "" \
+ " if (current == \">\"):" "" \
+ " pCounter = pCounter + 1" "" \
+ " return \"python line \" + str (pCounter) + \": \"" "" \
+ " return None" "" \
+ "end" ""
+
+set newprompt "py prompt 1"
+set newprompt2 "py prompt 2"
+set testfake "testfake"
+
+gdb_test_multiple "python gdb.prompt_hook = prompt" "set the hook" {
+ -re "\[\r\n\]$newprompt $" {
+ pass "set hook"
+ }
+}
+
+gdb_test_multiple "set prompt testfake " "set testfake prompt in GDB" {
+ -re "\[\r\n\]$testfake $" {
+ pass "set prompt testfake"
+ }
+}
+
+gdb_test_multiple "show prompt" "show testfake prompt" {
+ -re "Gdb's prompt is \"$testfake \"..* $" {
+ pass "show prompt shows guarded prompt"
+ }
+}
+
+gdb_test_multiple "set prompt blah " "set blah in GDB" {
+ -re "\[\r\n\]$newprompt2 $" {
+ pass "set prompt blah overriden"
+ }
+}
+
+gdb_test_multiple "python gdb.prompt_hook = None" "Delete hook" {
+ -re "\[\r\n\]$newprompt2 $" {
+ pass "Delete old hook"
+ }
+}
+
+gdb_test_multiple "set prompt $gdb_prompt " "set default prompt" {
+ -re "\[\r\n\]$gdb_prompt $" {
+ pass "set default prompt"
+ }
+}
+
+gdb_test_multiple "python gdb.prompt_hook = program_prompt" "set the hook" {
+ -re "\[\r\n\]$gdb_prompt $" {
+ pass "set programming hook"
+ }
+}
+
+gdb_test_multiple "python" "test we ignore substituion for seconday prompts" {
+ -re "\r\n>$" {
+ pass "readline secondary are not substituted"
+ }
+}
+
+gdb_test_multiple "end" "end programming" {
+ -re "\[\r\n\]$gdb_prompt $" {
+ pass "end programming"
+ }
+}
diff --git a/gdb/top.c b/gdb/top.c
index ecb91f2..3ffd000 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1133,14 +1133,17 @@ get_prompt (void)
}
void
-set_prompt (char *s)
+set_prompt (const char *s)
{
-/* ??rehrauer: I don't know why this fails, since it looks as though
- assignments to prompt are wrapped in calls to xstrdup...
- if (prompt != NULL)
- xfree (prompt);
- */
- PROMPT (0) = xstrdup (s);
+ char *p = xstrdup (s);
+
+ xfree (PROMPT (0));
+ PROMPT (0) = p;
+
+ /* Also, free and set new_async_prompt so prompt changes sync up
+ with set/show prompt. */
+ xfree (new_async_prompt);
+ new_async_prompt = xstrdup (PROMPT (0));
}
diff --git a/gdb/top.h b/gdb/top.h
index 4a6e8fb..24ec2f2 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -55,7 +55,7 @@ extern char *get_prompt (void);
/* This function copies the specified string into the string that
is used by gdb for its command prompt. */
-extern void set_prompt (char *);
+extern void set_prompt (const char *);
/* From random places. */
extern int readnow_symbol_files;