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.
This commit is contained in:
Phil Muldoon 2011-07-21 11:03:48 +00:00
parent 3779080d04
commit d17b6f8101
10 changed files with 256 additions and 23 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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;
if (! new_prompt)
{
/* Just use the top of the prompt stack. */
prompt_length = strlen (PREFIX (0)) +
strlen (SUFFIX (0)) +
strlen (get_prompt()) + 1;
new_prompt = (char *) alloca (prompt_length);
actual_gdb_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));
/* 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);
}
}

View File

@ -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);

View File

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

View File

@ -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"
}
}

View File

@ -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));
}

View File

@ -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;