|
|
http://sourceware.org/ml/gdb-cvs/2013-05/msg00084.html |
|
|
|
|
|
### src/gdb/ChangeLog 2013/05/09 18:03:27 1.15539 |
|
|
### src/gdb/ChangeLog 2013/05/10 10:26:01 1.15540 |
|
|
## -1,3 +1,52 @@ |
|
|
+2013-05-10 Phil Muldoon <pmuldoon@redhat.com> |
|
|
+ |
|
|
+ * stack.c (backtrace_command_1): Add "no-filters", and Python frame |
|
|
+ filter logic. |
|
|
+ (backtrace_command): Add "no-filters" option parsing. |
|
|
+ (_initialize_stack): Alter help to reflect "no-filters" option. |
|
|
+ * Makefile.in (SUBDIR_PYTHON_OBS): Add py-framefilter.o |
|
|
+ (SUBDIR_PYTHON_SRCS): Add py-framefilter.c |
|
|
+ (py-frame.o): Add target |
|
|
+ * data-directory/Makefile.in (PYTHON_DIR): Add Python frame |
|
|
+ filter files. |
|
|
+ * python/python.h: Add new frame filter constants, and flag enum. |
|
|
+ (apply_frame_filter): Add definition. |
|
|
+ * python/python.c (apply_frame_filter): New non-Python |
|
|
+ enabled function. |
|
|
+ * python/py-utils.c (py_xdecref): New function. |
|
|
+ (make_cleanup_py_xdecref): Ditto. |
|
|
+ * python/py-objfile.c: Declare frame_filters dictionary. |
|
|
+ (objfpy_dealloc): Add frame_filters dealloc. |
|
|
+ (objfpy_new): Initialize frame_filters attribute. |
|
|
+ (objfile_to_objfile_object): Ditto. |
|
|
+ (objfpy_get_frame_filters): New function. |
|
|
+ (objfpy_set_frame_filters): New function. |
|
|
+ * python/py-progspace.c: Declare frame_filters dictionary. |
|
|
+ (pspy_dealloc): Add frame_filters dealloc. |
|
|
+ (pspy_new): Initialize frame_filters attribute. |
|
|
+ (pspacee_to_pspace_object): Ditto. |
|
|
+ (pspy_get_frame_filters): New function. |
|
|
+ (pspy_set_frame_filters): New function. |
|
|
+ * python/py-framefilter.c: New file. |
|
|
+ * python/lib/gdb/command/frame_filters.py: New file. |
|
|
+ * python/lib/gdb/frames.py: New file. |
|
|
+ * python/lib/gdb/__init__.py: Initialize global frame_filters |
|
|
+ dictionary |
|
|
+ * python/lib/gdb/FrameDecorator.py: New file. |
|
|
+ * python/lib/gdb/FrameIterator.py: New file. |
|
|
+ * mi/mi-cmds.c (mi_cmds): Add frame filters command. |
|
|
+ * mi/mi-cmds.h: Declare. |
|
|
+ * mi/mi-cmd-stack.c (mi_cmd_stack_list_frames): Add |
|
|
+ --no-frame-filter logic, and Python frame filter logic. |
|
|
+ (stack_enable_frame_filters): New function. |
|
|
+ (parse_no_frame_option): Ditto. |
|
|
+ (mi_cmd_stack_list_frames): Add --no-frame-filter and Python frame |
|
|
+ filter logic. |
|
|
+ (mi_cmd_stack_list_locals): Ditto. |
|
|
+ (mi_cmd_stack_list_args): Ditto. |
|
|
+ (mi_cmd_stack_list_variables): Ditto. |
|
|
+ * NEWS: Add frame filter note. |
|
|
+ |
|
|
2013-05-09 Doug Evans <dje@google.com> |
|
|
|
|
|
* symfile.c (syms_from_objfile_1): Delete args offsets, num_offsets. |
|
|
Index: gdb-7.6/gdb/Makefile.in |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/Makefile.in 2013-06-10 14:31:02.704084663 +0200 |
|
|
+++ gdb-7.6/gdb/Makefile.in 2013-06-10 14:31:08.351082443 +0200 |
|
|
@@ -284,6 +284,7 @@ SUBDIR_PYTHON_OBS = \ |
|
|
py-exitedevent.o \ |
|
|
py-finishbreakpoint.o \ |
|
|
py-frame.o \ |
|
|
+ py-framefilter.o \ |
|
|
py-function.o \ |
|
|
py-gdb-readline.o \ |
|
|
py-inferior.o \ |
|
|
@@ -318,6 +319,7 @@ SUBDIR_PYTHON_SRCS = \ |
|
|
python/py-exitedevent.c \ |
|
|
python/py-finishbreakpoint.c \ |
|
|
python/py-frame.c \ |
|
|
+ python/py-framefilter.c \ |
|
|
python/py-function.c \ |
|
|
python/py-gdb-readline.c \ |
|
|
python/py-inferior.c \ |
|
|
@@ -2174,6 +2176,10 @@ py-frame.o: $(srcdir)/python/py-frame.c |
|
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c |
|
|
$(POSTCOMPILE) |
|
|
|
|
|
+py-framefilter.o: $(srcdir)/python/py-framefilter.c |
|
|
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-framefilter.c |
|
|
+ $(POSTCOMPILE) |
|
|
+ |
|
|
py-function.o: $(srcdir)/python/py-function.c |
|
|
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c |
|
|
$(POSTCOMPILE) |
|
|
Index: gdb-7.6/gdb/NEWS |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/NEWS 2013-06-10 14:31:08.353082442 +0200 |
|
|
+++ gdb-7.6/gdb/NEWS 2013-06-10 14:31:21.230077319 +0200 |
|
|
@@ -4,6 +4,10 @@ |
|
|
* Newly installed $prefix/bin/gcore acts as a shell interface for the |
|
|
GDB command gcore. |
|
|
|
|
|
+* Python scripting |
|
|
+ |
|
|
+ ** Frame filters and frame decorators have been added. |
|
|
+ |
|
|
* New remote packets |
|
|
|
|
|
qXfer:libraries-svr4:read's annex |
|
|
Index: gdb-7.6/gdb/stack.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/stack.c 2013-06-10 14:31:02.709084661 +0200 |
|
|
+++ gdb-7.6/gdb/stack.c 2013-06-10 14:31:08.354082441 +0200 |
|
|
@@ -54,6 +54,7 @@ |
|
|
|
|
|
#include "psymtab.h" |
|
|
#include "symfile.h" |
|
|
+#include "python/python.h" |
|
|
|
|
|
void (*deprecated_selected_frame_level_changed_hook) (int); |
|
|
|
|
|
@@ -1655,13 +1656,15 @@ frame_info (char *addr_exp, int from_tty |
|
|
frames. */ |
|
|
|
|
|
static void |
|
|
-backtrace_command_1 (char *count_exp, int show_locals, int from_tty) |
|
|
+backtrace_command_1 (char *count_exp, int show_locals, int no_filters, |
|
|
+ int from_tty) |
|
|
{ |
|
|
struct frame_info *fi; |
|
|
int count; |
|
|
int i; |
|
|
struct frame_info *trailing; |
|
|
- int trailing_level; |
|
|
+ int trailing_level, py_start = 0, py_end = 0; |
|
|
+ enum py_bt_status result = PY_BT_ERROR; |
|
|
|
|
|
if (!target_has_stack) |
|
|
error (_("No stack.")); |
|
|
@@ -1680,6 +1683,7 @@ backtrace_command_1 (char *count_exp, in |
|
|
{ |
|
|
struct frame_info *current; |
|
|
|
|
|
+ py_start = count; |
|
|
count = -count; |
|
|
|
|
|
current = trailing; |
|
|
@@ -1701,9 +1705,17 @@ backtrace_command_1 (char *count_exp, in |
|
|
|
|
|
count = -1; |
|
|
} |
|
|
+ else |
|
|
+ { |
|
|
+ py_start = 0; |
|
|
+ py_end = count; |
|
|
+ } |
|
|
} |
|
|
else |
|
|
- count = -1; |
|
|
+ { |
|
|
+ py_end = -1; |
|
|
+ count = -1; |
|
|
+ } |
|
|
|
|
|
if (info_verbose) |
|
|
{ |
|
|
@@ -1723,16 +1735,40 @@ backtrace_command_1 (char *count_exp, in |
|
|
} |
|
|
} |
|
|
|
|
|
- for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) |
|
|
+ if (! no_filters) |
|
|
{ |
|
|
- QUIT; |
|
|
+ int flags = PRINT_LEVEL | PRINT_FRAME_INFO | PRINT_ARGS; |
|
|
+ enum py_frame_args arg_type; |
|
|
|
|
|
- /* Don't use print_stack_frame; if an error() occurs it probably |
|
|
- means further attempts to backtrace would fail (on the other |
|
|
- hand, perhaps the code does or could be fixed to make sure |
|
|
- the frame->prev field gets set to NULL in that case). */ |
|
|
- print_frame_info (fi, 1, LOCATION, 1); |
|
|
if (show_locals) |
|
|
+ flags |= PRINT_LOCALS; |
|
|
+ |
|
|
+ if (!strcmp (print_frame_arguments, "scalars")) |
|
|
+ arg_type = CLI_SCALAR_VALUES; |
|
|
+ else if (!strcmp (print_frame_arguments, "all")) |
|
|
+ arg_type = CLI_ALL_VALUES; |
|
|
+ else |
|
|
+ arg_type = NO_VALUES; |
|
|
+ |
|
|
+ result = apply_frame_filter (get_current_frame (), flags, arg_type, |
|
|
+ current_uiout, py_start, py_end); |
|
|
+ |
|
|
+ } |
|
|
+ /* Run the inbuilt backtrace if there are no filters registered, or |
|
|
+ "no-filters" has been specified from the command. */ |
|
|
+ if (no_filters || result == PY_BT_NO_FILTERS) |
|
|
+ { |
|
|
+ for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) |
|
|
+ { |
|
|
+ QUIT; |
|
|
+ |
|
|
+ /* Don't use print_stack_frame; if an error() occurs it probably |
|
|
+ means further attempts to backtrace would fail (on the other |
|
|
+ hand, perhaps the code does or could be fixed to make sure |
|
|
+ the frame->prev field gets set to NULL in that case). */ |
|
|
+ |
|
|
+ print_frame_info (fi, 1, LOCATION, 1); |
|
|
+ if (show_locals) |
|
|
{ |
|
|
struct frame_id frame_id = get_frame_id (fi); |
|
|
|
|
|
@@ -1748,24 +1784,25 @@ backtrace_command_1 (char *count_exp, in |
|
|
} |
|
|
} |
|
|
|
|
|
- /* Save the last frame to check for error conditions. */ |
|
|
- trailing = fi; |
|
|
- } |
|
|
+ /* Save the last frame to check for error conditions. */ |
|
|
+ trailing = fi; |
|
|
+ } |
|
|
|
|
|
- /* If we've stopped before the end, mention that. */ |
|
|
- if (fi && from_tty) |
|
|
- printf_filtered (_("(More stack frames follow...)\n")); |
|
|
+ /* If we've stopped before the end, mention that. */ |
|
|
+ if (fi && from_tty) |
|
|
+ printf_filtered (_("(More stack frames follow...)\n")); |
|
|
|
|
|
- /* If we've run out of frames, and the reason appears to be an error |
|
|
- condition, print it. */ |
|
|
- if (fi == NULL && trailing != NULL) |
|
|
- { |
|
|
- enum unwind_stop_reason reason; |
|
|
+ /* If we've run out of frames, and the reason appears to be an error |
|
|
+ condition, print it. */ |
|
|
+ if (fi == NULL && trailing != NULL) |
|
|
+ { |
|
|
+ enum unwind_stop_reason reason; |
|
|
|
|
|
- reason = get_frame_unwind_stop_reason (trailing); |
|
|
- if (reason >= UNWIND_FIRST_ERROR) |
|
|
- printf_filtered (_("Backtrace stopped: %s\n"), |
|
|
- frame_stop_reason_string (reason)); |
|
|
+ reason = get_frame_unwind_stop_reason (trailing); |
|
|
+ if (reason >= UNWIND_FIRST_ERROR) |
|
|
+ printf_filtered (_("Backtrace stopped: %s\n"), |
|
|
+ frame_stop_reason_string (reason)); |
|
|
+ } |
|
|
} |
|
|
} |
|
|
|
|
|
@@ -1773,7 +1810,8 @@ static void |
|
|
backtrace_command (char *arg, int from_tty) |
|
|
{ |
|
|
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); |
|
|
- int fulltrace_arg = -1, arglen = 0, argc = 0; |
|
|
+ int fulltrace_arg = -1, arglen = 0, argc = 0, no_filters = -1; |
|
|
+ int user_arg = 0; |
|
|
|
|
|
if (arg) |
|
|
{ |
|
|
@@ -1790,25 +1828,31 @@ backtrace_command (char *arg, int from_t |
|
|
for (j = 0; j < strlen (argv[i]); j++) |
|
|
argv[i][j] = tolower (argv[i][j]); |
|
|
|
|
|
- if (fulltrace_arg < 0 && subset_compare (argv[i], "full")) |
|
|
- fulltrace_arg = argc; |
|
|
+ if (no_filters < 0 && subset_compare (argv[i], "no-filters")) |
|
|
+ no_filters = argc; |
|
|
else |
|
|
{ |
|
|
- arglen += strlen (argv[i]); |
|
|
- argc++; |
|
|
+ if (fulltrace_arg < 0 && subset_compare (argv[i], "full")) |
|
|
+ fulltrace_arg = argc; |
|
|
+ else |
|
|
+ { |
|
|
+ user_arg++; |
|
|
+ arglen += strlen (argv[i]); |
|
|
+ } |
|
|
} |
|
|
+ argc++; |
|
|
} |
|
|
- arglen += argc; |
|
|
- if (fulltrace_arg >= 0) |
|
|
+ arglen += user_arg; |
|
|
+ if (fulltrace_arg >= 0 || no_filters >= 0) |
|
|
{ |
|
|
if (arglen > 0) |
|
|
{ |
|
|
arg = xmalloc (arglen + 1); |
|
|
make_cleanup (xfree, arg); |
|
|
arg[0] = 0; |
|
|
- for (i = 0; i < (argc + 1); i++) |
|
|
+ for (i = 0; i < argc; i++) |
|
|
{ |
|
|
- if (i != fulltrace_arg) |
|
|
+ if (i != fulltrace_arg && i != no_filters) |
|
|
{ |
|
|
strcat (arg, argv[i]); |
|
|
strcat (arg, " "); |
|
|
@@ -1820,7 +1864,8 @@ backtrace_command (char *arg, int from_t |
|
|
} |
|
|
} |
|
|
|
|
|
- backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */, from_tty); |
|
|
+ backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */, |
|
|
+ no_filters >= 0 /* no frame-filters */, from_tty); |
|
|
|
|
|
do_cleanups (old_chain); |
|
|
} |
|
|
@@ -1828,7 +1873,7 @@ backtrace_command (char *arg, int from_t |
|
|
static void |
|
|
backtrace_full_command (char *arg, int from_tty) |
|
|
{ |
|
|
- backtrace_command_1 (arg, 1 /* show_locals */, from_tty); |
|
|
+ backtrace_command_1 (arg, 1 /* show_locals */, 0, from_tty); |
|
|
} |
|
|
|
|
|
|
|
|
@@ -2562,7 +2607,9 @@ It can be a stack frame number or the ad |
|
|
add_com ("backtrace", class_stack, backtrace_command, _("\ |
|
|
Print backtrace of all stack frames, or innermost COUNT frames.\n\ |
|
|
With a negative argument, print outermost -COUNT frames.\nUse of the \ |
|
|
-'full' qualifier also prints the values of the local variables.\n")); |
|
|
+'full' qualifier also prints the values of the local variables.\n\ |
|
|
+Use of the 'no-filters' qualifier prohibits frame filters from executing\n\ |
|
|
+on this backtrace.\n")); |
|
|
add_com_alias ("bt", "backtrace", class_stack, 0); |
|
|
if (xdb_commands) |
|
|
{ |
|
|
Index: gdb-7.6/gdb/data-directory/Makefile.in |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/data-directory/Makefile.in 2013-06-10 14:31:02.710084660 +0200 |
|
|
+++ gdb-7.6/gdb/data-directory/Makefile.in 2013-06-10 14:31:08.355082441 +0200 |
|
|
@@ -53,7 +53,11 @@ PYTHON_DIR = python |
|
|
PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR) |
|
|
PYTHON_FILES = \ |
|
|
gdb/__init__.py \ |
|
|
+ gdb/frames.py \ |
|
|
+ gdb/FrameIterator.py \ |
|
|
+ gdb/FrameDecorator.py \ |
|
|
gdb/command/__init__.py \ |
|
|
+ gdb/command/frame_filters.py \ |
|
|
gdb/command/ignore_errors.py \ |
|
|
gdb/command/pahole.py \ |
|
|
gdb/command/type_printers.py \ |
|
|
Index: gdb-7.6/gdb/doc/gdb.texinfo |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/doc/gdb.texinfo 2013-06-10 14:31:02.727084654 +0200 |
|
|
+++ gdb-7.6/gdb/doc/gdb.texinfo 2013-06-10 14:31:08.364082438 +0200 |
|
|
@@ -6459,6 +6459,7 @@ currently executing frame and describes |
|
|
@menu |
|
|
* Frames:: Stack frames |
|
|
* Backtrace:: Backtraces |
|
|
+* Frame Filter Management:: Managing frame filters |
|
|
* Selection:: Selecting a frame |
|
|
* Frame Info:: Information on a frame |
|
|
|
|
|
@@ -6546,6 +6547,7 @@ line per frame, for many frames, startin |
|
|
frame (frame zero), followed by its caller (frame one), and on up the |
|
|
stack. |
|
|
|
|
|
+@anchor{backtrace-command} |
|
|
@table @code |
|
|
@kindex backtrace |
|
|
@kindex bt @r{(@code{backtrace})} |
|
|
@@ -6571,6 +6573,19 @@ Similar, but print only the outermost @v |
|
|
@itemx bt full -@var{n} |
|
|
Print the values of the local variables also. @var{n} specifies the |
|
|
number of frames to print, as described above. |
|
|
+ |
|
|
+@item backtrace no-filters |
|
|
+@itemx bt no-filters |
|
|
+@itemx bt no-filters @var{n} |
|
|
+@itemx bt no-filters -@var{n} |
|
|
+@itemx bt no-filters full |
|
|
+@itemx bt no-filters full @var{n} |
|
|
+@itemx bt no-filters full -@var{n} |
|
|
+Do not run Python frame filters on this backtrace. @xref{Frame |
|
|
+Filter API}, for more information. Additionally use @ref{disable |
|
|
+frame-filter all} to turn off all frame filters. This is only |
|
|
+relevant when @value{GDBN} has been configured with @code{Python} |
|
|
+support. |
|
|
@end table |
|
|
|
|
|
@kindex where |
|
|
@@ -6720,6 +6735,149 @@ Display an absolute filename. |
|
|
Show the current way to display filenames. |
|
|
@end table |
|
|
|
|
|
+@node Frame Filter Management |
|
|
+@section Management of Frame Filters. |
|
|
+@cindex managing frame filters |
|
|
+ |
|
|
+Frame filters are Python based utilities to manage and decorate the |
|
|
+output of frames. @xref{Frame Filter API}, for further information. |
|
|
+ |
|
|
+Managing frame filters is performed by several commands available |
|
|
+within @value{GDBN}, detailed here. |
|
|
+ |
|
|
+@table @code |
|
|
+@kindex info frame-filter |
|
|
+@item info frame-filter |
|
|
+Print a list of installed frame filters from all dictionaries, showing |
|
|
+their name, priority and enabled status. |
|
|
+ |
|
|
+@kindex disable frame-filter |
|
|
+@anchor{disable frame-filter all} |
|
|
+@item disable frame-filter @var{filter-dictionary} @var{filter-name} |
|
|
+Disable a frame filter in the dictionary matching |
|
|
+@var{filter-dictionary}, or @code{all}, and @var{filter-name}. |
|
|
+@var{filter-dictionary} may be @code{all}, @code{global}, |
|
|
+@code{progspace} or the name of the object file where the frame filter |
|
|
+dictionary resides. When @code{all} is specified, all frame filters |
|
|
+across all dictionaries are disabled. @var{filter-name} is the name |
|
|
+of the frame filter and is used when @code{all} is not the option for |
|
|
+@var{filter-dictionary}. A disabled frame-filter is not deleted, it |
|
|
+may be enabled again later. |
|
|
+ |
|
|
+@kindex enable frame-filter |
|
|
+@item enable frame-filter @var{filter-dictionary} @var{filter-name} |
|
|
+Enable a frame filter in the dictionary matching |
|
|
+@var{filter-dictionary}, or @code{all}, and @var{filter-name}. |
|
|
+@var{filter-dictionary} may be @code{all}, @code{global}, |
|
|
+@code{progspace} or the name of the object file where the frame filter |
|
|
+dictionary resides. When @code{all} is specified, all frame filters across |
|
|
+all dictionaries are enabled. @var{filter-name} is the name of the frame |
|
|
+filter and is used when @code{all} is not the option for |
|
|
+@var{filter-dictionary}. |
|
|
+ |
|
|
+Example: |
|
|
+ |
|
|
+@smallexample |
|
|
+(gdb) info frame-filter |
|
|
+ |
|
|
+global frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 1000 No PrimaryFunctionFilter |
|
|
+ 100 Yes Reverse |
|
|
+ |
|
|
+progspace /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 100 Yes ProgspaceFilter |
|
|
+ |
|
|
+objfile /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 999 Yes BuildProgra Filter |
|
|
+ |
|
|
+(gdb) disable frame-filter /build/test BuildProgramFilter |
|
|
+(gdb) info frame-filter |
|
|
+ |
|
|
+global frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 1000 No PrimaryFunctionFilter |
|
|
+ 100 Yes Reverse |
|
|
+ |
|
|
+progspace /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 100 Yes ProgspaceFilter |
|
|
+ |
|
|
+objfile /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 999 No BuildProgramFilter |
|
|
+ |
|
|
+(gdb) enable frame-filter global PrimaryFunctionFilter |
|
|
+(gdb) info frame-filter |
|
|
+ |
|
|
+global frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 1000 Yes PrimaryFunctionFilter |
|
|
+ 100 Yes Reverse |
|
|
+ |
|
|
+progspace /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 100 Yes ProgspaceFilter |
|
|
+ |
|
|
+objfile /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 999 No BuildProgramFilter |
|
|
+@end smallexample |
|
|
+ |
|
|
+@kindex set frame-filter priority |
|
|
+@item set frame-filter priority @var{filter-dictionary} @var{filter-name} @var{priority} |
|
|
+Set the @var{priority} of a frame filter in the dictionary matching |
|
|
+@var{filter-dictionary}, and the frame filter name matching |
|
|
+@var{filter-name}. @var{filter-dictionary} may be @code{global}, |
|
|
+@code{progspace} or the name of the object file where the frame filter |
|
|
+dictionary resides. @var{priority} is an integer. |
|
|
+ |
|
|
+@kindex show frame-filter priority |
|
|
+@item show frame-filter priority @var{filter-dictionary} @var{filter-name} |
|
|
+Show the @var{priority} of a frame filter in the dictionary matching |
|
|
+@var{filter-dictionary}, and the frame filter name matching |
|
|
+@var{filter-name}. @var{filter-dictionary} may be @code{global}, |
|
|
+@code{progspace} or the name of the object file where the frame filter |
|
|
+dictionary resides. |
|
|
+ |
|
|
+Example: |
|
|
+ |
|
|
+@smallexample |
|
|
+(gdb) info frame-filter |
|
|
+ |
|
|
+global frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 1000 Yes PrimaryFunctionFilter |
|
|
+ 100 Yes Reverse |
|
|
+ |
|
|
+progspace /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 100 Yes ProgspaceFilter |
|
|
+ |
|
|
+objfile /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 999 No BuildProgramFilter |
|
|
+ |
|
|
+(gdb) set frame-filter priority global Reverse 50 |
|
|
+(gdb) info frame-filter |
|
|
+ |
|
|
+global frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 1000 Yes PrimaryFunctionFilter |
|
|
+ 50 Yes Reverse |
|
|
+ |
|
|
+progspace /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 100 Yes ProgspaceFilter |
|
|
+ |
|
|
+objfile /build/test frame-filters: |
|
|
+ Priority Enabled Name |
|
|
+ 999 No BuildProgramFilter |
|
|
+@end smallexample |
|
|
+@end table |
|
|
+ |
|
|
@node Selection |
|
|
@section Selecting a Frame |
|
|
|
|
|
@@ -23100,6 +23258,9 @@ situation, a Python @code{KeyboardInterr |
|
|
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer. |
|
|
* Writing a Pretty-Printer:: Writing a Pretty-Printer. |
|
|
* Type Printing API:: Pretty-printing types. |
|
|
+* Frame Filter API:: Filtering Frames. |
|
|
+* Frame Decorator API:: Decorating Frames. |
|
|
+* Writing a Frame Filter:: Writing a Frame Filter. |
|
|
* Inferiors In Python:: Python representation of inferiors (processes) |
|
|
* Events In Python:: Listening for events from @value{GDBN}. |
|
|
* Threads In Python:: Accessing inferior threads from Python. |
|
|
@@ -24450,6 +24611,636 @@ done then type printers would have to ma |
|
|
order to avoid holding information that could become stale as the |
|
|
inferior changed. |
|
|
|
|
|
+@node Frame Filter API |
|
|
+@subsubsection Filtering Frames. |
|
|
+@cindex frame filters api |
|
|
+ |
|
|
+Frame filters are Python objects that manipulate the visibility of a |
|
|
+frame or frames when a backtrace (@pxref{Backtrace}) is printed by |
|
|
+@value{GDBN}. |
|
|
+ |
|
|
+Only commands that print a backtrace, or, in the case of @sc{gdb/mi} |
|
|
+commands (@pxref{GDB/MI}), those that return a collection of frames |
|
|
+are affected. The commands that work with frame filters are: |
|
|
+ |
|
|
+@code{backtrace} (@pxref{backtrace-command,, The backtrace command}), |
|
|
+@code{-stack-list-frames} |
|
|
+(@pxref{-stack-list-frames,, The -stack-list-frames command}), |
|
|
+@code{-stack-list-variables} (@pxref{-stack-list-variables,, The |
|
|
+-stack-list-variables command}), @code{-stack-list-arguments} |
|
|
+@pxref{-stack-list-arguments,, The -stack-list-arguments command}) and |
|
|
+@code{-stack-list-locals} (@pxref{-stack-list-locals,, The |
|
|
+-stack-list-locals command}). |
|
|
+ |
|
|
+A frame filter works by taking an iterator as an argument, applying |
|
|
+actions to the contents of that iterator, and returning another |
|
|
+iterator (or, possibly, the same iterator it was provided in the case |
|
|
+where the filter does not perform any operations). Typically, frame |
|
|
+filters utilize tools such as the Python's @code{itertools} module to |
|
|
+work with and create new iterators from the source iterator. |
|
|
+Regardless of how a filter chooses to apply actions, it must not alter |
|
|
+the underlying @value{GDBN} frame or frames, or attempt to alter the |
|
|
+call-stack within @value{GDBN}. This preserves data integrity within |
|
|
+@value{GDBN}. Frame filters are executed on a priority basis and care |
|
|
+should be taken that some frame filters may have been executed before, |
|
|
+and that some frame filters will be executed after. |
|
|
+ |
|
|
+An important consideration when designing frame filters, and well |
|
|
+worth reflecting upon, is that frame filters should avoid unwinding |
|
|
+the call stack if possible. Some stacks can run very deep, into the |
|
|
+tens of thousands in some cases. To search every frame when a frame |
|
|
+filter executes may be too expensive at that step. The frame filter |
|
|
+cannot know how many frames it has to iterate over, and it may have to |
|
|
+iterate through them all. This ends up duplicating effort as |
|
|
+@value{GDBN} performs this iteration when it prints the frames. If |
|
|
+the filter can defer unwinding frames until frame decorators are |
|
|
+executed, after the last filter has executed, it should. @xref{Frame |
|
|
+Decorator API}, for more information on decorators. Also, there are |
|
|
+examples for both frame decorators and filters in later chapters. |
|
|
+@xref{Writing a Frame Filter}, for more information. |
|
|
+ |
|
|
+The Python dictionary @code{gdb.frame_filters} contains key/object |
|
|
+pairings that comprise a frame filter. Frame filters in this |
|
|
+dictionary are called @code{global} frame filters, and they are |
|
|
+available when debugging all inferiors. These frame filters must |
|
|
+register with the dictionary directly. In addition to the |
|
|
+@code{global} dictionary, there are other dictionaries that are loaded |
|
|
+with different inferiors via auto-loading (@pxref{Python |
|
|
+Auto-loading}). The two other areas where frame filter dictionaries |
|
|
+can be found are: @code{gdb.Progspace} which contains a |
|
|
+@code{frame_filters} dictionary attribute, and each @code{gdb.Objfile} |
|
|
+object which also contains a @code{frame_filters} dictionary |
|
|
+attribute. |
|
|
+ |
|
|
+When a command is executed from @value{GDBN} that is compatible with |
|
|
+frame filters, @value{GDBN} combines the @code{global}, |
|
|
+@code{gdb.Progspace} and all @code{gdb.Objfile} dictionaries currently |
|
|
+loaded. All of the @code{gdb.Objfile} dictionaries are combined, as |
|
|
+several frames, and thus several object files, might be in use. |
|
|
+@value{GDBN} then prunes any frame filter whose @code{enabled} |
|
|
+attribute is @code{False}. This pruned list is then sorted according |
|
|
+to the @code{priority} attribute in each filter. |
|
|
+ |
|
|
+Once the dictionaries are combined, pruned and sorted, @value{GDBN} |
|
|
+creates an iterator which wraps each frame in the call stack in a |
|
|
+@code{FrameDecorator} object, and calls each filter in order. The |
|
|
+output from the previous filter will always be the input to the next |
|
|
+filter, and so on. |
|
|
+ |
|
|
+Frame filters have a mandatory interface which each frame filter must |
|
|
+implement, defined here: |
|
|
+ |
|
|
+@defun FrameFilter.filter (iterator) |
|
|
+@value{GDBN} will call this method on a frame filter when it has |
|
|
+reached the order in the priority list for that filter. |
|
|
+ |
|
|
+For example, if there are four frame filters: |
|
|
+ |
|
|
+@smallexample |
|
|
+Name Priority |
|
|
+ |
|
|
+Filter1 5 |
|
|
+Filter2 10 |
|
|
+Filter3 100 |
|
|
+Filter4 1 |
|
|
+@end smallexample |
|
|
+ |
|
|
+The order that the frame filters will be called is: |
|
|
+ |
|
|
+@smallexample |
|
|
+Filter3 -> Filter2 -> Filter1 -> Filter4 |
|
|
+@end smallexample |
|
|
+ |
|
|
+Note that the output from @code{Filter3} is passed to the input of |
|
|
+@code{Filter2}, and so on. |
|
|
+ |
|
|
+This @code{filter} method is passed a Python iterator. This iterator |
|
|
+contains a sequence of frame decorators that wrap each |
|
|
+@code{gdb.Frame}, or a frame decorator that wraps another frame |
|
|
+decorator. The first filter that is executed in the sequence of frame |
|
|
+filters will receive an iterator entirely comprised of default |
|
|
+@code{FrameDecorator} objects. However, after each frame filter is |
|
|
+executed, the previous frame filter may have wrapped some or all of |
|
|
+the frame decorators with their own frame decorator. As frame |
|
|
+decorators must also conform to a mandatory interface, these |
|
|
+decorators can be assumed to act in a uniform manner (@pxref{Frame |
|
|
+Decorator API}). |
|
|
+ |
|
|
+This method must return an object conforming to the Python iterator |
|
|
+protocol. Each item in the iterator must be an object conforming to |
|
|
+the frame decorator interface. If a frame filter does not wish to |
|
|
+perform any operations on this iterator, it should return that |
|
|
+iterator untouched. |
|
|
+ |
|
|
+This method is not optional. If it does not exist, @value{GDBN} will |
|
|
+raise and print an error. |
|
|
+@end defun |
|
|
+ |
|
|
+@defvar FrameFilter.name |
|
|
+The @code{name} attribute must be Python string which contains the |
|
|
+name of the filter displayed by @value{GDBN} (@pxref{Frame Filter |
|
|
+Management}). This attribute may contain any combination of letters |
|
|
+or numbers. Care should be taken to ensure that it is unique. This |
|
|
+attribute is mandatory. |
|
|
+@end defvar |
|
|
+ |
|
|
+@defvar FrameFilter.enabled |
|
|
+The @code{enabled} attribute must be Python boolean. This attribute |
|
|
+indicates to @value{GDBN} whether the frame filter is enabled, and |
|
|
+should be considered when frame filters are executed. If |
|
|
+@code{enabled} is @code{True}, then the frame filter will be executed |
|
|
+when any of the backtrace commands detailed earlier in this chapter |
|
|
+are executed. If @code{enabled} is @code{False}, then the frame |
|
|
+filter will not be executed. This attribute is mandatory. |
|
|
+@end defvar |
|
|
+ |
|
|
+@defvar FrameFilter.priority |
|
|
+The @code{priority} attribute must be Python integer. This attribute |
|
|
+controls the order of execution in relation to other frame filters. |
|
|
+There are no imposed limits on the range of @code{priority} other than |
|
|
+it must be a valid integer. The higher the @code{priority} attribute, |
|
|
+the sooner the frame filter will be executed in relation to other |
|
|
+frame filters. Although @code{priority} can be negative, it is |
|
|
+recommended practice to assume zero is the lowest priority that a |
|
|
+frame filter can be assigned. Frame filters that have the same |
|
|
+priority are executed in unsorted order in that priority slot. This |
|
|
+attribute is mandatory. |
|
|
+@end defvar |
|
|
+ |
|
|
+@node Frame Decorator API |
|
|
+@subsubsection Decorating Frames. |
|
|
+@cindex frame decorator api |
|
|
+ |
|
|
+Frame decorators are sister objects to frame filters (@pxref{Frame |
|
|
+Filter API}). Frame decorators are applied by a frame filter and can |
|
|
+only be used in conjunction with frame filters. |
|
|
+ |
|
|
+The purpose of a frame decorator is to customize the printed content |
|
|
+of each @code{gdb.Frame} in commands where frame filters are executed. |
|
|
+This concept is called decorating a frame. Frame decorators decorate |
|
|
+a @code{gdb.Frame} with Python code contained within each API call. |
|
|
+This separates the actual data contained in a @code{gdb.Frame} from |
|
|
+the decorated data produced by a frame decorator. This abstraction is |
|
|
+necessary to maintain integrity of the data contained in each |
|
|
+@code{gdb.Frame}. |
|
|
+ |
|
|
+Frame decorators have a mandatory interface, defined below. |
|
|
+ |
|
|
+@value{GDBN} already contains a frame decorator called |
|
|
+@code{FrameDecorator}. This contains substantial amounts of |
|
|
+boilerplate code to decorate the content of a @code{gdb.Frame}. It is |
|
|
+recommended that other frame decorators inherit and extend this |
|
|
+object, and only to override the methods needed. |
|
|
+ |
|
|
+@defun FrameDecorator.elided (self) |
|
|
+ |
|
|
+The @code{elided} method groups frames together in a hierarchical |
|
|
+system. An example would be an interpreter, where multiple low-level |
|
|
+frames make up a single call in the interpreted language. In this |
|
|
+example, the frame filter would elide the low-level frames and present |
|
|
+a single high-level frame, representing the call in the interpreted |
|
|
+language, to the user. |
|
|
+ |
|
|
+The @code{elided} function must return an iterable and this iterable |
|
|
+must contain the frames that are being elided wrapped in a suitable |
|
|
+frame decorator. If no frames are being elided this function may |
|
|
+return an empty iterable, or @code{None}. Elided frames are indented |
|
|
+from normal frames in a @code{CLI} backtrace, or in the case of |
|
|
+@code{GDB/MI}, are placed in the @code{children} field of the eliding |
|
|
+frame. |
|
|
+ |
|
|
+It is the frame filter's task to also filter out the elided frames from |
|
|
+the source iterator. This will avoid printing the frame twice. |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.function (self) |
|
|
+ |
|
|
+This method returns the name of the function in the frame that is to |
|
|
+be printed. |
|
|
+ |
|
|
+This method must return a Python string describing the function, or |
|
|
+@code{None}. |
|
|
+ |
|
|
+If this function returns @code{None}, @value{GDBN} will not print any |
|
|
+data for this field. |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.address (self) |
|
|
+ |
|
|
+This method returns the address of the frame that is to be printed. |
|
|
+ |
|
|
+This method must return a Python numeric integer type of sufficient |
|
|
+size to describe the address of the frame, or @code{None}. |
|
|
+ |
|
|
+If this function returns a @code{None}, @value{GDBN} will not print |
|
|
+any data for this field. |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.filename (self) |
|
|
+ |
|
|
+This method returns the filename and path associated with this frame. |
|
|
+ |
|
|
+This method must return a Python string containing the filename and |
|
|
+the path to the object file backing the frame, or @code{None}. |
|
|
+ |
|
|
+If this function returns a @code{None}, @value{GDBN} will not print |
|
|
+any data for this field. |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.line (self): |
|
|
+ |
|
|
+This method returns the line number associated with the current |
|
|
+position within the function addressed by this frame. |
|
|
+ |
|
|
+This method must return a Python integer type, or @code{None}. |
|
|
+ |
|
|
+If this function returns a @code{None}, @value{GDBN} will not print |
|
|
+any data for this field. |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.frame_args (self) |
|
|
+@anchor{frame_args} |
|
|
+ |
|
|
+This method must return an iterable, or @code{None}. Returning an |
|
|
+empty iterable, or @code{None} means frame arguments will not be |
|
|
+printed for this frame. This iterable must contain objects that |
|
|
+implement two methods, described here. |
|
|
+ |
|
|
+This object must implement a @code{argument} method which takes a |
|
|
+single @code{self} parameter and must return a @code{gdb.Symbol} |
|
|
+(@pxref{Symbols In Python}), or a Python string. The object must also |
|
|
+implement a @code{value} method which takes a single @code{self} |
|
|
+parameter and must return a @code{gdb.Value} (@pxref{Values From |
|
|
+Inferior}), a Python value, or @code{None}. If the @code{value} |
|
|
+method returns @code{None}, and the @code{argument} method returns a |
|
|
+@code{gdb.Symbol}, @value{GDBN} will look-up and print the value of |
|
|
+the @code{gdb.Symbol} automatically. |
|
|
+ |
|
|
+A brief example: |
|
|
+ |
|
|
+@smallexample |
|
|
+class SymValueWrapper(): |
|
|
+ |
|
|
+ def __init__(self, symbol, value): |
|
|
+ self.sym = symbol |
|
|
+ self.val = value |
|
|
+ |
|
|
+ def value(self): |
|
|
+ return self.val |
|
|
+ |
|
|
+ def symbol(self): |
|
|
+ return self.sym |
|
|
+ |
|
|
+class SomeFrameDecorator() |
|
|
+... |
|
|
+... |
|
|
+ def frame_args(self): |
|
|
+ args = [] |
|
|
+ try: |
|
|
+ block = self.inferior_frame.block() |
|
|
+ except: |
|
|
+ return None |
|
|
+ |
|
|
+ # Iterate over all symbols in a block. Only add |
|
|
+ # symbols that are arguments. |
|
|
+ for sym in block: |
|
|
+ if not sym.is_argument: |
|
|
+ continue |
|
|
+ args.append(SymValueWrapper(sym,None)) |
|
|
+ |
|
|
+ # Add example synthetic argument. |
|
|
+ args.append(SymValueWrapper(``foo'', 42)) |
|
|
+ |
|
|
+ return args |
|
|
+@end smallexample |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.frame_locals (self) |
|
|
+ |
|
|
+This method must return an iterable or @code{None}. Returning an |
|
|
+empty iterable, or @code{None} means frame local arguments will not be |
|
|
+printed for this frame. |
|
|
+ |
|
|
+The object interface, the description of the various strategies for |
|
|
+reading frame locals, and the example are largely similar to those |
|
|
+described in the @code{frame_args} function, (@pxref{frame_args,,The |
|
|
+frame filter frame_args function}). Below is a modified example: |
|
|
+ |
|
|
+@smallexample |
|
|
+class SomeFrameDecorator() |
|
|
+... |
|
|
+... |
|
|
+ def frame_locals(self): |
|
|
+ vars = [] |
|
|
+ try: |
|
|
+ block = self.inferior_frame.block() |
|
|
+ except: |
|
|
+ return None |
|
|
+ |
|
|
+ # Iterate over all symbols in a block. Add all |
|
|
+ # symbols, except arguments. |
|
|
+ for sym in block: |
|
|
+ if sym.is_argument: |
|
|
+ continue |
|
|
+ vars.append(SymValueWrapper(sym,None)) |
|
|
+ |
|
|
+ # Add an example of a synthetic local variable. |
|
|
+ vars.append(SymValueWrapper(``bar'', 99)) |
|
|
+ |
|
|
+ return vars |
|
|
+@end smallexample |
|
|
+@end defun |
|
|
+ |
|
|
+@defun FrameDecorator.inferior_frame (self): |
|
|
+ |
|
|
+This method must return the underlying @code{gdb.Frame} that this |
|
|
+frame decorator is decorating. @value{GDBN} requires the underlying |
|
|
+frame for internal frame information to determine how to print certain |
|
|
+values when printing a frame. |
|
|
+@end defun |
|
|
+ |
|
|
+@node Writing a Frame Filter |
|
|
+@subsubsection Writing a Frame Filter |
|
|
+@cindex writing a frame filter |
|
|
+ |
|
|
+There are three basic elements that a frame filter must implement: it |
|
|
+must correctly implement the documented interface (@pxref{Frame Filter |
|
|
+API}), it must register itself with @value{GDBN}, and finally, it must |
|
|
+decide if it is to work on the data provided by @value{GDBN}. In all |
|
|
+cases, whether it works on the iterator or not, each frame filter must |
|
|
+return an iterator. A bare-bones frame filter follows the pattern in |
|
|
+the following example. |
|
|
+ |
|
|
+@smallexample |
|
|
+import gdb |
|
|
+ |
|
|
+class FrameFilter(): |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ # Frame filter attribute creation. |
|
|
+ # |
|
|
+ # 'name' is the name of the filter that GDB will display. |
|
|
+ # |
|
|
+ # 'priority' is the priority of the filter relative to other |
|
|
+ # filters. |
|
|
+ # |
|
|
+ # 'enabled' is a boolean that indicates whether this filter is |
|
|
+ # enabled and should be executed. |
|
|
+ |
|
|
+ self.name = "Foo" |
|
|
+ self.priority = 100 |
|
|
+ self.enabled = True |
|
|
+ |
|
|
+ # Register this frame filter with the global frame_filters |
|
|
+ # dictionary. |
|
|
+ gdb.frame_filters[self.name] = self |
|
|
+ |
|
|
+ def filter(self, frame_iter): |
|
|
+ # Just return the iterator. |
|
|
+ return frame_iter |
|
|
+@end smallexample |
|
|
+ |
|
|
+The frame filter in the example above implements the three |
|
|
+requirements for all frame filters. It implements the API, self |
|
|
+registers, and makes a decision on the iterator (in this case, it just |
|
|
+returns the iterator untouched). |
|
|
+ |
|
|
+The first step is attribute creation and assignment, and as shown in |
|
|
+the comments the filter assigns the following attributes: @code{name}, |
|
|
+@code{priority} and whether the filter should be enabled with the |
|
|
+@code{enabled} attribute. |
|
|
+ |
|
|
+The second step is registering the frame filter with the dictionary or |
|
|
+dictionaries that the frame filter has interest in. As shown in the |
|
|
+comments, this filter just registers itself with the global dictionary |
|
|
+@code{gdb.frame_filters}. As noted earlier, @code{gdb.frame_filters} |
|
|
+is a dictionary that is initialized in the @code{gdb} module when |
|
|
+@value{GDBN} starts. What dictionary a filter registers with is an |
|
|
+important consideration. Generally, if a filter is specific to a set |
|
|
+of code, it should be registered either in the @code{objfile} or |
|
|
+@code{progspace} dictionaries as they are specific to the program |
|
|
+currently loaded in @value{GDBN}. The global dictionary is always |
|
|
+present in @value{GDBN} and is never unloaded. Any filters registered |
|
|
+with the global dictionary will exist until @value{GDBN} exits. To |
|
|
+avoid filters that may conflict, it is generally better to register |
|
|
+frame filters against the dictionaries that more closely align with |
|
|
+the usage of the filter currently in question. @xref{Python |
|
|
+Auto-loading}, for further information on auto-loading Python scripts. |
|
|
+ |
|
|
+@value{GDBN} takes a hands-off approach to frame filter registration, |
|
|
+therefore it is the frame filter's responsibility to ensure |
|
|
+registration has occurred, and that any exceptions are handled |
|
|
+appropriately. In particular, you may wish to handle exceptions |
|
|
+relating to Python dictionary key uniqueness. It is mandatory that |
|
|
+the dictionary key is the same as frame filter's @code{name} |
|
|
+attribute. When a user manages frame filters (@pxref{Frame Filter |
|
|
+Management}), the names @value{GDBN} will display are those contained |
|
|
+in the @code{name} attribute. |
|
|
+ |
|
|
+The final step of this example is the implementation of the |
|
|
+@code{filter} method. As shown in the example comments, we define the |
|
|
+@code{filter} method and note that the method must take an iterator, |
|
|
+and also must return an iterator. In this bare-bones example, the |
|
|
+frame filter is not very useful as it just returns the iterator |
|
|
+untouched. However this is a valid operation for frame filters that |
|
|
+have the @code{enabled} attribute set, but decide not to operate on |
|
|
+any frames. |
|
|
+ |
|
|
+In the next example, the frame filter operates on all frames and |
|
|
+utilizes a frame decorator to perform some work on the frames. |
|
|
+@xref{Frame Decorator API}, for further information on the frame |
|
|
+decorator interface. |
|
|
+ |
|
|
+This example works on inlined frames. It highlights frames which are |
|
|
+inlined by tagging them with an ``[inlined]'' tag. By applying a |
|
|
+frame decorator to all frames with the Python @code{itertools imap} |
|
|
+method, the example defers actions to the frame decorator. Frame |
|
|
+decorators are only processed when @value{GDBN} prints the backtrace. |
|
|
+ |
|
|
+This introduces a new decision making topic: whether to perform |
|
|
+decision making operations at the filtering step, or at the printing |
|
|
+step. In this example's approach, it does not perform any filtering |
|
|
+decisions at the filtering step beyond mapping a frame decorator to |
|
|
+each frame. This allows the actual decision making to be performed |
|
|
+when each frame is printed. This is an important consideration, and |
|
|
+well worth reflecting upon when designing a frame filter. An issue |
|
|
+that frame filters should avoid is unwinding the stack if possible. |
|
|
+Some stacks can run very deep, into the tens of thousands in some |
|
|
+cases. To search every frame to determine if it is inlined ahead of |
|
|
+time may be too expensive at the filtering step. The frame filter |
|
|
+cannot know how many frames it has to iterate over, and it would have |
|
|
+to iterate through them all. This ends up duplicating effort as |
|
|
+@value{GDBN} performs this iteration when it prints the frames. |
|
|
+ |
|
|
+In this example decision making can be deferred to the printing step. |
|
|
+As each frame is printed, the frame decorator can examine each frame |
|
|
+in turn when @value{GDBN} iterates. From a performance viewpoint, |
|
|
+this is the most appropriate decision to make as it avoids duplicating |
|
|
+the effort that the printing step would undertake anyway. Also, if |
|
|
+there are many frame filters unwinding the stack during filtering, it |
|
|
+can substantially delay the printing of the backtrace which will |
|
|
+result in large memory usage, and a poor user experience. |
|
|
+ |
|
|
+@smallexample |
|
|
+class InlineFilter(): |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ self.name = "InlinedFrameFilter" |
|
|
+ self.priority = 100 |
|
|
+ self.enabled = True |
|
|
+ gdb.frame_filters[self.name] = self |
|
|
+ |
|
|
+ def filter(self, frame_iter): |
|
|
+ frame_iter = itertools.imap(InlinedFrameDecorator, |
|
|
+ frame_iter) |
|
|
+ return frame_iter |
|
|
+@end smallexample |
|
|
+ |
|
|
+This frame filter is somewhat similar to the earlier example, except |
|
|
+that the @code{filter} method applies a frame decorator object called |
|
|
+@code{InlinedFrameDecorator} to each element in the iterator. The |
|
|
+@code{imap} Python method is light-weight. It does not proactively |
|
|
+iterate over the iterator, but rather creates a new iterator which |
|
|
+wraps the existing one. |
|
|
+ |
|
|
+Below is the frame decorator for this example. |
|
|
+ |
|
|
+@smallexample |
|
|
+class InlinedFrameDecorator(FrameDecorator): |
|
|
+ |
|
|
+ def __init__(self, fobj): |
|
|
+ super(InlinedFrameDecorator, self).__init__(fobj) |
|
|
+ |
|
|
+ def function(self): |
|
|
+ frame = fobj.inferior_frame() |
|
|
+ name = str(frame.name()) |
|
|
+ |
|
|
+ if frame.type() == gdb.INLINE_FRAME: |
|
|
+ name = name + " [inlined]" |
|
|
+ |
|
|
+ return name |
|
|
+@end smallexample |
|
|
+ |
|
|
+This frame decorator only defines and overrides the @code{function} |
|
|
+method. It lets the supplied @code{FrameDecorator}, which is shipped |
|
|
+with @value{GDBN}, perform the other work associated with printing |
|
|
+this frame. |
|
|
+ |
|
|
+The combination of these two objects create this output from a |
|
|
+backtrace: |
|
|
+ |
|
|
+@smallexample |
|
|
+#0 0x004004e0 in bar () at inline.c:11 |
|
|
+#1 0x00400566 in max [inlined] (b=6, a=12) at inline.c:21 |
|
|
+#2 0x00400566 in main () at inline.c:31 |
|
|
+@end smallexample |
|
|
+ |
|
|
+So in the case of this example, a frame decorator is applied to all |
|
|
+frames, regardless of whether they may be inlined or not. As |
|
|
+@value{GDBN} iterates over the iterator produced by the frame filters, |
|
|
+@value{GDBN} executes each frame decorator which then makes a decision |
|
|
+on what to print in the @code{function} callback. Using a strategy |
|
|
+like this is a way to defer decisions on the frame content to printing |
|
|
+time. |
|
|
+ |
|
|
+@subheading Eliding Frames |
|
|
+ |
|
|
+It might be that the above example is not desirable for representing |
|
|
+inlined frames, and a hierarchical approach may be preferred. If we |
|
|
+want to hierarchically represent frames, the @code{elided} frame |
|
|
+decorator interface might be preferable. |
|
|
+ |
|
|
+This example approaches the issue with the @code{elided} method. This |
|
|
+example is quite long, but very simplistic. It is out-of-scope for |
|
|
+this section to write a complete example that comprehensively covers |
|
|
+all approaches of finding and printing inlined frames. However, this |
|
|
+example illustrates the approach an author might use. |
|
|
+ |
|
|
+This example comprises of three sections. |
|
|
+ |
|
|
+@smallexample |
|
|
+class InlineFrameFilter(): |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ self.name = "InlinedFrameFilter" |
|
|
+ self.priority = 100 |
|
|
+ self.enabled = True |
|
|
+ gdb.frame_filters[self.name] = self |
|
|
+ |
|
|
+ def filter(self, frame_iter): |
|
|
+ return ElidingInlineIterator(frame_iter) |
|
|
+@end smallexample |
|
|
+ |
|
|
+This frame filter is very similar to the other examples. The only |
|
|
+difference is this frame filter is wrapping the iterator provided to |
|
|
+it (@code{frame_iter}) with a custom iterator called |
|
|
+@code{ElidingInlineIterator}. This again defers actions to when |
|
|
+@value{GDBN} prints the backtrace, as the iterator is not traversed |
|
|
+until printing. |
|
|
+ |
|
|
+The iterator for this example is as follows. It is in this section of |
|
|
+the example where decisions are made on the content of the backtrace. |
|
|
+ |
|
|
+@smallexample |
|
|
+class ElidingInlineIterator: |
|
|
+ def __init__(self, ii): |
|
|
+ self.input_iterator = ii |
|
|
+ |
|
|
+ def __iter__(self): |
|
|
+ return self |
|
|
+ |
|
|
+ def next(self): |
|
|
+ frame = next(self.input_iterator) |
|
|
+ |
|
|
+ if frame.inferior_frame().type() != gdb.INLINE_FRAME: |
|
|
+ return frame |
|
|
+ |
|
|
+ try: |
|
|
+ eliding_frame = next(self.input_iterator) |
|
|
+ except StopIteration: |
|
|
+ return frame |
|
|
+ return ElidingFrameDecorator(eliding_frame, [frame]) |
|
|
+@end smallexample |
|
|
+ |
|
|
+This iterator implements the Python iterator protocol. When the |
|
|
+@code{next} function is called (when @value{GDBN} prints each frame), |
|
|
+the iterator checks if this frame decorator, @code{frame}, is wrapping |
|
|
+an inlined frame. If it is not, it returns the existing frame decorator |
|
|
+untouched. If it is wrapping an inlined frame, it assumes that the |
|
|
+inlined frame was contained within the next oldest frame, |
|
|
+@code{eliding_frame}, which it fetches. It then creates and returns a |
|
|
+frame decorator, @code{ElidingFrameDecorator}, which contains both the |
|
|
+elided frame, and the eliding frame. |
|
|
+ |
|
|
+@smallexample |
|
|
+class ElidingInlineDecorator(FrameDecorator): |
|
|
+ |
|
|
+ def __init__(self, frame, elided_frames): |
|
|
+ super(ElidingInlineDecorator, self).__init__(frame) |
|
|
+ self.frame = frame |
|
|
+ self.elided_frames = elided_frames |
|
|
+ |
|
|
+ def elided(self): |
|
|
+ return iter(self.elided_frames) |
|
|
+@end smallexample |
|
|
+ |
|
|
+This frame decorator overrides one function and returns the inlined |
|
|
+frame in the @code{elided} method. As before it lets |
|
|
+@code{FrameDecorator} do the rest of the work involved in printing |
|
|
+this frame. This produces the following output. |
|
|
+ |
|
|
+@smallexample |
|
|
+#0 0x004004e0 in bar () at inline.c:11 |
|
|
+#2 0x00400529 in main () at inline.c:25 |
|
|
+ #1 0x00400529 in max (b=6, a=12) at inline.c:15 |
|
|
+@end smallexample |
|
|
+ |
|
|
+In that output, @code{max} which has been inlined into @code{main} is |
|
|
+printed hierarchically. Another approach would be to combine the |
|
|
+@code{function} method, and the @code{elided} method to both print a |
|
|
+marker in the inlined frame, and also show the hierarchical |
|
|
+relationship. |
|
|
+ |
|
|
@node Inferiors In Python |
|
|
@subsubsection Inferiors In Python |
|
|
@cindex inferiors in Python |
|
|
@@ -25280,6 +26071,11 @@ The @code{type_printers} attribute is a |
|
|
@xref{Type Printing API}, for more information. |
|
|
@end defvar |
|
|
|
|
|
+@defvar Progspace.frame_filters |
|
|
+The @code{frame_filters} attribute is a dictionary of frame filter |
|
|
+objects. @xref{Frame Filter API}, for more information. |
|
|
+@end defvar |
|
|
+ |
|
|
@node Objfiles In Python |
|
|
@subsubsection Objfiles In Python |
|
|
|
|
|
@@ -25330,6 +26126,11 @@ The @code{type_printers} attribute is a |
|
|
@xref{Type Printing API}, for more information. |
|
|
@end defvar |
|
|
|
|
|
+@defvar Objfile.frame_filters |
|
|
+The @code{frame_filters} attribute is a dictionary of frame filter |
|
|
+objects. @xref{Frame Filter API}, for more information. |
|
|
+@end defvar |
|
|
+ |
|
|
A @code{gdb.Objfile} object has the following methods: |
|
|
|
|
|
@defun Objfile.is_valid () |
|
|
@@ -26348,7 +27149,7 @@ No my-foo-pretty-printers.py |
|
|
When reading an auto-loaded file, @value{GDBN} sets the |
|
|
@dfn{current objfile}. This is available via the @code{gdb.current_objfile} |
|
|
function (@pxref{Objfiles In Python}). This can be useful for |
|
|
-registering objfile-specific pretty-printers. |
|
|
+registering objfile-specific pretty-printers and frame-filters. |
|
|
|
|
|
@menu |
|
|
* objfile-gdb.py file:: The @file{@var{objfile}-gdb.py} file |
|
|
@@ -30219,6 +31020,22 @@ Is this going away???? |
|
|
@node GDB/MI Stack Manipulation |
|
|
@section @sc{gdb/mi} Stack Manipulation Commands |
|
|
|
|
|
+@subheading The @code{-enable-frame-filters} Command |
|
|
+@findex -enable-frame-filters |
|
|
+ |
|
|
+@smallexample |
|
|
+-enable-frame-filters |
|
|
+@end smallexample |
|
|
+ |
|
|
+@value{GDBN} allows Python-based frame filters to affect the output of |
|
|
+the MI commands relating to stack traces. As there is no way to |
|
|
+implement this in a fully backward-compatible way, a front end must |
|
|
+request that this functionality be enabled. |
|
|
+ |
|
|
+Once enabled, this feature cannot be disabled. |
|
|
+ |
|
|
+Note that if Python support has not been compiled into @value{GDBN}, |
|
|
+this command will still succeed (and do nothing). |
|
|
|
|
|
@subheading The @code{-stack-info-frame} Command |
|
|
@findex -stack-info-frame |
|
|
@@ -30286,13 +31103,14 @@ For a stack with frame levels 0 through |
|
|
(gdb) |
|
|
@end smallexample |
|
|
|
|
|
+@anchor{-stack-list-arguments} |
|
|
@subheading The @code{-stack-list-arguments} Command |
|
|
@findex -stack-list-arguments |
|
|
|
|
|
@subsubheading Synopsis |
|
|
|
|
|
@smallexample |
|
|
- -stack-list-arguments @var{print-values} |
|
|
+ -stack-list-arguments [ --no-frame-filters ] @var{print-values} |
|
|
[ @var{low-frame} @var{high-frame} ] |
|
|
@end smallexample |
|
|
|
|
|
@@ -30309,7 +31127,9 @@ If @var{print-values} is 0 or @code{--no |
|
|
the variables; if it is 1 or @code{--all-values}, print also their |
|
|
values; and if it is 2 or @code{--simple-values}, print the name, |
|
|
type and value for simple data types, and the name and type for arrays, |
|
|
-structures and unions. |
|
|
+structures and unions. If the option @code{--no-frame-filters} is |
|
|
+supplied, then Python frame filters will not be executed. |
|
|
+ |
|
|
|
|
|
Use of this command to obtain arguments in a single frame is |
|
|
deprecated in favor of the @samp{-stack-list-variables} command. |
|
|
@@ -30380,13 +31200,14 @@ args=[@{name="intarg",value="2"@}, |
|
|
@c @subheading -stack-list-exception-handlers |
|
|
|
|
|
|
|
|
+@anchor{-stack-list-frames} |
|
|
@subheading The @code{-stack-list-frames} Command |
|
|
@findex -stack-list-frames |
|
|
|
|
|
@subsubheading Synopsis |
|
|
|
|
|
@smallexample |
|
|
- -stack-list-frames [ @var{low-frame} @var{high-frame} ] |
|
|
+ -stack-list-frames [ --no-frame-filters @var{low-frame} @var{high-frame} ] |
|
|
@end smallexample |
|
|
|
|
|
List the frames currently on the stack. For each frame it displays the |
|
|
@@ -30416,7 +31237,9 @@ levels are between the two arguments (in |
|
|
are equal, it shows the single frame at the corresponding level. It is |
|
|
an error if @var{low-frame} is larger than the actual number of |
|
|
frames. On the other hand, @var{high-frame} may be larger than the |
|
|
-actual number of frames, in which case only existing frames will be returned. |
|
|
+actual number of frames, in which case only existing frames will be |
|
|
+returned. If the option @code{--no-frame-filters} is supplied, then |
|
|
+Python frame filters will not be executed. |
|
|
|
|
|
@subsubheading @value{GDBN} Command |
|
|
|
|
|
@@ -30486,11 +31309,12 @@ Show a single frame: |
|
|
|
|
|
@subheading The @code{-stack-list-locals} Command |
|
|
@findex -stack-list-locals |
|
|
+@anchor{-stack-list-locals} |
|
|
|
|
|
@subsubheading Synopsis |
|
|
|
|
|
@smallexample |
|
|
- -stack-list-locals @var{print-values} |
|
|
+ -stack-list-locals [ --no-frame-filters ] @var{print-values} |
|
|
@end smallexample |
|
|
|
|
|
Display the local variable names for the selected frame. If |
|
|
@@ -30501,7 +31325,8 @@ type and value for simple data types, an |
|
|
structures and unions. In this last case, a frontend can immediately |
|
|
display the value of simple data types and create variable objects for |
|
|
other data types when the user wishes to explore their values in |
|
|
-more detail. |
|
|
+more detail. If the option @code{--no-frame-filters} is supplied, then |
|
|
+Python frame filters will not be executed. |
|
|
|
|
|
This command is deprecated in favor of the |
|
|
@samp{-stack-list-variables} command. |
|
|
@@ -30526,13 +31351,14 @@ This command is deprecated in favor of t |
|
|
(gdb) |
|
|
@end smallexample |
|
|
|
|
|
+@anchor{-stack-list-variables} |
|
|
@subheading The @code{-stack-list-variables} Command |
|
|
@findex -stack-list-variables |
|
|
|
|
|
@subsubheading Synopsis |
|
|
|
|
|
@smallexample |
|
|
- -stack-list-variables @var{print-values} |
|
|
+ -stack-list-variables [ --no-frame-filters ] @var{print-values} |
|
|
@end smallexample |
|
|
|
|
|
Display the names of local variables and function arguments for the selected frame. If |
|
|
@@ -30540,7 +31366,8 @@ Display the names of local variables and |
|
|
the variables; if it is 1 or @code{--all-values}, print also their |
|
|
values; and if it is 2 or @code{--simple-values}, print the name, |
|
|
type and value for simple data types, and the name and type for arrays, |
|
|
-structures and unions. |
|
|
+structures and unions. If the option @code{--no-frame-filters} is |
|
|
+supplied, then Python frame filters will not be executed. |
|
|
|
|
|
@subsubheading Example |
|
|
|
|
|
Index: gdb-7.6/gdb/mi/mi-cmd-stack.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/mi/mi-cmd-stack.c 2013-06-10 14:31:02.730084652 +0200 |
|
|
+++ gdb-7.6/gdb/mi/mi-cmd-stack.c 2013-06-10 14:31:08.365082437 +0200 |
|
|
@@ -31,6 +31,10 @@ |
|
|
#include "language.h" |
|
|
#include "valprint.h" |
|
|
#include "exceptions.h" |
|
|
+#include "utils.h" |
|
|
+#include "mi-getopt.h" |
|
|
+#include "python/python.h" |
|
|
+#include <ctype.h> |
|
|
|
|
|
enum what_to_list { locals, arguments, all }; |
|
|
|
|
|
@@ -38,6 +42,28 @@ static void list_args_or_locals (enum wh |
|
|
enum print_values values, |
|
|
struct frame_info *fi); |
|
|
|
|
|
+/* True if we want to allow Python-based frame filters. */ |
|
|
+static int frame_filters = 0; |
|
|
+ |
|
|
+void |
|
|
+mi_cmd_enable_frame_filters (char *command, char **argv, int argc) |
|
|
+{ |
|
|
+ if (argc != 0) |
|
|
+ error (_("-enable-frame-filters: no arguments allowed")); |
|
|
+ frame_filters = 1; |
|
|
+} |
|
|
+ |
|
|
+/* Parse the --no-frame-filters option in commands where we cannot use |
|
|
+ mi_getopt. */ |
|
|
+static int |
|
|
+parse_no_frames_option (const char *arg) |
|
|
+{ |
|
|
+ if (arg && (strcmp (arg, "--no-frame-filters") == 0)) |
|
|
+ return 1; |
|
|
+ |
|
|
+ return 0; |
|
|
+} |
|
|
+ |
|
|
/* Print a list of the stack frames. Args can be none, in which case |
|
|
we want to print the whole backtrace, or a pair of numbers |
|
|
specifying the frame numbers at which to start and stop the |
|
|
@@ -52,14 +78,46 @@ mi_cmd_stack_list_frames (char *command, |
|
|
int i; |
|
|
struct cleanup *cleanup_stack; |
|
|
struct frame_info *fi; |
|
|
+ enum py_bt_status result = PY_BT_ERROR; |
|
|
+ int raw_arg = 0; |
|
|
+ int oind = 0; |
|
|
+ enum opt |
|
|
+ { |
|
|
+ NO_FRAME_FILTERS |
|
|
+ }; |
|
|
+ static const struct mi_opt opts[] = |
|
|
+ { |
|
|
+ {"-no-frame-filters", NO_FRAME_FILTERS, 0}, |
|
|
+ { 0, 0, 0 } |
|
|
+ }; |
|
|
+ |
|
|
+ /* Parse arguments. In this instance we are just looking for |
|
|
+ --no-frame-filters. */ |
|
|
+ while (1) |
|
|
+ { |
|
|
+ char *oarg; |
|
|
+ int opt = mi_getopt ("-stack-list-frames", argc, argv, |
|
|
+ opts, &oind, &oarg); |
|
|
+ if (opt < 0) |
|
|
+ break; |
|
|
+ switch ((enum opt) opt) |
|
|
+ { |
|
|
+ case NO_FRAME_FILTERS: |
|
|
+ raw_arg = oind; |
|
|
+ break; |
|
|
+ } |
|
|
+ } |
|
|
|
|
|
- if (argc > 2 || argc == 1) |
|
|
- error (_("-stack-list-frames: Usage: [FRAME_LOW FRAME_HIGH]")); |
|
|
+ /* After the last option is parsed, there should either be low - |
|
|
+ high range, or no further arguments. */ |
|
|
+ if ((argc - oind != 0) && (argc - oind != 2)) |
|
|
+ error (_("-stack-list-frames: Usage: [--no-frame-filters] [FRAME_LOW FRAME_HIGH]")); |
|
|
|
|
|
- if (argc == 2) |
|
|
+ /* If there is a range, set it. */ |
|
|
+ if (argc - oind == 2) |
|
|
{ |
|
|
- frame_low = atoi (argv[0]); |
|
|
- frame_high = atoi (argv[1]); |
|
|
+ frame_low = atoi (argv[0 + oind]); |
|
|
+ frame_high = atoi (argv[1 + oind]); |
|
|
} |
|
|
else |
|
|
{ |
|
|
@@ -81,16 +139,37 @@ mi_cmd_stack_list_frames (char *command, |
|
|
|
|
|
cleanup_stack = make_cleanup_ui_out_list_begin_end (current_uiout, "stack"); |
|
|
|
|
|
- /* Now let's print the frames up to frame_high, or until there are |
|
|
- frames in the stack. */ |
|
|
- for (; |
|
|
- fi && (i <= frame_high || frame_high == -1); |
|
|
- i++, fi = get_prev_frame (fi)) |
|
|
+ if (! raw_arg && frame_filters) |
|
|
{ |
|
|
- QUIT; |
|
|
- /* Print the location and the address always, even for level 0. |
|
|
- If args is 0, don't print the arguments. */ |
|
|
- print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ ); |
|
|
+ int flags = PRINT_LEVEL | PRINT_FRAME_INFO; |
|
|
+ int py_frame_low = frame_low; |
|
|
+ |
|
|
+ /* We cannot pass -1 to frame_low, as that would signify a |
|
|
+ relative backtrace from the tail of the stack. So, in the case |
|
|
+ of frame_low == -1, assign and increment it. */ |
|
|
+ if (py_frame_low == -1) |
|
|
+ py_frame_low++; |
|
|
+ |
|
|
+ result = apply_frame_filter (get_current_frame (), flags, |
|
|
+ NO_VALUES, current_uiout, |
|
|
+ py_frame_low, frame_high); |
|
|
+ } |
|
|
+ |
|
|
+ /* Run the inbuilt backtrace if there are no filters registered, or |
|
|
+ if "--no-frame-filters" has been specified from the command. */ |
|
|
+ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) |
|
|
+ { |
|
|
+ /* Now let's print the frames up to frame_high, or until there are |
|
|
+ frames in the stack. */ |
|
|
+ for (; |
|
|
+ fi && (i <= frame_high || frame_high == -1); |
|
|
+ i++, fi = get_prev_frame (fi)) |
|
|
+ { |
|
|
+ QUIT; |
|
|
+ /* Print the location and the address always, even for level 0. |
|
|
+ If args is 0, don't print the arguments. */ |
|
|
+ print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ ); |
|
|
+ } |
|
|
} |
|
|
|
|
|
do_cleanups (cleanup_stack); |
|
|
@@ -147,13 +226,34 @@ void |
|
|
mi_cmd_stack_list_locals (char *command, char **argv, int argc) |
|
|
{ |
|
|
struct frame_info *frame; |
|
|
+ int raw_arg = 0; |
|
|
+ enum py_bt_status result = PY_BT_ERROR; |
|
|
+ int print_value; |
|
|
+ |
|
|
+ if (argc > 0) |
|
|
+ raw_arg = parse_no_frames_option (argv[0]); |
|
|
+ |
|
|
+ if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg) |
|
|
+ || (argc == 1 && raw_arg)) |
|
|
+ error (_("-stack-list-locals: Usage: [--no-frame-filters] PRINT_VALUES")); |
|
|
|
|
|
- if (argc != 1) |
|
|
- error (_("-stack-list-locals: Usage: PRINT_VALUES")); |
|
|
- |
|
|
- frame = get_selected_frame (NULL); |
|
|
+ frame = get_selected_frame (NULL); |
|
|
+ print_value = parse_print_values (argv[raw_arg]); |
|
|
|
|
|
- list_args_or_locals (locals, parse_print_values (argv[0]), frame); |
|
|
+ if (! raw_arg && frame_filters) |
|
|
+ { |
|
|
+ int flags = PRINT_LEVEL | PRINT_LOCALS; |
|
|
+ |
|
|
+ result = apply_frame_filter (frame, flags, print_value, |
|
|
+ current_uiout, 0, 0); |
|
|
+ } |
|
|
+ |
|
|
+ /* Run the inbuilt backtrace if there are no filters registered, or |
|
|
+ if "--no-frame-filters" has been specified from the command. */ |
|
|
+ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) |
|
|
+ { |
|
|
+ list_args_or_locals (locals, print_value, frame); |
|
|
+ } |
|
|
} |
|
|
|
|
|
/* Print a list of the arguments for the current frame. With argument |
|
|
@@ -170,15 +270,20 @@ mi_cmd_stack_list_args (char *command, c |
|
|
struct cleanup *cleanup_stack_args; |
|
|
enum print_values print_values; |
|
|
struct ui_out *uiout = current_uiout; |
|
|
+ int raw_arg = 0; |
|
|
+ enum py_bt_status result = PY_BT_ERROR; |
|
|
|
|
|
- if (argc < 1 || argc > 3 || argc == 2) |
|
|
- error (_("-stack-list-arguments: Usage: " |
|
|
- "PRINT_VALUES [FRAME_LOW FRAME_HIGH]")); |
|
|
+ if (argc > 0) |
|
|
+ raw_arg = parse_no_frames_option (argv[0]); |
|
|
|
|
|
- if (argc == 3) |
|
|
+ if (argc < 1 || (argc > 3 && ! raw_arg) || (argc == 2 && ! raw_arg)) |
|
|
+ error (_("-stack-list-arguments: Usage: " \ |
|
|
+ "[--no-frame-filters] PRINT_VALUES [FRAME_LOW FRAME_HIGH]")); |
|
|
+ |
|
|
+ if (argc >= 3) |
|
|
{ |
|
|
- frame_low = atoi (argv[1]); |
|
|
- frame_high = atoi (argv[2]); |
|
|
+ frame_low = atoi (argv[1 + raw_arg]); |
|
|
+ frame_high = atoi (argv[2 + raw_arg]); |
|
|
} |
|
|
else |
|
|
{ |
|
|
@@ -188,7 +293,7 @@ mi_cmd_stack_list_args (char *command, c |
|
|
frame_high = -1; |
|
|
} |
|
|
|
|
|
- print_values = parse_print_values (argv[0]); |
|
|
+ print_values = parse_print_values (argv[raw_arg]); |
|
|
|
|
|
/* Let's position fi on the frame at which to start the |
|
|
display. Could be the innermost frame if the whole stack needs |
|
|
@@ -203,21 +308,41 @@ mi_cmd_stack_list_args (char *command, c |
|
|
cleanup_stack_args |
|
|
= make_cleanup_ui_out_list_begin_end (uiout, "stack-args"); |
|
|
|
|
|
- /* Now let's print the frames up to frame_high, or until there are |
|
|
- frames in the stack. */ |
|
|
- for (; |
|
|
- fi && (i <= frame_high || frame_high == -1); |
|
|
- i++, fi = get_prev_frame (fi)) |
|
|
+ if (! raw_arg && frame_filters) |
|
|
{ |
|
|
- struct cleanup *cleanup_frame; |
|
|
+ int flags = PRINT_LEVEL | PRINT_ARGS; |
|
|
+ int py_frame_low = frame_low; |
|
|
|
|
|
- QUIT; |
|
|
- cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame"); |
|
|
- ui_out_field_int (uiout, "level", i); |
|
|
- list_args_or_locals (arguments, print_values, fi); |
|
|
- do_cleanups (cleanup_frame); |
|
|
+ /* We cannot pass -1 to frame_low, as that would signify a |
|
|
+ relative backtrace from the tail of the stack. So, in the case |
|
|
+ of frame_low == -1, assign and increment it. */ |
|
|
+ if (py_frame_low == -1) |
|
|
+ py_frame_low++; |
|
|
+ |
|
|
+ result = apply_frame_filter (get_current_frame (), flags, |
|
|
+ print_values, current_uiout, |
|
|
+ py_frame_low, frame_high); |
|
|
} |
|
|
|
|
|
+ /* Run the inbuilt backtrace if there are no filters registered, or |
|
|
+ if "--no-frame-filters" has been specified from the command. */ |
|
|
+ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) |
|
|
+ { |
|
|
+ /* Now let's print the frames up to frame_high, or until there are |
|
|
+ frames in the stack. */ |
|
|
+ for (; |
|
|
+ fi && (i <= frame_high || frame_high == -1); |
|
|
+ i++, fi = get_prev_frame (fi)) |
|
|
+ { |
|
|
+ struct cleanup *cleanup_frame; |
|
|
+ |
|
|
+ QUIT; |
|
|
+ cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame"); |
|
|
+ ui_out_field_int (uiout, "level", i); |
|
|
+ list_args_or_locals (arguments, print_values, fi); |
|
|
+ do_cleanups (cleanup_frame); |
|
|
+ } |
|
|
+ } |
|
|
do_cleanups (cleanup_stack_args); |
|
|
} |
|
|
|
|
|
@@ -230,13 +355,35 @@ void |
|
|
mi_cmd_stack_list_variables (char *command, char **argv, int argc) |
|
|
{ |
|
|
struct frame_info *frame; |
|
|
+ int raw_arg = 0; |
|
|
+ enum py_bt_status result = PY_BT_ERROR; |
|
|
+ int print_value; |
|
|
+ |
|
|
+ if (argc > 0) |
|
|
+ raw_arg = parse_no_frames_option (argv[0]); |
|
|
+ |
|
|
+ if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg) |
|
|
+ || (argc == 1 && raw_arg)) |
|
|
+ error (_("-stack-list-variables: Usage: " \ |
|
|
+ "[--no-frame-filters] PRINT_VALUES")); |
|
|
|
|
|
- if (argc != 1) |
|
|
- error (_("Usage: PRINT_VALUES")); |
|
|
- |
|
|
- frame = get_selected_frame (NULL); |
|
|
+ frame = get_selected_frame (NULL); |
|
|
+ print_value = parse_print_values (argv[raw_arg]); |
|
|
|
|
|
- list_args_or_locals (all, parse_print_values (argv[0]), frame); |
|
|
+ if (! raw_arg && frame_filters) |
|
|
+ { |
|
|
+ int flags = PRINT_LEVEL | PRINT_ARGS | PRINT_LOCALS; |
|
|
+ |
|
|
+ result = apply_frame_filter (frame, flags, print_value, |
|
|
+ current_uiout, 0, 0); |
|
|
+ } |
|
|
+ |
|
|
+ /* Run the inbuilt backtrace if there are no filters registered, or |
|
|
+ if "--no-frame-filters" has been specified from the command. */ |
|
|
+ if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS) |
|
|
+ { |
|
|
+ list_args_or_locals (all, print_value, frame); |
|
|
+ } |
|
|
} |
|
|
|
|
|
/* Print single local or argument. ARG must be already read in. For |
|
|
Index: gdb-7.6/gdb/mi/mi-cmds.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/mi/mi-cmds.c 2013-06-10 14:31:02.730084652 +0200 |
|
|
+++ gdb-7.6/gdb/mi/mi-cmds.c 2013-06-10 14:31:08.365082437 +0200 |
|
|
@@ -86,6 +86,7 @@ static struct mi_cmd mi_cmds[] = |
|
|
mi_cmd_data_write_register_values), |
|
|
DEF_MI_CMD_MI ("enable-timings", mi_cmd_enable_timings), |
|
|
DEF_MI_CMD_MI ("enable-pretty-printing", mi_cmd_enable_pretty_printing), |
|
|
+ DEF_MI_CMD_MI ("enable-frame-filters", mi_cmd_enable_frame_filters), |
|
|
DEF_MI_CMD_MI ("environment-cd", mi_cmd_env_cd), |
|
|
DEF_MI_CMD_MI ("environment-directory", mi_cmd_env_dir), |
|
|
DEF_MI_CMD_MI ("environment-path", mi_cmd_env_path), |
|
|
Index: gdb-7.6/gdb/mi/mi-cmds.h |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/mi/mi-cmds.h 2013-06-10 14:31:02.730084652 +0200 |
|
|
+++ gdb-7.6/gdb/mi/mi-cmds.h 2013-06-10 14:31:08.365082437 +0200 |
|
|
@@ -118,6 +118,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_show |
|
|
extern mi_cmd_argv_ftype mi_cmd_var_show_format; |
|
|
extern mi_cmd_argv_ftype mi_cmd_var_update; |
|
|
extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing; |
|
|
+extern mi_cmd_argv_ftype mi_cmd_enable_frame_filters; |
|
|
extern mi_cmd_argv_ftype mi_cmd_var_set_update_range; |
|
|
|
|
|
/* Description of a single command. */ |
|
|
Index: gdb-7.6/gdb/python/py-framefilter.c |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/python/py-framefilter.c 2013-06-10 14:31:08.366082437 +0200 |
|
|
@@ -0,0 +1,1528 @@ |
|
|
+/* Python frame filters |
|
|
+ |
|
|
+ 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/>. */ |
|
|
+ |
|
|
+#include "defs.h" |
|
|
+#include "objfiles.h" |
|
|
+#include "symtab.h" |
|
|
+#include "language.h" |
|
|
+#include "exceptions.h" |
|
|
+#include "arch-utils.h" |
|
|
+#include "python.h" |
|
|
+#include "ui-out.h" |
|
|
+#include "valprint.h" |
|
|
+#include "annotate.h" |
|
|
+#include "hashtab.h" |
|
|
+#include "demangle.h" |
|
|
+#include "mi/mi-cmds.h" |
|
|
+#include "python-internal.h" |
|
|
+ |
|
|
+enum mi_print_types |
|
|
+{ |
|
|
+ MI_PRINT_ARGS, |
|
|
+ MI_PRINT_LOCALS |
|
|
+}; |
|
|
+ |
|
|
+/* Helper function to extract a symbol, a name and a language |
|
|
+ definition from a Python object that conforms to the "Symbol Value" |
|
|
+ interface. OBJ is the Python object to extract the values from. |
|
|
+ NAME is a pass-through argument where the name of the symbol will |
|
|
+ be written. NAME is allocated in this function, but the caller is |
|
|
+ responsible for clean up. SYM is a pass-through argument where the |
|
|
+ symbol will be written. In the case of the API returning a string, |
|
|
+ this will be set to NULL. LANGUAGE is also a pass-through argument |
|
|
+ denoting the language attributed to the Symbol. In the case of SYM |
|
|
+ being NULL, this will be set to the current language. Returns |
|
|
+ PY_BT_ERROR on error with the appropriate Python exception set, and |
|
|
+ PY_BT_OK on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+extract_sym (PyObject *obj, char **name, struct symbol **sym, |
|
|
+ const struct language_defn **language) |
|
|
+{ |
|
|
+ PyObject *result = PyObject_CallMethod (obj, "symbol", NULL); |
|
|
+ |
|
|
+ if (result == NULL) |
|
|
+ return PY_BT_ERROR; |
|
|
+ |
|
|
+ /* For 'symbol' callback, the function can return a symbol or a |
|
|
+ string. */ |
|
|
+ if (gdbpy_is_string (result)) |
|
|
+ { |
|
|
+ *name = python_string_to_host_string (result); |
|
|
+ Py_DECREF (result); |
|
|
+ |
|
|
+ if (*name == NULL) |
|
|
+ return PY_BT_ERROR; |
|
|
+ /* If the API returns a string (and not a symbol), then there is |
|
|
+ no symbol derived language available and the frame filter has |
|
|
+ either overridden the symbol with a string, or supplied a |
|
|
+ entirely synthetic symbol/value pairing. In that case, use |
|
|
+ python_language. */ |
|
|
+ *language = python_language; |
|
|
+ *sym = NULL; |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ /* This type checks 'result' during the conversion so we |
|
|
+ just call it unconditionally and check the return. */ |
|
|
+ *sym = symbol_object_to_symbol (result); |
|
|
+ |
|
|
+ Py_DECREF (result); |
|
|
+ |
|
|
+ if (*sym == NULL) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_RuntimeError, |
|
|
+ _("Unexpected value. Expecting a " |
|
|
+ "gdb.Symbol or a Python string.")); |
|
|
+ return PY_BT_ERROR; |
|
|
+ } |
|
|
+ |
|
|
+ /* Duplicate the symbol name, so the caller has consistency |
|
|
+ in garbage collection. */ |
|
|
+ *name = xstrdup (SYMBOL_PRINT_NAME (*sym)); |
|
|
+ |
|
|
+ /* If a symbol is specified attempt to determine the language |
|
|
+ from the symbol. If mode is not "auto", then the language |
|
|
+ has been explicitly set, use that. */ |
|
|
+ if (language_mode == language_mode_auto) |
|
|
+ *language = language_def (SYMBOL_LANGUAGE (*sym)); |
|
|
+ else |
|
|
+ *language = current_language; |
|
|
+ } |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function to extract a value from an object that conforms to |
|
|
+ the "Symbol Value" interface. OBJ is the Python object to extract |
|
|
+ the value from. VALUE is a pass-through argument where the value |
|
|
+ will be written. If the object does not have the value attribute, |
|
|
+ or provides the Python None for a value, VALUE will be set to NULL |
|
|
+ and this function will return as successful. Returns PY_BT_ERROR |
|
|
+ on error with the appropriate Python exception set, and PY_BT_OK on |
|
|
+ success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+extract_value (PyObject *obj, struct value **value) |
|
|
+{ |
|
|
+ if (PyObject_HasAttrString (obj, "value")) |
|
|
+ { |
|
|
+ PyObject *vresult = PyObject_CallMethod (obj, "value", NULL); |
|
|
+ |
|
|
+ if (vresult == NULL) |
|
|
+ return PY_BT_ERROR; |
|
|
+ |
|
|
+ /* The Python code has returned 'None' for a value, so we set |
|
|
+ value to NULL. This flags that GDB should read the |
|
|
+ value. */ |
|
|
+ if (vresult == Py_None) |
|
|
+ { |
|
|
+ Py_DECREF (vresult); |
|
|
+ *value = NULL; |
|
|
+ return PY_BT_OK; |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ *value = convert_value_from_python (vresult); |
|
|
+ Py_DECREF (vresult); |
|
|
+ |
|
|
+ if (*value == NULL) |
|
|
+ return PY_BT_ERROR; |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+ } |
|
|
+ } |
|
|
+ else |
|
|
+ *value = NULL; |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+} |
|
|
+ |
|
|
+/* MI prints only certain values according to the type of symbol and |
|
|
+ also what the user has specified. SYM is the symbol to check, and |
|
|
+ MI_PRINT_TYPES is an enum specifying what the user wants emitted |
|
|
+ for the MI command in question. */ |
|
|
+static int |
|
|
+mi_should_print (struct symbol *sym, enum mi_print_types type) |
|
|
+{ |
|
|
+ int print_me = 0; |
|
|
+ |
|
|
+ switch (SYMBOL_CLASS (sym)) |
|
|
+ { |
|
|
+ default: |
|
|
+ case LOC_UNDEF: /* catches errors */ |
|
|
+ case LOC_CONST: /* constant */ |
|
|
+ case LOC_TYPEDEF: /* local typedef */ |
|
|
+ case LOC_LABEL: /* local label */ |
|
|
+ case LOC_BLOCK: /* local function */ |
|
|
+ case LOC_CONST_BYTES: /* loc. byte seq. */ |
|
|
+ case LOC_UNRESOLVED: /* unresolved static */ |
|
|
+ case LOC_OPTIMIZED_OUT: /* optimized out */ |
|
|
+ print_me = 0; |
|
|
+ break; |
|
|
+ |
|
|
+ case LOC_ARG: /* argument */ |
|
|
+ case LOC_REF_ARG: /* reference arg */ |
|
|
+ case LOC_REGPARM_ADDR: /* indirect register arg */ |
|
|
+ case LOC_LOCAL: /* stack local */ |
|
|
+ case LOC_STATIC: /* static */ |
|
|
+ case LOC_REGISTER: /* register */ |
|
|
+ case LOC_COMPUTED: /* computed location */ |
|
|
+ if (type == MI_PRINT_LOCALS) |
|
|
+ print_me = ! SYMBOL_IS_ARGUMENT (sym); |
|
|
+ else |
|
|
+ print_me = SYMBOL_IS_ARGUMENT (sym); |
|
|
+ } |
|
|
+ return print_me; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function which outputs a type name extracted from VAL to a |
|
|
+ "type" field in the output stream OUT. OUT is the ui-out structure |
|
|
+ the type name will be output too, and VAL is the value that the |
|
|
+ type will be extracted from. Returns PY_BT_ERROR on error, with |
|
|
+ any GDB exceptions converted to a Python exception, or PY_BT_OK on |
|
|
+ success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_type (struct ui_out *out, struct value *val) |
|
|
+{ |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ struct type *type; |
|
|
+ struct ui_file *stb; |
|
|
+ struct cleanup *cleanup; |
|
|
+ |
|
|
+ stb = mem_fileopen (); |
|
|
+ cleanup = make_cleanup_ui_file_delete (stb); |
|
|
+ type = check_typedef (value_type (val)); |
|
|
+ type_print (value_type (val), "", stb, -1); |
|
|
+ ui_out_field_stream (out, "type", stb); |
|
|
+ do_cleanups (cleanup); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ return PY_BT_ERROR; |
|
|
+ } |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function which outputs a value to an output field in a |
|
|
+ stream. OUT is the ui-out structure the value will be output to, |
|
|
+ VAL is the value that will be printed, OPTS contains the value |
|
|
+ printing options, ARGS_TYPE is an enumerator describing the |
|
|
+ argument format, and LANGUAGE is the language_defn that the value |
|
|
+ will be printed with. Returns PY_BT_ERROR on error, with any GDB |
|
|
+ exceptions converted to a Python exception, or PY_BT_OK on |
|
|
+ success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_value (struct ui_out *out, struct value *val, |
|
|
+ const struct value_print_options *opts, |
|
|
+ int indent, |
|
|
+ enum py_frame_args args_type, |
|
|
+ const struct language_defn *language) |
|
|
+{ |
|
|
+ int should_print = 0; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ int local_indent = (4 * indent); |
|
|
+ |
|
|
+ /* Never set an indent level for common_val_print if MI. */ |
|
|
+ if (ui_out_is_mi_like_p (out)) |
|
|
+ local_indent = 0; |
|
|
+ |
|
|
+ /* MI does not print certain values, differentiated by type, |
|
|
+ depending on what ARGS_TYPE indicates. Test type against option. |
|
|
+ For CLI print all values. */ |
|
|
+ if (args_type == MI_PRINT_SIMPLE_VALUES |
|
|
+ || args_type == MI_PRINT_ALL_VALUES) |
|
|
+ { |
|
|
+ struct type *type = NULL; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ type = check_typedef (value_type (val)); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ return PY_BT_ERROR; |
|
|
+ } |
|
|
+ |
|
|
+ if (args_type == MI_PRINT_ALL_VALUES) |
|
|
+ should_print = 1; |
|
|
+ else if (args_type == MI_PRINT_SIMPLE_VALUES |
|
|
+ && TYPE_CODE (type) != TYPE_CODE_ARRAY |
|
|
+ && TYPE_CODE (type) != TYPE_CODE_STRUCT |
|
|
+ && TYPE_CODE (type) != TYPE_CODE_UNION) |
|
|
+ should_print = 1; |
|
|
+ } |
|
|
+ else if (args_type != NO_VALUES) |
|
|
+ should_print = 1; |
|
|
+ |
|
|
+ if (should_print) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ struct ui_file *stb; |
|
|
+ struct cleanup *cleanup; |
|
|
+ |
|
|
+ stb = mem_fileopen (); |
|
|
+ cleanup = make_cleanup_ui_file_delete (stb); |
|
|
+ common_val_print (val, stb, indent, opts, language); |
|
|
+ ui_out_field_stream (out, "value", stb); |
|
|
+ do_cleanups (cleanup); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ return PY_BT_ERROR; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function to call a Python method and extract an iterator |
|
|
+ from the result. If the function returns anything but an iterator |
|
|
+ the exception is preserved and NULL is returned. FILTER is the |
|
|
+ Python object to call, and FUNC is the name of the method. Returns |
|
|
+ a PyObject, or NULL on error with the appropriate exception set. |
|
|
+ This function can return an iterator, or NULL. */ |
|
|
+ |
|
|
+static PyObject * |
|
|
+get_py_iter_from_func (PyObject *filter, char *func) |
|
|
+{ |
|
|
+ if (PyObject_HasAttrString (filter, func)) |
|
|
+ { |
|
|
+ PyObject *result = PyObject_CallMethod (filter, func, NULL); |
|
|
+ |
|
|
+ if (result != NULL) |
|
|
+ { |
|
|
+ if (result == Py_None) |
|
|
+ { |
|
|
+ return result; |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ PyObject *iterator = PyObject_GetIter (result); |
|
|
+ |
|
|
+ Py_DECREF (result); |
|
|
+ return iterator; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ else |
|
|
+ Py_RETURN_NONE; |
|
|
+ |
|
|
+ return NULL; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function to output a single frame argument and value to an |
|
|
+ output stream. This function will account for entry values if the |
|
|
+ FV parameter is populated, the frame argument has entry values |
|
|
+ associated with them, and the appropriate "set entry-value" |
|
|
+ options are set. Will output in CLI or MI like format depending |
|
|
+ on the type of output stream detected. OUT is the output stream, |
|
|
+ SYM_NAME is the name of the symbol. If SYM_NAME is populated then |
|
|
+ it must have an accompanying value in the parameter FV. FA is a |
|
|
+ frame argument structure. If FA is populated, both SYM_NAME and |
|
|
+ FV are ignored. OPTS contains the value printing options, |
|
|
+ ARGS_TYPE is an enumerator describing the argument format, |
|
|
+ PRINT_ARGS_FIELD is a flag which indicates if we output "ARGS=1" |
|
|
+ in MI output in commands where both arguments and locals are |
|
|
+ printed. Returns PY_BT_ERROR on error, with any GDB exceptions |
|
|
+ converted to a Python exception, or PY_BT_OK on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_single_arg (struct ui_out *out, |
|
|
+ const char *sym_name, |
|
|
+ struct frame_arg *fa, |
|
|
+ struct value *fv, |
|
|
+ const struct value_print_options *opts, |
|
|
+ enum py_frame_args args_type, |
|
|
+ int print_args_field, |
|
|
+ const struct language_defn *language) |
|
|
+{ |
|
|
+ struct value *val; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ if (fa != NULL) |
|
|
+ { |
|
|
+ language = language_def (SYMBOL_LANGUAGE (fa->sym)); |
|
|
+ val = fa->val; |
|
|
+ } |
|
|
+ else |
|
|
+ val = fv; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); |
|
|
+ |
|
|
+ /* MI has varying rules for tuples, but generally if there is only |
|
|
+ one element in each item in the list, do not start a tuple. The |
|
|
+ exception is -stack-list-variables which emits an ARGS="1" field |
|
|
+ if the value is a frame argument. This is denoted in this |
|
|
+ function with PRINT_ARGS_FIELD which is flag from the caller to |
|
|
+ emit the ARGS field. */ |
|
|
+ if (ui_out_is_mi_like_p (out)) |
|
|
+ { |
|
|
+ if (print_args_field || args_type != NO_VALUES) |
|
|
+ make_cleanup_ui_out_tuple_begin_end (out, NULL); |
|
|
+ } |
|
|
+ |
|
|
+ annotate_arg_begin (); |
|
|
+ |
|
|
+ /* If frame argument is populated, check for entry-values and the |
|
|
+ entry value options. */ |
|
|
+ if (fa != NULL) |
|
|
+ { |
|
|
+ struct ui_file *stb; |
|
|
+ |
|
|
+ stb = mem_fileopen (); |
|
|
+ make_cleanup_ui_file_delete (stb); |
|
|
+ fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym), |
|
|
+ SYMBOL_LANGUAGE (fa->sym), |
|
|
+ DMGL_PARAMS | DMGL_ANSI); |
|
|
+ if (fa->entry_kind == print_entry_values_compact) |
|
|
+ { |
|
|
+ fputs_filtered ("=", stb); |
|
|
+ |
|
|
+ fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym), |
|
|
+ SYMBOL_LANGUAGE (fa->sym), |
|
|
+ DMGL_PARAMS | DMGL_ANSI); |
|
|
+ } |
|
|
+ if (fa->entry_kind == print_entry_values_only |
|
|
+ || fa->entry_kind == print_entry_values_compact) |
|
|
+ { |
|
|
+ fputs_filtered ("@entry", stb); |
|
|
+ } |
|
|
+ ui_out_field_stream (out, "name", stb); |
|
|
+ } |
|
|
+ else |
|
|
+ /* Otherwise, just output the name. */ |
|
|
+ ui_out_field_string (out, "name", sym_name); |
|
|
+ |
|
|
+ annotate_arg_name_end (); |
|
|
+ |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ ui_out_text (out, "="); |
|
|
+ |
|
|
+ if (print_args_field) |
|
|
+ ui_out_field_int (out, "arg", 1); |
|
|
+ |
|
|
+ /* For MI print the type, but only for simple values. This seems |
|
|
+ weird, but this is how MI choose to format the various output |
|
|
+ types. */ |
|
|
+ if (args_type == MI_PRINT_SIMPLE_VALUES) |
|
|
+ { |
|
|
+ if (py_print_type (out, val) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ annotate_arg_value (value_type (val)); |
|
|
+ |
|
|
+ /* If the output is to the CLI, and the user option "set print |
|
|
+ frame-arguments" is set to none, just output "...". */ |
|
|
+ if (! ui_out_is_mi_like_p (out) && args_type == NO_VALUES) |
|
|
+ ui_out_field_string (out, "value", "..."); |
|
|
+ else |
|
|
+ { |
|
|
+ /* Otherwise, print the value for both MI and the CLI, except |
|
|
+ for the case of MI_PRINT_NO_VALUES. */ |
|
|
+ if (args_type != NO_VALUES) |
|
|
+ { |
|
|
+ if (py_print_value (out, val, opts, 0, args_type, language) |
|
|
+ == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ do_cleanups (cleanups); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+ |
|
|
+ error: |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function to loop over frame arguments provided by the |
|
|
+ "frame_arguments" Python API. Elements in the iterator must |
|
|
+ conform to the "Symbol Value" interface. ITER is the Python |
|
|
+ iterable object, OUT is the output stream, ARGS_TYPE is an |
|
|
+ enumerator describing the argument format, PRINT_ARGS_FIELD is a |
|
|
+ flag which indicates if we output "ARGS=1" in MI output in commands |
|
|
+ where both arguments and locals are printed, and FRAME is the |
|
|
+ backing frame. Returns PY_BT_ERROR on error, with any GDB |
|
|
+ exceptions converted to a Python exception, or PY_BT_OK on |
|
|
+ success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+enumerate_args (PyObject *iter, |
|
|
+ struct ui_out *out, |
|
|
+ enum py_frame_args args_type, |
|
|
+ int print_args_field, |
|
|
+ struct frame_info *frame) |
|
|
+{ |
|
|
+ PyObject *item; |
|
|
+ struct value_print_options opts; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ get_user_print_options (&opts); |
|
|
+ |
|
|
+ if (args_type == CLI_SCALAR_VALUES) |
|
|
+ { |
|
|
+ /* True in "summary" mode, false otherwise. */ |
|
|
+ opts.summary = 1; |
|
|
+ } |
|
|
+ |
|
|
+ opts.deref_ref = 1; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_args (); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ /* Collect the first argument outside of the loop, so output of |
|
|
+ commas in the argument output is correct. At the end of the |
|
|
+ loop block collect another item from the iterator, and, if it is |
|
|
+ not null emit a comma. */ |
|
|
+ item = PyIter_Next (iter); |
|
|
+ if (item == NULL && PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ |
|
|
+ while (item) |
|
|
+ { |
|
|
+ const struct language_defn *language; |
|
|
+ char *sym_name; |
|
|
+ struct symbol *sym; |
|
|
+ struct value *val; |
|
|
+ enum py_bt_status success = PY_BT_ERROR; |
|
|
+ |
|
|
+ success = extract_sym (item, &sym_name, &sym, &language); |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ { |
|
|
+ Py_DECREF (item); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ success = extract_value (item, &val); |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ { |
|
|
+ xfree (sym_name); |
|
|
+ Py_DECREF (item); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ Py_DECREF (item); |
|
|
+ item = NULL; |
|
|
+ |
|
|
+ if (sym && ui_out_is_mi_like_p (out) |
|
|
+ && ! mi_should_print (sym, MI_PRINT_ARGS)) |
|
|
+ { |
|
|
+ xfree (sym_name); |
|
|
+ continue; |
|
|
+ } |
|
|
+ |
|
|
+ /* If the object did not provide a value, read it using |
|
|
+ read_frame_args and account for entry values, if any. */ |
|
|
+ if (val == NULL) |
|
|
+ { |
|
|
+ struct frame_arg arg, entryarg; |
|
|
+ |
|
|
+ /* If there is no value, and also no symbol, set error and |
|
|
+ exit. */ |
|
|
+ if (sym == NULL) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_RuntimeError, |
|
|
+ _("No symbol or value provided.")); |
|
|
+ xfree (sym_name); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ read_frame_arg (sym, frame, &arg, &entryarg); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ xfree (sym_name); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ /* The object has not provided a value, so this is a frame |
|
|
+ argument to be read by GDB. In this case we have to |
|
|
+ account for entry-values. */ |
|
|
+ |
|
|
+ if (arg.entry_kind != print_entry_values_only) |
|
|
+ { |
|
|
+ if (py_print_single_arg (out, NULL, &arg, |
|
|
+ NULL, &opts, |
|
|
+ args_type, |
|
|
+ print_args_field, |
|
|
+ NULL) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ xfree (arg.error); |
|
|
+ xfree (entryarg.error); |
|
|
+ xfree (sym_name); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (entryarg.entry_kind != print_entry_values_no) |
|
|
+ { |
|
|
+ if (arg.entry_kind != print_entry_values_only) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_text (out, ", "); |
|
|
+ ui_out_wrap_hint (out, " "); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ xfree (arg.error); |
|
|
+ xfree (entryarg.error); |
|
|
+ xfree (sym_name); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (py_print_single_arg (out, NULL, &entryarg, NULL, |
|
|
+ &opts, args_type, |
|
|
+ print_args_field, NULL) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ xfree (arg.error); |
|
|
+ xfree (entryarg.error); |
|
|
+ xfree (sym_name); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ xfree (arg.error); |
|
|
+ xfree (entryarg.error); |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ /* If the object has provided a value, we just print that. */ |
|
|
+ if (val != NULL) |
|
|
+ { |
|
|
+ if (py_print_single_arg (out, sym_name, NULL, val, &opts, |
|
|
+ args_type, print_args_field, |
|
|
+ language) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ xfree (sym_name); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ xfree (sym_name); |
|
|
+ |
|
|
+ /* Collect the next item from the iterator. If |
|
|
+ this is the last item, do not print the |
|
|
+ comma. */ |
|
|
+ item = PyIter_Next (iter); |
|
|
+ if (item != NULL) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_text (out, ", "); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ Py_DECREF (item); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ else if (PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_arg_end (); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ Py_DECREF (item); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+ |
|
|
+ error: |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+ |
|
|
+/* Helper function to loop over variables provided by the |
|
|
+ "frame_locals" Python API. Elements in the iterable must conform |
|
|
+ to the "Symbol Value" interface. ITER is the Python iterable |
|
|
+ object, OUT is the output stream, INDENT is whether we should |
|
|
+ indent the output (for CLI), ARGS_TYPE is an enumerator describing |
|
|
+ the argument format, PRINT_ARGS_FIELD is flag which indicates |
|
|
+ whether to output the ARGS field in the case of |
|
|
+ -stack-list-variables and FRAME is the backing frame. Returns |
|
|
+ PY_BT_ERROR on error, with any GDB exceptions converted to a Python |
|
|
+ exception, or PY_BT_OK on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+enumerate_locals (PyObject *iter, |
|
|
+ struct ui_out *out, |
|
|
+ int indent, |
|
|
+ enum py_frame_args args_type, |
|
|
+ int print_args_field, |
|
|
+ struct frame_info *frame) |
|
|
+{ |
|
|
+ PyObject *item; |
|
|
+ struct value_print_options opts; |
|
|
+ |
|
|
+ get_user_print_options (&opts); |
|
|
+ opts.deref_ref = 1; |
|
|
+ |
|
|
+ while ((item = PyIter_Next (iter))) |
|
|
+ { |
|
|
+ const struct language_defn *language; |
|
|
+ char *sym_name; |
|
|
+ struct value *val; |
|
|
+ enum py_bt_status success = PY_BT_ERROR; |
|
|
+ struct symbol *sym; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ int local_indent = 8 + (8 * indent); |
|
|
+ struct cleanup *locals_cleanups; |
|
|
+ |
|
|
+ locals_cleanups = make_cleanup_py_decref (item); |
|
|
+ |
|
|
+ success = extract_sym (item, &sym_name, &sym, &language); |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ make_cleanup (xfree, sym_name); |
|
|
+ |
|
|
+ success = extract_value (item, &val); |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ if (sym != NULL && ui_out_is_mi_like_p (out) |
|
|
+ && ! mi_should_print (sym, MI_PRINT_LOCALS)) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ continue; |
|
|
+ } |
|
|
+ |
|
|
+ /* If the object did not provide a value, read it. */ |
|
|
+ if (val == NULL) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ val = read_var_value (sym, frame); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* With PRINT_NO_VALUES, MI does not emit a tuple normally as |
|
|
+ each output contains only one field. The exception is |
|
|
+ -stack-list-variables, which always provides a tuple. */ |
|
|
+ if (ui_out_is_mi_like_p (out)) |
|
|
+ { |
|
|
+ if (print_args_field || args_type != NO_VALUES) |
|
|
+ make_cleanup_ui_out_tuple_begin_end (out, NULL); |
|
|
+ } |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ { |
|
|
+ /* If the output is not MI we indent locals. */ |
|
|
+ ui_out_spaces (out, local_indent); |
|
|
+ } |
|
|
+ |
|
|
+ ui_out_field_string (out, "name", sym_name); |
|
|
+ |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ ui_out_text (out, " = "); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ if (args_type == MI_PRINT_SIMPLE_VALUES) |
|
|
+ { |
|
|
+ if (py_print_type (out, val) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* CLI always prints values for locals. MI uses the |
|
|
+ simple/no/all system. */ |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ { |
|
|
+ int val_indent = (indent + 1) * 4; |
|
|
+ |
|
|
+ if (py_print_value (out, val, &opts, val_indent, args_type, |
|
|
+ language) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ if (args_type != NO_VALUES) |
|
|
+ { |
|
|
+ if (py_print_value (out, val, &opts, 0, args_type, |
|
|
+ language) == PY_BT_ERROR) |
|
|
+ { |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ do_cleanups (locals_cleanups); |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_text (out, "\n"); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (item == NULL && PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ |
|
|
+ return PY_BT_OK; |
|
|
+ |
|
|
+ error: |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function for -stack-list-variables. Returns PY_BT_ERROR on |
|
|
+ error, or PY_BT_OK on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_mi_print_variables (PyObject *filter, struct ui_out *out, |
|
|
+ struct value_print_options *opts, |
|
|
+ enum py_frame_args args_type, |
|
|
+ struct frame_info *frame) |
|
|
+{ |
|
|
+ struct cleanup *old_chain; |
|
|
+ PyObject *args_iter; |
|
|
+ PyObject *locals_iter; |
|
|
+ |
|
|
+ args_iter = get_py_iter_from_func (filter, "frame_args"); |
|
|
+ old_chain = make_cleanup_py_xdecref (args_iter); |
|
|
+ if (args_iter == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ locals_iter = get_py_iter_from_func (filter, "frame_locals"); |
|
|
+ if (locals_iter == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ make_cleanup_py_decref (locals_iter); |
|
|
+ make_cleanup_ui_out_list_begin_end (out, "variables"); |
|
|
+ |
|
|
+ if (args_iter != Py_None) |
|
|
+ if (enumerate_args (args_iter, out, args_type, 1, frame) == PY_BT_ERROR) |
|
|
+ goto error; |
|
|
+ |
|
|
+ if (locals_iter != Py_None) |
|
|
+ if (enumerate_locals (locals_iter, out, 1, args_type, 1, frame) |
|
|
+ == PY_BT_ERROR) |
|
|
+ goto error; |
|
|
+ |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_OK; |
|
|
+ |
|
|
+ error: |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function for printing locals. This function largely just |
|
|
+ creates the wrapping tuple, and calls enumerate_locals. Returns |
|
|
+ PY_BT_ERROR on error, or PY_BT_OK on success.*/ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_locals (PyObject *filter, |
|
|
+ struct ui_out *out, |
|
|
+ enum py_frame_args args_type, |
|
|
+ int indent, |
|
|
+ struct frame_info *frame) |
|
|
+{ |
|
|
+ PyObject *locals_iter = get_py_iter_from_func (filter, |
|
|
+ "frame_locals"); |
|
|
+ struct cleanup *old_chain = make_cleanup_py_xdecref (locals_iter); |
|
|
+ |
|
|
+ if (locals_iter == NULL) |
|
|
+ goto locals_error; |
|
|
+ |
|
|
+ make_cleanup_ui_out_list_begin_end (out, "locals"); |
|
|
+ |
|
|
+ if (locals_iter != Py_None) |
|
|
+ if (enumerate_locals (locals_iter, out, indent, args_type, |
|
|
+ 0, frame) == PY_BT_ERROR) |
|
|
+ goto locals_error; |
|
|
+ |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_OK;; |
|
|
+ |
|
|
+ locals_error: |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function for printing frame arguments. This function |
|
|
+ largely just creates the wrapping tuple, and calls enumerate_args. |
|
|
+ Returns PY_BT_ERROR on error, with any GDB exceptions converted to |
|
|
+ a Python exception, or PY_BT_OK on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_args (PyObject *filter, |
|
|
+ struct ui_out *out, |
|
|
+ enum py_frame_args args_type, |
|
|
+ struct frame_info *frame) |
|
|
+{ |
|
|
+ PyObject *args_iter = get_py_iter_from_func (filter, "frame_args"); |
|
|
+ struct cleanup *old_chain = make_cleanup_py_xdecref (args_iter); |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ if (args_iter == NULL) |
|
|
+ goto args_error; |
|
|
+ |
|
|
+ make_cleanup_ui_out_list_begin_end (out, "args"); |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_args (); |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ ui_out_text (out, " ("); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto args_error; |
|
|
+ } |
|
|
+ |
|
|
+ if (args_iter != Py_None) |
|
|
+ if (enumerate_args (args_iter, out, args_type, 0, frame) == PY_BT_ERROR) |
|
|
+ goto args_error; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ ui_out_text (out, ")"); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto args_error; |
|
|
+ } |
|
|
+ |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_OK; |
|
|
+ |
|
|
+ args_error: |
|
|
+ do_cleanups (old_chain); |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Print a single frame to the designated output stream, detecting |
|
|
+ whether the output is MI or console, and formatting the output |
|
|
+ according to the conventions of that protocol. FILTER is the |
|
|
+ frame-filter associated with this frame. FLAGS is an integer |
|
|
+ describing the various print options. The FLAGS variables is |
|
|
+ described in "apply_frame_filter" function. ARGS_TYPE is an |
|
|
+ enumerator describing the argument format. OUT is the output |
|
|
+ stream to print, INDENT is the level of indention for this frame |
|
|
+ (in the case of elided frames), and LEVELS_PRINTED is a hash-table |
|
|
+ containing all the frames level that have already been printed. |
|
|
+ If a frame level has been printed, do not print it again (in the |
|
|
+ case of elided frames). Returns PY_BT_ERROR on error, with any |
|
|
+ GDB exceptions converted to a Python exception, or PY_BT_COMPLETED |
|
|
+ on success. */ |
|
|
+ |
|
|
+static enum py_bt_status |
|
|
+py_print_frame (PyObject *filter, int flags, enum py_frame_args args_type, |
|
|
+ struct ui_out *out, int indent, htab_t levels_printed) |
|
|
+{ |
|
|
+ int has_addr = 0; |
|
|
+ CORE_ADDR address = 0; |
|
|
+ struct gdbarch *gdbarch = NULL; |
|
|
+ struct frame_info *frame = NULL; |
|
|
+ struct cleanup *cleanup_stack = make_cleanup (null_cleanup, NULL); |
|
|
+ struct value_print_options opts; |
|
|
+ PyObject *py_inf_frame, *elided; |
|
|
+ int print_level, print_frame_info, print_args, print_locals; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ /* Extract print settings from FLAGS. */ |
|
|
+ print_level = (flags & PRINT_LEVEL) ? 1 : 0; |
|
|
+ print_frame_info = (flags & PRINT_FRAME_INFO) ? 1 : 0; |
|
|
+ print_args = (flags & PRINT_ARGS) ? 1 : 0; |
|
|
+ print_locals = (flags & PRINT_LOCALS) ? 1 : 0; |
|
|
+ |
|
|
+ get_user_print_options (&opts); |
|
|
+ |
|
|
+ /* Get the underlying frame. This is needed to determine GDB |
|
|
+ architecture, and also, in the cases of frame variables/arguments to |
|
|
+ read them if they returned filter object requires us to do so. */ |
|
|
+ py_inf_frame = PyObject_CallMethod (filter, "inferior_frame", NULL); |
|
|
+ if (py_inf_frame == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ frame = frame_object_to_frame_info (py_inf_frame);; |
|
|
+ |
|
|
+ Py_DECREF (py_inf_frame); |
|
|
+ |
|
|
+ if (frame == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ gdbarch = get_frame_arch (frame); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ |
|
|
+ /* stack-list-variables. */ |
|
|
+ if (print_locals && print_args && ! print_frame_info) |
|
|
+ { |
|
|
+ if (py_mi_print_variables (filter, out, &opts, |
|
|
+ args_type, frame) == PY_BT_ERROR) |
|
|
+ goto error; |
|
|
+ else |
|
|
+ { |
|
|
+ do_cleanups (cleanup_stack); |
|
|
+ return PY_BT_COMPLETED; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* -stack-list-locals does not require a |
|
|
+ wrapping frame attribute. */ |
|
|
+ if (print_frame_info || (print_args && ! print_locals)) |
|
|
+ make_cleanup_ui_out_tuple_begin_end (out, "frame"); |
|
|
+ |
|
|
+ if (print_frame_info) |
|
|
+ { |
|
|
+ /* Elided frames are also printed with this function (recursively) |
|
|
+ and are printed with indention. */ |
|
|
+ if (indent > 0) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_spaces (out, indent*4); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* The address is required for frame annotations, and also for |
|
|
+ address printing. */ |
|
|
+ if (PyObject_HasAttrString (filter, "address")) |
|
|
+ { |
|
|
+ PyObject *paddr = PyObject_CallMethod (filter, "address", NULL); |
|
|
+ if (paddr != NULL) |
|
|
+ { |
|
|
+ if (paddr != Py_None) |
|
|
+ { |
|
|
+ address = PyLong_AsLong (paddr); |
|
|
+ has_addr = 1; |
|
|
+ } |
|
|
+ Py_DECREF (paddr); |
|
|
+ } |
|
|
+ else |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* Print frame level. MI does not require the level if |
|
|
+ locals/variables only are being printed. */ |
|
|
+ if ((print_frame_info || print_args) && print_level) |
|
|
+ { |
|
|
+ struct frame_info **slot; |
|
|
+ int level; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ |
|
|
+ slot = (struct frame_info **) htab_find_slot (levels_printed, |
|
|
+ frame, INSERT); |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ level = frame_relative_level (frame); |
|
|
+ |
|
|
+ /* Check if this frame has already been printed (there are cases |
|
|
+ where elided synthetic dummy-frames have to 'borrow' the frame |
|
|
+ architecture from the eliding frame. If that is the case, do |
|
|
+ not print 'level', but print spaces. */ |
|
|
+ if (*slot == frame) |
|
|
+ ui_out_field_skip (out, "level"); |
|
|
+ else |
|
|
+ { |
|
|
+ *slot = frame; |
|
|
+ annotate_frame_begin (print_level ? level : 0, |
|
|
+ gdbarch, address); |
|
|
+ ui_out_text (out, "#"); |
|
|
+ ui_out_field_fmt_int (out, 2, ui_left, "level", |
|
|
+ level); |
|
|
+ } |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (print_frame_info) |
|
|
+ { |
|
|
+ /* Print address to the address field. If an address is not provided, |
|
|
+ print nothing. */ |
|
|
+ if (opts.addressprint && has_addr) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_address (); |
|
|
+ ui_out_field_core_addr (out, "addr", gdbarch, address); |
|
|
+ annotate_frame_address_end (); |
|
|
+ ui_out_text (out, " in "); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* Print frame function name. */ |
|
|
+ if (PyObject_HasAttrString (filter, "function")) |
|
|
+ { |
|
|
+ PyObject *py_func = PyObject_CallMethod (filter, "function", NULL); |
|
|
+ |
|
|
+ if (py_func != NULL) |
|
|
+ { |
|
|
+ const char *function = NULL; |
|
|
+ |
|
|
+ if (gdbpy_is_string (py_func)) |
|
|
+ { |
|
|
+ function = PyString_AsString (py_func); |
|
|
+ |
|
|
+ if (function == NULL) |
|
|
+ { |
|
|
+ Py_DECREF (py_func); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ else if (PyLong_Check (py_func)) |
|
|
+ { |
|
|
+ CORE_ADDR addr = PyLong_AsUnsignedLongLong (py_func); |
|
|
+ struct minimal_symbol *msymbol; |
|
|
+ |
|
|
+ if (PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ |
|
|
+ msymbol = lookup_minimal_symbol_by_pc (addr); |
|
|
+ if (msymbol != NULL) |
|
|
+ function = SYMBOL_PRINT_NAME (msymbol); |
|
|
+ } |
|
|
+ else if (py_func != Py_None) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_RuntimeError, |
|
|
+ _("FrameDecorator.function: expecting a " \ |
|
|
+ "String, integer or None.")); |
|
|
+ Py_DECREF (py_func); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_function_name (); |
|
|
+ if (function == NULL) |
|
|
+ ui_out_field_skip (out, "func"); |
|
|
+ else |
|
|
+ ui_out_field_string (out, "func", function); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ Py_DECREF (py_func); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ Py_DECREF (py_func); |
|
|
+ } |
|
|
+ else |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ |
|
|
+ /* Frame arguments. Check the result, and error if something went |
|
|
+ wrong. */ |
|
|
+ if (print_args) |
|
|
+ { |
|
|
+ if (py_print_args (filter, out, args_type, frame) == PY_BT_ERROR) |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ /* File name/source/line number information. */ |
|
|
+ if (print_frame_info) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_source_begin (); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ if (PyObject_HasAttrString (filter, "filename")) |
|
|
+ { |
|
|
+ PyObject *py_fn = PyObject_CallMethod (filter, "filename", |
|
|
+ NULL); |
|
|
+ if (py_fn != NULL) |
|
|
+ { |
|
|
+ if (py_fn != Py_None) |
|
|
+ { |
|
|
+ char *filename = PyString_AsString (py_fn); |
|
|
+ |
|
|
+ if (filename == NULL) |
|
|
+ { |
|
|
+ Py_DECREF (py_fn); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_wrap_hint (out, " "); |
|
|
+ ui_out_text (out, " at "); |
|
|
+ annotate_frame_source_file (); |
|
|
+ ui_out_field_string (out, "file", filename); |
|
|
+ annotate_frame_source_file_end (); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ Py_DECREF (py_fn); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ Py_DECREF (py_fn); |
|
|
+ } |
|
|
+ else |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ if (PyObject_HasAttrString (filter, "line")) |
|
|
+ { |
|
|
+ PyObject *py_line = PyObject_CallMethod (filter, "line", NULL); |
|
|
+ int line; |
|
|
+ |
|
|
+ if (py_line != NULL) |
|
|
+ { |
|
|
+ if (py_line != Py_None) |
|
|
+ { |
|
|
+ line = PyLong_AsLong (py_line); |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ ui_out_text (out, ":"); |
|
|
+ annotate_frame_source_line (); |
|
|
+ ui_out_field_int (out, "line", line); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ Py_DECREF (py_line); |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ Py_DECREF (py_line); |
|
|
+ } |
|
|
+ else |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ /* For MI we need to deal with the "children" list population of |
|
|
+ elided frames, so if MI output detected do not send newline. */ |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ { |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ annotate_frame_end (); |
|
|
+ ui_out_text (out, "\n"); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (print_locals) |
|
|
+ { |
|
|
+ if (py_print_locals (filter, out, args_type, indent, |
|
|
+ frame) == PY_BT_ERROR) |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ /* Finally recursively print elided frames, if any. */ |
|
|
+ elided = get_py_iter_from_func (filter, "elided"); |
|
|
+ if (elided == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ make_cleanup_py_decref (elided); |
|
|
+ if (elided != Py_None) |
|
|
+ { |
|
|
+ PyObject *item; |
|
|
+ |
|
|
+ make_cleanup_ui_out_list_begin_end (out, "children"); |
|
|
+ |
|
|
+ if (! ui_out_is_mi_like_p (out)) |
|
|
+ indent++; |
|
|
+ |
|
|
+ while ((item = PyIter_Next (elided))) |
|
|
+ { |
|
|
+ enum py_bt_status success = py_print_frame (item, flags, |
|
|
+ args_type, out, |
|
|
+ indent, |
|
|
+ levels_printed); |
|
|
+ |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ { |
|
|
+ Py_DECREF (item); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ Py_DECREF (item); |
|
|
+ } |
|
|
+ if (item == NULL && PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ |
|
|
+ do_cleanups (cleanup_stack); |
|
|
+ return PY_BT_COMPLETED; |
|
|
+ |
|
|
+ error: |
|
|
+ do_cleanups (cleanup_stack); |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
+ |
|
|
+/* Helper function to initiate frame filter invocation at starting |
|
|
+ frame FRAME. */ |
|
|
+ |
|
|
+static PyObject * |
|
|
+bootstrap_python_frame_filters (struct frame_info *frame, |
|
|
+ int frame_low, int frame_high) |
|
|
+{ |
|
|
+ struct cleanup *cleanups = |
|
|
+ make_cleanup (null_cleanup, NULL); |
|
|
+ PyObject *module, *sort_func, *iterable, *frame_obj, *iterator; |
|
|
+ PyObject *py_frame_low, *py_frame_high; |
|
|
+ |
|
|
+ frame_obj = frame_info_to_frame_object (frame); |
|
|
+ if (frame_obj == NULL) |
|
|
+ goto error; |
|
|
+ make_cleanup_py_decref (frame_obj); |
|
|
+ |
|
|
+ module = PyImport_ImportModule ("gdb.frames"); |
|
|
+ if (module == NULL) |
|
|
+ goto error; |
|
|
+ make_cleanup_py_decref (module); |
|
|
+ |
|
|
+ sort_func = PyObject_GetAttrString (module, "execute_frame_filters"); |
|
|
+ if (sort_func == NULL) |
|
|
+ goto error; |
|
|
+ make_cleanup_py_decref (sort_func); |
|
|
+ |
|
|
+ py_frame_low = PyInt_FromLong (frame_low); |
|
|
+ if (py_frame_low == NULL) |
|
|
+ goto error; |
|
|
+ make_cleanup_py_decref (py_frame_low); |
|
|
+ |
|
|
+ py_frame_high = PyInt_FromLong (frame_high); |
|
|
+ if (py_frame_high == NULL) |
|
|
+ goto error; |
|
|
+ make_cleanup_py_decref (py_frame_high); |
|
|
+ |
|
|
+ iterable = PyObject_CallFunctionObjArgs (sort_func, frame_obj, |
|
|
+ py_frame_low, |
|
|
+ py_frame_high, |
|
|
+ NULL); |
|
|
+ if (iterable == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ do_cleanups (cleanups); |
|
|
+ |
|
|
+ if (iterable != Py_None) |
|
|
+ { |
|
|
+ iterator = PyObject_GetIter (iterable); |
|
|
+ Py_DECREF (iterable); |
|
|
+ } |
|
|
+ else |
|
|
+ { |
|
|
+ return iterable; |
|
|
+ } |
|
|
+ |
|
|
+ return iterator; |
|
|
+ |
|
|
+ error: |
|
|
+ do_cleanups (cleanups); |
|
|
+ return NULL; |
|
|
+} |
|
|
+ |
|
|
+/* This is the only publicly exported function in this file. 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 PY_BT_ERROR on error, |
|
|
+ or PY_BT_COMPLETED on success.*/ |
|
|
+ |
|
|
+enum py_bt_status |
|
|
+apply_frame_filter (struct frame_info *frame, int flags, |
|
|
+ enum py_frame_args args_type, |
|
|
+ struct ui_out *out, int frame_low, |
|
|
+ int frame_high) |
|
|
+ |
|
|
+{ |
|
|
+ struct gdbarch *gdbarch = NULL; |
|
|
+ struct cleanup *cleanups; |
|
|
+ enum py_bt_status success = PY_BT_ERROR; |
|
|
+ PyObject *iterable; |
|
|
+ volatile struct gdb_exception except; |
|
|
+ PyObject *item; |
|
|
+ htab_t levels_printed; |
|
|
+ |
|
|
+ cleanups = ensure_python_env (gdbarch, current_language); |
|
|
+ |
|
|
+ TRY_CATCH (except, RETURN_MASK_ALL) |
|
|
+ { |
|
|
+ gdbarch = get_frame_arch (frame); |
|
|
+ } |
|
|
+ if (except.reason < 0) |
|
|
+ { |
|
|
+ gdbpy_convert_exception (except); |
|
|
+ goto error; |
|
|
+ } |
|
|
+ |
|
|
+ iterable = bootstrap_python_frame_filters (frame, frame_low, frame_high); |
|
|
+ |
|
|
+ if (iterable == NULL) |
|
|
+ goto error; |
|
|
+ |
|
|
+ /* If iterable is None, then there are no frame filters registered. |
|
|
+ If this is the case, defer to default GDB printing routines in MI |
|
|
+ and CLI. */ |
|
|
+ make_cleanup_py_decref (iterable); |
|
|
+ if (iterable == Py_None) |
|
|
+ { |
|
|
+ success = PY_BT_NO_FILTERS; |
|
|
+ goto done; |
|
|
+ } |
|
|
+ |
|
|
+ levels_printed = htab_create (20, |
|
|
+ htab_hash_pointer, |
|
|
+ htab_eq_pointer, |
|
|
+ NULL); |
|
|
+ make_cleanup_htab_delete (levels_printed); |
|
|
+ |
|
|
+ while ((item = PyIter_Next (iterable))) |
|
|
+ { |
|
|
+ success = py_print_frame (item, flags, args_type, out, 0, |
|
|
+ levels_printed); |
|
|
+ |
|
|
+ /* Do not exit on error printing a single frame. Print the |
|
|
+ error and continue with other frames. */ |
|
|
+ if (success == PY_BT_ERROR) |
|
|
+ gdbpy_print_stack (); |
|
|
+ |
|
|
+ Py_DECREF (item); |
|
|
+ } |
|
|
+ |
|
|
+ if (item == NULL && PyErr_Occurred ()) |
|
|
+ goto error; |
|
|
+ |
|
|
+ done: |
|
|
+ do_cleanups (cleanups); |
|
|
+ return success; |
|
|
+ |
|
|
+ error: |
|
|
+ gdbpy_print_stack (); |
|
|
+ do_cleanups (cleanups); |
|
|
+ return PY_BT_ERROR; |
|
|
+} |
|
|
Index: gdb-7.6/gdb/python/py-objfile.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/py-objfile.c 2013-06-10 14:31:02.731084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/py-objfile.c 2013-06-10 14:31:08.366082437 +0200 |
|
|
@@ -33,6 +33,8 @@ typedef struct |
|
|
/* The pretty-printer list of functions. */ |
|
|
PyObject *printers; |
|
|
|
|
|
+ /* The frame filter list of functions. */ |
|
|
+ PyObject *frame_filters; |
|
|
/* The type-printer list. */ |
|
|
PyObject *type_printers; |
|
|
} objfile_object; |
|
|
@@ -61,6 +63,7 @@ objfpy_dealloc (PyObject *o) |
|
|
objfile_object *self = (objfile_object *) o; |
|
|
|
|
|
Py_XDECREF (self->printers); |
|
|
+ Py_XDECREF (self->frame_filters); |
|
|
Py_XDECREF (self->type_printers); |
|
|
Py_TYPE (self)->tp_free (self); |
|
|
} |
|
|
@@ -81,6 +84,13 @@ objfpy_new (PyTypeObject *type, PyObject |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
+ self->frame_filters = PyDict_New (); |
|
|
+ if (!self->frame_filters) |
|
|
+ { |
|
|
+ Py_DECREF (self); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
self->type_printers = PyList_New (0); |
|
|
if (!self->type_printers) |
|
|
{ |
|
|
@@ -129,6 +139,47 @@ objfpy_set_printers (PyObject *o, PyObje |
|
|
return 0; |
|
|
} |
|
|
|
|
|
+/* Return the Python dictionary attribute containing frame filters for |
|
|
+ this object file. */ |
|
|
+PyObject * |
|
|
+objfpy_get_frame_filters (PyObject *o, void *ignore) |
|
|
+{ |
|
|
+ objfile_object *self = (objfile_object *) o; |
|
|
+ |
|
|
+ Py_INCREF (self->frame_filters); |
|
|
+ return self->frame_filters; |
|
|
+} |
|
|
+ |
|
|
+/* Set this object file's frame filters dictionary to FILTERS. */ |
|
|
+static int |
|
|
+objfpy_set_frame_filters (PyObject *o, PyObject *filters, void *ignore) |
|
|
+{ |
|
|
+ PyObject *tmp; |
|
|
+ objfile_object *self = (objfile_object *) o; |
|
|
+ |
|
|
+ if (! filters) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_TypeError, |
|
|
+ _("Cannot delete the frame filters attribute.")); |
|
|
+ return -1; |
|
|
+ } |
|
|
+ |
|
|
+ if (! PyDict_Check (filters)) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_TypeError, |
|
|
+ _("The frame_filters attribute must be a dictionary.")); |
|
|
+ return -1; |
|
|
+ } |
|
|
+ |
|
|
+ /* Take care in case the LHS and RHS are related somehow. */ |
|
|
+ tmp = self->frame_filters; |
|
|
+ Py_INCREF (filters); |
|
|
+ self->frame_filters = filters; |
|
|
+ Py_XDECREF (tmp); |
|
|
+ |
|
|
+ return 0; |
|
|
+} |
|
|
+ |
|
|
/* Get the 'type_printers' attribute. */ |
|
|
|
|
|
static PyObject * |
|
|
@@ -225,6 +276,13 @@ objfile_to_objfile_object (struct objfil |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
+ object->frame_filters = PyDict_New (); |
|
|
+ if (!object->frame_filters) |
|
|
+ { |
|
|
+ Py_DECREF (object); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
object->type_printers = PyList_New (0); |
|
|
if (!object->type_printers) |
|
|
{ |
|
|
@@ -270,6 +328,8 @@ static PyGetSetDef objfile_getset[] = |
|
|
"The objfile's filename, or None.", NULL }, |
|
|
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers, |
|
|
"Pretty printers.", NULL }, |
|
|
+ { "frame_filters", objfpy_get_frame_filters, |
|
|
+ objfpy_set_frame_filters, "Frame Filters.", NULL }, |
|
|
{ "type_printers", objfpy_get_type_printers, objfpy_set_type_printers, |
|
|
"Type printers.", NULL }, |
|
|
{ NULL } |
|
|
Index: gdb-7.6/gdb/python/py-progspace.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/py-progspace.c 2013-06-10 14:31:02.731084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/py-progspace.c 2013-06-10 14:31:08.366082437 +0200 |
|
|
@@ -35,6 +35,8 @@ typedef struct |
|
|
/* The pretty-printer list of functions. */ |
|
|
PyObject *printers; |
|
|
|
|
|
+ /* The frame filter list of functions. */ |
|
|
+ PyObject *frame_filters; |
|
|
/* The type-printer list. */ |
|
|
PyObject *type_printers; |
|
|
} pspace_object; |
|
|
@@ -69,6 +71,7 @@ pspy_dealloc (PyObject *self) |
|
|
pspace_object *ps_self = (pspace_object *) self; |
|
|
|
|
|
Py_XDECREF (ps_self->printers); |
|
|
+ Py_XDECREF (ps_self->frame_filters); |
|
|
Py_XDECREF (ps_self->type_printers); |
|
|
Py_TYPE (self)->tp_free (self); |
|
|
} |
|
|
@@ -89,6 +92,13 @@ pspy_new (PyTypeObject *type, PyObject * |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
+ self->frame_filters = PyDict_New (); |
|
|
+ if (!self->frame_filters) |
|
|
+ { |
|
|
+ Py_DECREF (self); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
self->type_printers = PyList_New (0); |
|
|
if (!self->type_printers) |
|
|
{ |
|
|
@@ -137,6 +147,47 @@ pspy_set_printers (PyObject *o, PyObject |
|
|
return 0; |
|
|
} |
|
|
|
|
|
+/* Return the Python dictionary attribute containing frame filters for |
|
|
+ this program space. */ |
|
|
+PyObject * |
|
|
+pspy_get_frame_filters (PyObject *o, void *ignore) |
|
|
+{ |
|
|
+ pspace_object *self = (pspace_object *) o; |
|
|
+ |
|
|
+ Py_INCREF (self->frame_filters); |
|
|
+ return self->frame_filters; |
|
|
+} |
|
|
+ |
|
|
+/* Set this object file's frame filters dictionary to FILTERS. */ |
|
|
+static int |
|
|
+pspy_set_frame_filters (PyObject *o, PyObject *frame, void *ignore) |
|
|
+{ |
|
|
+ PyObject *tmp; |
|
|
+ pspace_object *self = (pspace_object *) o; |
|
|
+ |
|
|
+ if (! frame) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_TypeError, |
|
|
+ "cannot delete the frame filter attribute"); |
|
|
+ return -1; |
|
|
+ } |
|
|
+ |
|
|
+ if (! PyDict_Check (frame)) |
|
|
+ { |
|
|
+ PyErr_SetString (PyExc_TypeError, |
|
|
+ "the frame filter attribute must be a dictionary"); |
|
|
+ return -1; |
|
|
+ } |
|
|
+ |
|
|
+ /* Take care in case the LHS and RHS are related somehow. */ |
|
|
+ tmp = self->frame_filters; |
|
|
+ Py_INCREF (frame); |
|
|
+ self->frame_filters = frame; |
|
|
+ Py_XDECREF (tmp); |
|
|
+ |
|
|
+ return 0; |
|
|
+} |
|
|
+ |
|
|
/* Get the 'type_printers' attribute. */ |
|
|
|
|
|
static PyObject * |
|
|
@@ -221,6 +272,13 @@ pspace_to_pspace_object (struct program_ |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
+ object->frame_filters = PyDict_New (); |
|
|
+ if (!object->frame_filters) |
|
|
+ { |
|
|
+ Py_DECREF (object); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
object->type_printers = PyList_New (0); |
|
|
if (!object->type_printers) |
|
|
{ |
|
|
@@ -257,6 +315,8 @@ static PyGetSetDef pspace_getset[] = |
|
|
"The progspace's main filename, or None.", NULL }, |
|
|
{ "pretty_printers", pspy_get_printers, pspy_set_printers, |
|
|
"Pretty printers.", NULL }, |
|
|
+ { "frame_filters", pspy_get_frame_filters, pspy_set_frame_filters, |
|
|
+ "Frame filters.", NULL }, |
|
|
{ "type_printers", pspy_get_type_printers, pspy_set_type_printers, |
|
|
"Type printers.", NULL }, |
|
|
{ NULL } |
|
|
Index: gdb-7.6/gdb/python/py-utils.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/py-utils.c 2013-06-10 14:31:02.732084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/py-utils.c 2013-06-10 14:31:08.366082437 +0200 |
|
|
@@ -48,6 +48,28 @@ make_cleanup_py_decref (PyObject *py) |
|
|
return make_cleanup (py_decref, (void *) py); |
|
|
} |
|
|
|
|
|
+/* This is a cleanup function which decrements the refcount on a |
|
|
+ Python object. This function accounts appropriately for NULL |
|
|
+ references. */ |
|
|
+ |
|
|
+static void |
|
|
+py_xdecref (void *p) |
|
|
+{ |
|
|
+ PyObject *py = p; |
|
|
+ |
|
|
+ Py_XDECREF (py); |
|
|
+} |
|
|
+ |
|
|
+/* Return a new cleanup which will decrement the Python object's |
|
|
+ refcount when run. Account for and operate on NULL references |
|
|
+ correctly. */ |
|
|
+ |
|
|
+struct cleanup * |
|
|
+make_cleanup_py_xdecref (PyObject *py) |
|
|
+{ |
|
|
+ return make_cleanup (py_xdecref, py); |
|
|
+} |
|
|
+ |
|
|
/* Converts a Python 8-bit string to a unicode string object. Assumes the |
|
|
8-bit string is in the host charset. If an error occurs during conversion, |
|
|
returns NULL with a python exception set. |
|
|
Index: gdb-7.6/gdb/python/python-internal.h |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/python-internal.h 2013-06-10 14:31:02.732084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/python-internal.h 2013-06-10 14:31:08.367082436 +0200 |
|
|
@@ -251,9 +251,11 @@ PyObject *frame_info_to_frame_object (st |
|
|
|
|
|
PyObject *pspace_to_pspace_object (struct program_space *); |
|
|
PyObject *pspy_get_printers (PyObject *, void *); |
|
|
+PyObject *pspy_get_frame_filters (PyObject *, void *); |
|
|
|
|
|
PyObject *objfile_to_objfile_object (struct objfile *); |
|
|
PyObject *objfpy_get_printers (PyObject *, void *); |
|
|
+PyObject *objfpy_get_frame_filters (PyObject *, void *); |
|
|
|
|
|
PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch); |
|
|
|
|
|
@@ -304,6 +306,7 @@ void gdbpy_initialize_new_objfile_event |
|
|
void gdbpy_initialize_arch (void); |
|
|
|
|
|
struct cleanup *make_cleanup_py_decref (PyObject *py); |
|
|
+struct cleanup *make_cleanup_py_xdecref (PyObject *py); |
|
|
|
|
|
struct cleanup *ensure_python_env (struct gdbarch *gdbarch, |
|
|
const struct language_defn *language); |
|
|
Index: gdb-7.6/gdb/python/python.c |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/python.c 2013-06-10 14:31:02.732084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/python.c 2013-06-10 14:31:08.367082436 +0200 |
|
|
@@ -1442,6 +1442,15 @@ free_type_printers (void *arg) |
|
|
{ |
|
|
} |
|
|
|
|
|
+enum py_bt_status |
|
|
+apply_frame_filter (struct frame_info *frame, int flags, |
|
|
+ enum py_frame_args args_type, |
|
|
+ struct ui_out *out, int frame_low, |
|
|
+ int frame_high) |
|
|
+{ |
|
|
+ return PY_BT_NO_FILTERS; |
|
|
+} |
|
|
+ |
|
|
#endif /* HAVE_PYTHON */ |
|
|
|
|
|
|
|
|
Index: gdb-7.6/gdb/python/python.h |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/python.h 2013-06-10 14:31:02.732084652 +0200 |
|
|
+++ gdb-7.6/gdb/python/python.h 2013-06-10 14:31:08.367082436 +0200 |
|
|
@@ -21,6 +21,7 @@ |
|
|
#define GDB_PYTHON_H |
|
|
|
|
|
#include "value.h" |
|
|
+#include "mi/mi-cmds.h" |
|
|
|
|
|
struct breakpoint_object; |
|
|
|
|
|
@@ -28,6 +29,66 @@ struct breakpoint_object; |
|
|
E.g. When the program loads libfoo.so, look for libfoo-gdb.py. */ |
|
|
#define GDBPY_AUTO_FILE_NAME "-gdb.py" |
|
|
|
|
|
+/* Python frame-filter status return values. */ |
|
|
+enum py_bt_status |
|
|
+ { |
|
|
+ /* Return when an error has occurred in processing frame filters, |
|
|
+ or when printing the stack. */ |
|
|
+ PY_BT_ERROR = -1, |
|
|
+ |
|
|
+ /* Return from internal routines to indicate that the function |
|
|
+ succeeded. */ |
|
|
+ PY_BT_OK = 1, |
|
|
+ |
|
|
+ /* Return when the frame filter process is complete, and all |
|
|
+ operations have succeeded. */ |
|
|
+ PY_BT_COMPLETED = 2, |
|
|
+ |
|
|
+ /* Return when the frame filter process is complete, but there |
|
|
+ were no filter registered and enabled to process. */ |
|
|
+ PY_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. */ |
|
|
+typedef enum py_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 |
|
|
+} py_frame_args; |
|
|
+ |
|
|
extern void finish_python_initialization (void); |
|
|
|
|
|
void eval_python_from_control_command (struct command_line *); |
|
|
@@ -43,6 +104,11 @@ int apply_val_pretty_printer (struct typ |
|
|
const struct value_print_options *options, |
|
|
const struct language_defn *language); |
|
|
|
|
|
+enum py_bt_status apply_frame_filter (struct frame_info *frame, int flags, |
|
|
+ enum py_frame_args args_type, |
|
|
+ struct ui_out *out, int frame_low, |
|
|
+ int frame_high); |
|
|
+ |
|
|
void preserve_python_values (struct objfile *objfile, htab_t copied_types); |
|
|
|
|
|
void gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile); |
|
|
Index: gdb-7.6/gdb/python/lib/gdb/FrameDecorator.py |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/python/lib/gdb/FrameDecorator.py 2013-06-10 14:31:08.367082436 +0200 |
|
|
@@ -0,0 +1,285 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+import gdb |
|
|
+ |
|
|
+class FrameDecorator(object): |
|
|
+ """Basic implementation of a Frame Decorator""" |
|
|
+ |
|
|
+ """ This base frame decorator decorates a frame or another frame |
|
|
+ decorator, and provides convenience methods. If this object is |
|
|
+ wrapping a frame decorator, defer to that wrapped object's method |
|
|
+ if it has one. This allows for frame decorators that have |
|
|
+ sub-classed FrameDecorator object, but also wrap other frame |
|
|
+ decorators on the same frame to correctly execute. |
|
|
+ |
|
|
+ E.g |
|
|
+ |
|
|
+ If the result of frame filters running means we have one gdb.Frame |
|
|
+ wrapped by multiple frame decorators, all sub-classed from |
|
|
+ FrameDecorator, the resulting hierarchy will be: |
|
|
+ |
|
|
+ Decorator1 |
|
|
+ -- (wraps) Decorator2 |
|
|
+ -- (wraps) FrameDecorator |
|
|
+ -- (wraps) gdb.Frame |
|
|
+ |
|
|
+ In this case we have two frame decorators, both of which are |
|
|
+ sub-classed from FrameDecorator. If Decorator1 just overrides the |
|
|
+ 'function' method, then all of the other methods are carried out |
|
|
+ by the super-class FrameDecorator. But Decorator2 may have |
|
|
+ overriden other methods, so FrameDecorator will look at the |
|
|
+ 'base' parameter and defer to that class's methods. And so on, |
|
|
+ down the chain.""" |
|
|
+ |
|
|
+ # 'base' can refer to a gdb.Frame or another frame decorator. In |
|
|
+ # the latter case, the child class will have called the super |
|
|
+ # method and _base will be an object conforming to the Frame Filter |
|
|
+ # class. |
|
|
+ def __init__(self, base): |
|
|
+ self._base = base |
|
|
+ |
|
|
+ @staticmethod |
|
|
+ def _is_limited_frame(frame): |
|
|
+ """Internal utility to determine if the frame is special or |
|
|
+ limited.""" |
|
|
+ sal = frame.find_sal() |
|
|
+ |
|
|
+ if (not sal.symtab or not sal.symtab.filename |
|
|
+ or frame.type() == gdb.DUMMY_FRAME |
|
|
+ or frame.type() == gdb.SIGTRAMP_FRAME): |
|
|
+ |
|
|
+ return True |
|
|
+ |
|
|
+ return False |
|
|
+ |
|
|
+ def elided(self): |
|
|
+ """Return any elided frames that this class might be |
|
|
+ wrapping, or None.""" |
|
|
+ if hasattr(self._base, "elided"): |
|
|
+ return self._base.elided() |
|
|
+ |
|
|
+ return None |
|
|
+ |
|
|
+ def function(self): |
|
|
+ """ Return the name of the frame's function or an address of |
|
|
+ the function of the frame. First determine if this is a |
|
|
+ special frame. If not, try to determine filename from GDB's |
|
|
+ frame internal function API. Finally, if a name cannot be |
|
|
+ determined return the address. If this function returns an |
|
|
+ address, GDB will attempt to determine the function name from |
|
|
+ its internal minimal symbols store (for example, for inferiors |
|
|
+ without debug-info).""" |
|
|
+ |
|
|
+ # Both gdb.Frame, and FrameDecorator have a method called |
|
|
+ # "function", so determine which object this is. |
|
|
+ if not isinstance(self._base, gdb.Frame): |
|
|
+ if hasattr(self._base, "function"): |
|
|
+ # If it is not a gdb.Frame, and there is already a |
|
|
+ # "function" method, use that. |
|
|
+ return self._base.function() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ |
|
|
+ if frame.type() == gdb.DUMMY_FRAME: |
|
|
+ return "<function called from gdb>" |
|
|
+ elif frame.type() == gdb.SIGTRAMP_FRAME: |
|
|
+ return "<signal handler called>" |
|
|
+ |
|
|
+ func = frame.function() |
|
|
+ |
|
|
+ # If we cannot determine the function name, return the |
|
|
+ # address. If GDB detects an integer value from this function |
|
|
+ # it will attempt to find the function name from minimal |
|
|
+ # symbols via its own internal functions. |
|
|
+ if func == None: |
|
|
+ pc = frame.pc() |
|
|
+ return pc |
|
|
+ |
|
|
+ return str(func) |
|
|
+ |
|
|
+ def address(self): |
|
|
+ """ Return the address of the frame's pc""" |
|
|
+ |
|
|
+ if hasattr(self._base, "address"): |
|
|
+ return self._base.address() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ return frame.pc() |
|
|
+ |
|
|
+ def filename(self): |
|
|
+ """ Return the filename associated with this frame, detecting |
|
|
+ and returning the appropriate library name is this is a shared |
|
|
+ library.""" |
|
|
+ |
|
|
+ if hasattr(self._base, "filename"): |
|
|
+ return self._base.filename() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ sal = frame.find_sal() |
|
|
+ if not sal.symtab or not sal.symtab.filename: |
|
|
+ pc = frame.pc() |
|
|
+ return gdb.solib_name(pc) |
|
|
+ else: |
|
|
+ return sal.symtab.filename |
|
|
+ |
|
|
+ def frame_args(self): |
|
|
+ """ Return an iterable of frame arguments for this frame, if |
|
|
+ any. The iterable object contains objects conforming with the |
|
|
+ Symbol/Value interface. If there are no frame arguments, or |
|
|
+ if this frame is deemed to be a special case, return None.""" |
|
|
+ |
|
|
+ if hasattr(self._base, "frame_args"): |
|
|
+ return self._base.frame_args() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ if self._is_limited_frame(frame): |
|
|
+ return None |
|
|
+ |
|
|
+ args = FrameVars(frame) |
|
|
+ return args.fetch_frame_args() |
|
|
+ |
|
|
+ def frame_locals(self): |
|
|
+ """ Return an iterable of local variables for this frame, if |
|
|
+ any. The iterable object contains objects conforming with the |
|
|
+ Symbol/Value interface. If there are no frame locals, or if |
|
|
+ this frame is deemed to be a special case, return None.""" |
|
|
+ |
|
|
+ if hasattr(self._base, "frame_locals"): |
|
|
+ return self._base.frame_locals() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ if self._is_limited_frame(frame): |
|
|
+ return None |
|
|
+ |
|
|
+ args = FrameVars(frame) |
|
|
+ return args.fetch_frame_locals() |
|
|
+ |
|
|
+ def line(self): |
|
|
+ """ Return line number information associated with the frame's |
|
|
+ pc. If symbol table/line information does not exist, or if |
|
|
+ this frame is deemed to be a special case, return None""" |
|
|
+ |
|
|
+ if hasattr(self._base, "line"): |
|
|
+ return self._base.line() |
|
|
+ |
|
|
+ frame = self.inferior_frame() |
|
|
+ if self._is_limited_frame(frame): |
|
|
+ return None |
|
|
+ |
|
|
+ sal = frame.find_sal() |
|
|
+ if (sal): |
|
|
+ return sal.line |
|
|
+ else: |
|
|
+ return None |
|
|
+ |
|
|
+ def inferior_frame(self): |
|
|
+ """ Return the gdb.Frame underpinning this frame decorator.""" |
|
|
+ |
|
|
+ # If 'base' is a frame decorator, we want to call its inferior |
|
|
+ # frame method. If '_base' is a gdb.Frame, just return that. |
|
|
+ if hasattr(self._base, "inferior_frame"): |
|
|
+ return self._base.inferior_frame() |
|
|
+ return self._base |
|
|
+ |
|
|
+class SymValueWrapper(object): |
|
|
+ """A container class conforming to the Symbol/Value interface |
|
|
+ which holds frame locals or frame arguments.""" |
|
|
+ def __init__(self, symbol, value): |
|
|
+ self.sym = symbol |
|
|
+ self.val = value |
|
|
+ |
|
|
+ def value(self): |
|
|
+ """ Return the value associated with this symbol, or None""" |
|
|
+ return self.val |
|
|
+ |
|
|
+ def symbol(self): |
|
|
+ """ Return the symbol, or Python text, associated with this |
|
|
+ symbol, or None""" |
|
|
+ return self.sym |
|
|
+ |
|
|
+class FrameVars(object): |
|
|
+ |
|
|
+ """Utility class to fetch and store frame local variables, or |
|
|
+ frame arguments.""" |
|
|
+ |
|
|
+ def __init__(self, frame): |
|
|
+ self.frame = frame |
|
|
+ self.symbol_class = { |
|
|
+ gdb.SYMBOL_LOC_STATIC: True, |
|
|
+ gdb.SYMBOL_LOC_REGISTER: True, |
|
|
+ gdb.SYMBOL_LOC_ARG: True, |
|
|
+ gdb.SYMBOL_LOC_REF_ARG: True, |
|
|
+ gdb.SYMBOL_LOC_LOCAL: True, |
|
|
+ gdb.SYMBOL_LOC_REGPARM_ADDR: True, |
|
|
+ gdb.SYMBOL_LOC_COMPUTED: True |
|
|
+ } |
|
|
+ |
|
|
+ def fetch_b(self, sym): |
|
|
+ """ Local utility method to determine if according to Symbol |
|
|
+ type whether it should be included in the iterator. Not all |
|
|
+ symbols are fetched, and only symbols that return |
|
|
+ True from this method should be fetched.""" |
|
|
+ |
|
|
+ # SYM may be a string instead of a symbol in the case of |
|
|
+ # synthetic local arguments or locals. If that is the case, |
|
|
+ # always fetch. |
|
|
+ if isinstance(sym, basestring): |
|
|
+ return True |
|
|
+ |
|
|
+ sym_type = sym.addr_class |
|
|
+ |
|
|
+ return self.symbol_class.get(sym_type, False) |
|
|
+ |
|
|
+ def fetch_frame_locals(self): |
|
|
+ """Public utility method to fetch frame local variables for |
|
|
+ the stored frame. Frame arguments are not fetched. If there |
|
|
+ are no frame local variables, return an empty list.""" |
|
|
+ lvars = [] |
|
|
+ |
|
|
+ block = self.frame.block() |
|
|
+ |
|
|
+ while block != None: |
|
|
+ if block.is_global or block.is_static: |
|
|
+ break |
|
|
+ for sym in block: |
|
|
+ if sym.is_argument: |
|
|
+ continue; |
|
|
+ if self.fetch_b(sym): |
|
|
+ lvars.append(SymValueWrapper(sym, None)) |
|
|
+ |
|
|
+ block = block.superblock |
|
|
+ |
|
|
+ return lvars |
|
|
+ |
|
|
+ def fetch_frame_args(self): |
|
|
+ """Public utility method to fetch frame arguments for the |
|
|
+ stored frame. Frame arguments are the only type fetched. If |
|
|
+ there are no frame argument variables, return an empty list.""" |
|
|
+ |
|
|
+ args = [] |
|
|
+ block = self.frame.block() |
|
|
+ while block != None: |
|
|
+ if block.function != None: |
|
|
+ break |
|
|
+ block = block.superblock |
|
|
+ |
|
|
+ if block != None: |
|
|
+ for sym in block: |
|
|
+ if not sym.is_argument: |
|
|
+ continue; |
|
|
+ args.append(SymValueWrapper(sym, None)) |
|
|
+ |
|
|
+ return args |
|
|
Index: gdb-7.6/gdb/python/lib/gdb/FrameIterator.py |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/python/lib/gdb/FrameIterator.py 2013-06-10 14:31:08.367082436 +0200 |
|
|
@@ -0,0 +1,45 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+import gdb |
|
|
+import itertools |
|
|
+ |
|
|
+class FrameIterator(object): |
|
|
+ """A gdb.Frame iterator. Iterates over gdb.Frames or objects that |
|
|
+ conform to that interface.""" |
|
|
+ |
|
|
+ def __init__(self, frame_obj): |
|
|
+ """Initialize a FrameIterator. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ frame_obj the starting frame.""" |
|
|
+ |
|
|
+ super(FrameIterator, self).__init__() |
|
|
+ self.frame = frame_obj |
|
|
+ |
|
|
+ def __iter__(self): |
|
|
+ return self |
|
|
+ |
|
|
+ def next(self): |
|
|
+ """next implementation. |
|
|
+ |
|
|
+ Returns: |
|
|
+ The next oldest frame.""" |
|
|
+ |
|
|
+ result = self.frame |
|
|
+ if result is None: |
|
|
+ raise StopIteration |
|
|
+ self.frame = result.older() |
|
|
+ return result |
|
|
Index: gdb-7.6/gdb/python/lib/gdb/frames.py |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/python/lib/gdb/frames.py 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -0,0 +1,229 @@ |
|
|
+# Frame-filter commands. |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+"""Internal functions for working with frame-filters.""" |
|
|
+ |
|
|
+import gdb |
|
|
+from gdb.FrameIterator import FrameIterator |
|
|
+from gdb.FrameDecorator import FrameDecorator |
|
|
+import itertools |
|
|
+import collections |
|
|
+ |
|
|
+def get_priority(filter_item): |
|
|
+ """ Internal worker function to return the frame-filter's priority |
|
|
+ from a frame filter object. This is a fail free function as it is |
|
|
+ used in sorting and filtering. If a badly implemented frame |
|
|
+ filter does not implement the priority attribute, return zero |
|
|
+ (otherwise sorting/filtering will fail and prevent other frame |
|
|
+ filters from executing). |
|
|
+ |
|
|
+ Arguments: |
|
|
+ filter_item: An object conforming to the frame filter |
|
|
+ interface. |
|
|
+ |
|
|
+ Returns: |
|
|
+ The priority of the frame filter from the "priority" |
|
|
+ attribute, or zero. |
|
|
+ """ |
|
|
+ # Do not fail here, as the sort will fail. If a filter has not |
|
|
+ # (incorrectly) set a priority, set it to zero. |
|
|
+ return getattr(filter_item, "priority", 0) |
|
|
+ |
|
|
+def set_priority(filter_item, priority): |
|
|
+ """ Internal worker function to set the frame-filter's priority. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ filter_item: An object conforming to the frame filter |
|
|
+ interface. |
|
|
+ priority: The priority to assign as an integer. |
|
|
+ """ |
|
|
+ |
|
|
+ filter_item.priority = priority |
|
|
+ |
|
|
+def get_enabled(filter_item): |
|
|
+ """ Internal worker function to return a filter's enabled state |
|
|
+ from a frame filter object. This is a fail free function as it is |
|
|
+ used in sorting and filtering. If a badly implemented frame |
|
|
+ filter does not implement the enabled attribute, return False |
|
|
+ (otherwise sorting/filtering will fail and prevent other frame |
|
|
+ filters from executing). |
|
|
+ |
|
|
+ Arguments: |
|
|
+ filter_item: An object conforming to the frame filter |
|
|
+ interface. |
|
|
+ |
|
|
+ Returns: |
|
|
+ The enabled state of the frame filter from the "enabled" |
|
|
+ attribute, or False. |
|
|
+ """ |
|
|
+ |
|
|
+ # If the filter class is badly implemented when called from the |
|
|
+ # Python filter command, do not cease filter operations, just set |
|
|
+ # enabled to False. |
|
|
+ return getattr(filter_item, "enabled", False) |
|
|
+ |
|
|
+def set_enabled(filter_item, state): |
|
|
+ """ Internal Worker function to set the frame-filter's enabled |
|
|
+ state. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ filter_item: An object conforming to the frame filter |
|
|
+ interface. |
|
|
+ state: True or False, depending on desired state. |
|
|
+ """ |
|
|
+ |
|
|
+ filter_item.enabled = state |
|
|
+ |
|
|
+def return_list(name): |
|
|
+ """ Internal Worker function to return the frame filter |
|
|
+ dictionary, depending on the name supplied as an argument. If the |
|
|
+ name is not "all", "global" or "progspace", it is assumed to name |
|
|
+ an object-file. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ name: The name of the list, as specified by GDB user commands. |
|
|
+ |
|
|
+ Returns: |
|
|
+ A dictionary object for a single specified dictionary, or a |
|
|
+ list containing all the items for "all" |
|
|
+ |
|
|
+ Raises: |
|
|
+ gdb.GdbError: A dictionary of that name cannot be found. |
|
|
+ """ |
|
|
+ |
|
|
+ # If all dictionaries are wanted in the case of "all" we |
|
|
+ # cannot return a combined dictionary as keys() may clash in |
|
|
+ # between different dictionaries. As we just want all the frame |
|
|
+ # filters to enable/disable them all, just return the combined |
|
|
+ # items() as a list. |
|
|
+ if name == "all": |
|
|
+ all_dicts = gdb.frame_filters.values() |
|
|
+ all_dicts = all_dicts + gdb.current_progspace().frame_filters.values() |
|
|
+ for objfile in gdb.objfiles(): |
|
|
+ all_dicts = all_dicts + objfile.frame_filters.values() |
|
|
+ return all_dicts |
|
|
+ |
|
|
+ if name == "global": |
|
|
+ return gdb.frame_filters |
|
|
+ else: |
|
|
+ if name == "progspace": |
|
|
+ cp = gdb.current_progspace() |
|
|
+ return cp.frame_filters |
|
|
+ else: |
|
|
+ for objfile in gdb.objfiles(): |
|
|
+ if name == objfile.filename: |
|
|
+ return objfile.frame_filters |
|
|
+ |
|
|
+ msg = "Cannot find frame-filter dictionary for '" + name + "'" |
|
|
+ raise gdb.GdbError(msg) |
|
|
+ |
|
|
+def _sort_list(): |
|
|
+ """ Internal Worker function to merge all known frame-filter |
|
|
+ lists, prune any filters with the state set to "disabled", and |
|
|
+ sort the list on the frame-filter's "priority" attribute. |
|
|
+ |
|
|
+ Returns: |
|
|
+ sorted_list: A sorted, pruned list of frame filters to |
|
|
+ execute. |
|
|
+ """ |
|
|
+ |
|
|
+ all_filters = [] |
|
|
+ for objfile in gdb.objfiles(): |
|
|
+ all_filters = all_filters + objfile.frame_filters.values() |
|
|
+ cp = gdb.current_progspace() |
|
|
+ |
|
|
+ all_filters = all_filters + cp.frame_filters.values() |
|
|
+ all_filters = all_filters + gdb.frame_filters.values() |
|
|
+ |
|
|
+ sorted_frame_filters = sorted(all_filters, key = get_priority, |
|
|
+ reverse = True) |
|
|
+ |
|
|
+ sorted_frame_filters = filter(get_enabled, |
|
|
+ sorted_frame_filters) |
|
|
+ |
|
|
+ return sorted_frame_filters |
|
|
+ |
|
|
+def execute_frame_filters(frame, frame_low, frame_high): |
|
|
+ """ Internal function called from GDB that will execute the chain |
|
|
+ of frame filters. Each filter is executed in priority order. |
|
|
+ After the execution completes, slice the iterator to frame_low - |
|
|
+ frame_high range. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ frame: The initial frame. |
|
|
+ |
|
|
+ frame_low: The low range of the slice. If this is a negative |
|
|
+ integer then it indicates a backward slice (ie bt -4) which |
|
|
+ counts backward from the last frame in the backtrace. |
|
|
+ |
|
|
+ frame_high: The high range of the slice. If this is -1 then |
|
|
+ it indicates all frames until the end of the stack from |
|
|
+ frame_low. |
|
|
+ |
|
|
+ Returns: |
|
|
+ frame_iterator: The sliced iterator after all frame |
|
|
+ filters have had a change to execute, or None if no frame |
|
|
+ filters are registered. |
|
|
+ """ |
|
|
+ |
|
|
+ # Get a sorted list of frame filters. |
|
|
+ sorted_list = _sort_list() |
|
|
+ |
|
|
+ # Check to see if there are any frame-filters. If not, just |
|
|
+ # return None and let default backtrace printing occur. |
|
|
+ if len(sorted_list) == 0: |
|
|
+ return None |
|
|
+ |
|
|
+ frame_iterator = FrameIterator(frame) |
|
|
+ |
|
|
+ # Apply a basic frame decorator to all gdb.Frames. This unifies the |
|
|
+ # interface. |
|
|
+ frame_iterator = itertools.imap(FrameDecorator, frame_iterator) |
|
|
+ |
|
|
+ for ff in sorted_list: |
|
|
+ frame_iterator = ff.filter(frame_iterator) |
|
|
+ |
|
|
+ # Slicing |
|
|
+ |
|
|
+ # Is this a slice from the end of the backtrace, ie bt -2? |
|
|
+ if frame_low < 0: |
|
|
+ count = 0 |
|
|
+ slice_length = abs(frame_low) |
|
|
+ # We cannot use MAXLEN argument for deque as it is 2.6 onwards |
|
|
+ # and some GDB versions might be < 2.6. |
|
|
+ sliced = collections.deque() |
|
|
+ |
|
|
+ for frame_item in frame_iterator: |
|
|
+ if count >= slice_length: |
|
|
+ sliced.popleft(); |
|
|
+ count = count + 1 |
|
|
+ sliced.append(frame_item) |
|
|
+ |
|
|
+ return iter(sliced) |
|
|
+ |
|
|
+ # -1 for frame_high means until the end of the backtrace. Set to |
|
|
+ # None if that is the case, to indicate to itertools.islice to |
|
|
+ # slice to the end of the iterator. |
|
|
+ if frame_high == -1: |
|
|
+ frame_high = None |
|
|
+ else: |
|
|
+ # As frames start from 0, add one to frame_high so islice |
|
|
+ # correctly finds the end |
|
|
+ frame_high = frame_high + 1; |
|
|
+ |
|
|
+ sliced = itertools.islice(frame_iterator, frame_low, frame_high) |
|
|
+ |
|
|
+ return sliced |
|
|
Index: gdb-7.6/gdb/python/lib/gdb/__init__.py |
|
|
=================================================================== |
|
|
--- gdb-7.6.orig/gdb/python/lib/gdb/__init__.py 2013-06-10 14:31:02.733084651 +0200 |
|
|
+++ gdb-7.6/gdb/python/lib/gdb/__init__.py 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -67,6 +67,8 @@ pretty_printers = [] |
|
|
|
|
|
# Initial type printers. |
|
|
type_printers = [] |
|
|
+# Initial frame filters. |
|
|
+frame_filters = {} |
|
|
|
|
|
# Convenience variable to GDB's python directory |
|
|
PYTHONDIR = os.path.dirname(os.path.dirname(__file__)) |
|
|
Index: gdb-7.6/gdb/python/lib/gdb/command/frame_filters.py |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/python/lib/gdb/command/frame_filters.py 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -0,0 +1,461 @@ |
|
|
+# Frame-filter commands. |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+"""GDB commands for working with frame-filters.""" |
|
|
+ |
|
|
+import gdb |
|
|
+import copy |
|
|
+from gdb.FrameIterator import FrameIterator |
|
|
+from gdb.FrameDecorator import FrameDecorator |
|
|
+import gdb.frames |
|
|
+import itertools |
|
|
+ |
|
|
+# GDB Commands. |
|
|
+class SetFilterPrefixCmd(gdb.Command): |
|
|
+ """Prefix command for 'set' frame-filter related operations.""" |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ super(SetFilterPrefixCmd, self).__init__("set frame-filter", |
|
|
+ gdb.COMMAND_OBSCURE, |
|
|
+ gdb.COMPLETE_NONE, True) |
|
|
+ |
|
|
+class ShowFilterPrefixCmd(gdb.Command): |
|
|
+ """Prefix command for 'show' frame-filter related operations.""" |
|
|
+ def __init__(self): |
|
|
+ super(ShowFilterPrefixCmd, self).__init__("show frame-filter", |
|
|
+ gdb.COMMAND_OBSCURE, |
|
|
+ gdb.COMPLETE_NONE, True) |
|
|
+class InfoFrameFilter(gdb.Command): |
|
|
+ """List all registered Python frame-filters. |
|
|
+ |
|
|
+ Usage: info frame-filters |
|
|
+ """ |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ super(InfoFrameFilter, self).__init__("info frame-filter", |
|
|
+ gdb.COMMAND_DATA) |
|
|
+ @staticmethod |
|
|
+ def enabled_string(state): |
|
|
+ """Return "Yes" if filter is enabled, otherwise "No".""" |
|
|
+ if state: |
|
|
+ return "Yes" |
|
|
+ else: |
|
|
+ return "No" |
|
|
+ |
|
|
+ def list_frame_filters(self, frame_filters): |
|
|
+ """ Internal worker function to list and print frame filters |
|
|
+ in a dictionary. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ frame_filters: The name of the dictionary, as |
|
|
+ specified by GDB user commands. |
|
|
+ """ |
|
|
+ |
|
|
+ sorted_frame_filters = sorted(frame_filters.items(), |
|
|
+ key=lambda i: gdb.frames.get_priority(i[1]), |
|
|
+ reverse=True) |
|
|
+ |
|
|
+ if len(sorted_frame_filters) == 0: |
|
|
+ print(" No frame filters registered.") |
|
|
+ else: |
|
|
+ print(" Priority Enabled Name") |
|
|
+ for frame_filter in sorted_frame_filters: |
|
|
+ name = frame_filter[0] |
|
|
+ try: |
|
|
+ priority = '{:<8}'.format( |
|
|
+ str(gdb.frames.get_priority(frame_filter[1]))) |
|
|
+ enabled = '{:<7}'.format( |
|
|
+ self.enabled_string(gdb.frames.get_enabled(frame_filter[1]))) |
|
|
+ except Exception as e: |
|
|
+ print(" Error printing filter '"+name+"': "+str(e)) |
|
|
+ else: |
|
|
+ print(" %s %s %s" % (priority, enabled, name)) |
|
|
+ |
|
|
+ def print_list(self, title, filter_list, blank_line): |
|
|
+ print(title) |
|
|
+ self.list_frame_filters(filter_list) |
|
|
+ if blank_line: |
|
|
+ print("") |
|
|
+ |
|
|
+ def invoke(self, arg, from_tty): |
|
|
+ self.print_list("global frame-filters:", gdb.frame_filters, True) |
|
|
+ |
|
|
+ cp = gdb.current_progspace() |
|
|
+ self.print_list("progspace %s frame-filters:" % cp.filename, |
|
|
+ cp.frame_filters, True) |
|
|
+ |
|
|
+ for objfile in gdb.objfiles(): |
|
|
+ self.print_list("objfile %s frame-filters:" % objfile.filename, |
|
|
+ objfile.frame_filters, False) |
|
|
+ |
|
|
+# Internal enable/disable functions. |
|
|
+ |
|
|
+def _enable_parse_arg(cmd_name, arg): |
|
|
+ """ Internal worker function to take an argument from |
|
|
+ enable/disable and return a tuple of arguments. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ cmd_name: Name of the command invoking this function. |
|
|
+ args: The argument as a string. |
|
|
+ |
|
|
+ Returns: |
|
|
+ A tuple containing the dictionary, and the argument, or just |
|
|
+ the dictionary in the case of "all". |
|
|
+ """ |
|
|
+ |
|
|
+ argv = gdb.string_to_argv(arg); |
|
|
+ argc = len(argv) |
|
|
+ if argv[0] == "all" and argc > 1: |
|
|
+ raise gdb.GdbError(cmd_name + ": with 'all' " \ |
|
|
+ "you may not specify a filter.") |
|
|
+ else: |
|
|
+ if argv[0] != "all" and argc != 2: |
|
|
+ raise gdb.GdbError(cmd_name + " takes exactly two arguments.") |
|
|
+ |
|
|
+ return argv |
|
|
+ |
|
|
+def _do_enable_frame_filter(command_tuple, flag): |
|
|
+ """Worker for enabling/disabling frame_filters. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ command_type: A tuple with the first element being the |
|
|
+ frame filter dictionary, and the second being |
|
|
+ the frame filter name. |
|
|
+ flag: True for Enable, False for Disable. |
|
|
+ """ |
|
|
+ |
|
|
+ list_op = command_tuple[0] |
|
|
+ op_list = gdb.frames.return_list(list_op) |
|
|
+ |
|
|
+ if list_op == "all": |
|
|
+ for item in op_list: |
|
|
+ gdb.frames.set_enabled(item, flag) |
|
|
+ else: |
|
|
+ frame_filter = command_tuple[1] |
|
|
+ try: |
|
|
+ ff = op_list[frame_filter] |
|
|
+ except KeyError: |
|
|
+ msg = "frame-filter '" + str(name) + "' not found." |
|
|
+ raise gdb.GdbError(msg) |
|
|
+ |
|
|
+ gdb.frames.set_enabled(ff, flag) |
|
|
+ |
|
|
+def _complete_frame_filter_list(text, word, all_flag): |
|
|
+ """Worker for frame filter dictionary name completion. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ text: The full text of the command line. |
|
|
+ word: The most recent word of the command line. |
|
|
+ all_flag: Whether to include the word "all" in completion. |
|
|
+ |
|
|
+ Returns: |
|
|
+ A list of suggested frame filter dictionary name completions |
|
|
+ from text/word analysis. This list can be empty when there |
|
|
+ are no suggestions for completion. |
|
|
+ """ |
|
|
+ if all_flag == True: |
|
|
+ filter_locations = ["all", "global", "progspace"] |
|
|
+ else: |
|
|
+ filter_locations = ["global", "progspace"] |
|
|
+ for objfile in gdb.objfiles(): |
|
|
+ filter_locations.append(objfile.filename) |
|
|
+ |
|
|
+ # If the user just asked for completions with no completion |
|
|
+ # hints, just return all the frame filter dictionaries we know |
|
|
+ # about. |
|
|
+ if (text == ""): |
|
|
+ return filter_locations |
|
|
+ |
|
|
+ # Otherwise filter on what we know. |
|
|
+ flist = filter(lambda x,y=text:x.startswith(y), filter_locations) |
|
|
+ |
|
|
+ # If we only have one completion, complete it and return it. |
|
|
+ if len(flist) == 1: |
|
|
+ flist[0] = flist[0][len(text)-len(word):] |
|
|
+ |
|
|
+ # Otherwise, return an empty list, or a list of frame filter |
|
|
+ # dictionaries that the previous filter operation returned. |
|
|
+ return flist |
|
|
+ |
|
|
+def _complete_frame_filter_name(word, printer_dict): |
|
|
+ """Worker for frame filter name completion. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ |
|
|
+ word: The most recent word of the command line. |
|
|
+ |
|
|
+ printer_dict: The frame filter dictionary to search for frame |
|
|
+ filter name completions. |
|
|
+ |
|
|
+ Returns: A list of suggested frame filter name completions |
|
|
+ from word analysis of the frame filter dictionary. This list |
|
|
+ can be empty when there are no suggestions for completion. |
|
|
+ """ |
|
|
+ |
|
|
+ printer_keys = printer_dict.keys() |
|
|
+ if (word == ""): |
|
|
+ return printer_keys |
|
|
+ |
|
|
+ flist = filter(lambda x,y=word:x.startswith(y), printer_keys) |
|
|
+ return flist |
|
|
+ |
|
|
+class EnableFrameFilter(gdb.Command): |
|
|
+ """GDB command to disable the specified frame-filter. |
|
|
+ |
|
|
+ Usage: enable frame-filter enable DICTIONARY [NAME] |
|
|
+ |
|
|
+ DICTIONARY is the name of the frame filter dictionary on which to |
|
|
+ operate. If dictionary is set to "all", perform operations on all |
|
|
+ dictionaries. Named dictionaries are: "global" for the global |
|
|
+ frame filter dictionary, "progspace" for the program space's frame |
|
|
+ filter dictionary. If either all, or the two named dictionaries |
|
|
+ are not specified, the dictionary name is assumed to be the name |
|
|
+ of the object-file name. |
|
|
+ |
|
|
+ NAME matches the name of the frame-filter to operate on. If |
|
|
+ DICTIONARY is "all", NAME is ignored. |
|
|
+ """ |
|
|
+ def __init__(self): |
|
|
+ super(EnableFrameFilter, self).__init__("enable frame-filter", |
|
|
+ gdb.COMMAND_DATA) |
|
|
+ def complete(self, text, word): |
|
|
+ """Completion function for both frame filter dictionary, and |
|
|
+ frame filter name.""" |
|
|
+ if text.count(" ") == 0: |
|
|
+ return _complete_frame_filter_list(text, word, True) |
|
|
+ else: |
|
|
+ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
|
|
+ return _complete_frame_filter_name(word, printer_list) |
|
|
+ |
|
|
+ def invoke(self, arg, from_tty): |
|
|
+ command_tuple = _enable_parse_arg("enable frame-filter", arg) |
|
|
+ _do_enable_frame_filter(command_tuple, True) |
|
|
+ |
|
|
+ |
|
|
+class DisableFrameFilter(gdb.Command): |
|
|
+ """GDB command to disable the specified frame-filter. |
|
|
+ |
|
|
+ Usage: disable frame-filter disable DICTIONARY [NAME] |
|
|
+ |
|
|
+ DICTIONARY is the name of the frame filter dictionary on which to |
|
|
+ operate. If dictionary is set to "all", perform operations on all |
|
|
+ dictionaries. Named dictionaries are: "global" for the global |
|
|
+ frame filter dictionary, "progspace" for the program space's frame |
|
|
+ filter dictionary. If either all, or the two named dictionaries |
|
|
+ are not specified, the dictionary name is assumed to be the name |
|
|
+ of the object-file name. |
|
|
+ |
|
|
+ NAME matches the name of the frame-filter to operate on. If |
|
|
+ DICTIONARY is "all", NAME is ignored. |
|
|
+ """ |
|
|
+ def __init__(self): |
|
|
+ super(DisableFrameFilter, self).__init__("disable frame-filter", |
|
|
+ gdb.COMMAND_DATA) |
|
|
+ |
|
|
+ def complete(self, text, word): |
|
|
+ """Completion function for both frame filter dictionary, and |
|
|
+ frame filter name.""" |
|
|
+ if text.count(" ") == 0: |
|
|
+ return _complete_frame_filter_list(text, word, True) |
|
|
+ else: |
|
|
+ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
|
|
+ return _complete_frame_filter_name(word, printer_list) |
|
|
+ |
|
|
+ def invoke(self, arg, from_tty): |
|
|
+ command_tuple = _enable_parse_arg("disable frame-filter", arg) |
|
|
+ _do_enable_frame_filter(command_tuple, False) |
|
|
+ |
|
|
+class SetFrameFilterPriority(gdb.Command): |
|
|
+ """GDB command to set the priority of the specified frame-filter. |
|
|
+ |
|
|
+ Usage: set frame-filter priority DICTIONARY NAME PRIORITY |
|
|
+ |
|
|
+ DICTIONARY is the name of the frame filter dictionary on which to |
|
|
+ operate. Named dictionaries are: "global" for the global frame |
|
|
+ filter dictionary, "progspace" for the program space's framefilter |
|
|
+ dictionary. If either of these two are not specified, the |
|
|
+ dictionary name is assumed to be the name of the object-file name. |
|
|
+ |
|
|
+ NAME matches the name of the frame filter to operate on. |
|
|
+ |
|
|
+ PRIORITY is the an integer to assign the new priority to the frame |
|
|
+ filter. |
|
|
+ """ |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ super(SetFrameFilterPriority, self).__init__("set frame-filter " \ |
|
|
+ "priority", |
|
|
+ gdb.COMMAND_DATA) |
|
|
+ |
|
|
+ def _parse_pri_arg(self, arg): |
|
|
+ """Internal worker to parse a priority from a tuple. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ arg: Tuple which contains the arguments from the command. |
|
|
+ |
|
|
+ Returns: |
|
|
+ A tuple containing the dictionary, name and priority from |
|
|
+ the arguments. |
|
|
+ |
|
|
+ Raises: |
|
|
+ gdb.GdbError: An error parsing the arguments. |
|
|
+ """ |
|
|
+ |
|
|
+ argv = gdb.string_to_argv(arg); |
|
|
+ argc = len(argv) |
|
|
+ if argc != 3: |
|
|
+ print("set frame-filter priority " \ |
|
|
+ "takes exactly three arguments.") |
|
|
+ return None |
|
|
+ |
|
|
+ return argv |
|
|
+ |
|
|
+ def _set_filter_priority(self, command_tuple): |
|
|
+ """Internal worker for setting priority of frame-filters, by |
|
|
+ parsing a tuple and calling _set_priority with the parsed |
|
|
+ tuple. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ command_tuple: Tuple which contains the arguments from the |
|
|
+ command. |
|
|
+ """ |
|
|
+ |
|
|
+ list_op = command_tuple[0] |
|
|
+ frame_filter = command_tuple[1] |
|
|
+ priority = command_tuple[2] |
|
|
+ |
|
|
+ op_list = gdb.frames.return_list(list_op) |
|
|
+ |
|
|
+ try: |
|
|
+ ff = op_list[frame_filter] |
|
|
+ except KeyError: |
|
|
+ msg = "frame-filter '" + str(name) + "' not found." |
|
|
+ raise gdb.GdbError(msg) |
|
|
+ |
|
|
+ gdb.frames.set_priority(ff, priority) |
|
|
+ |
|
|
+ def complete(self, text, word): |
|
|
+ """Completion function for both frame filter dictionary, and |
|
|
+ frame filter name.""" |
|
|
+ if text.count(" ") == 0: |
|
|
+ return _complete_frame_filter_list(text, word, False) |
|
|
+ else: |
|
|
+ printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
|
|
+ return _complete_frame_filter_name(word, printer_list) |
|
|
+ |
|
|
+ def invoke(self, arg, from_tty): |
|
|
+ command_tuple = self._parse_pri_arg(arg) |
|
|
+ if command_tuple != None: |
|
|
+ self._set_filter_priority(command_tuple) |
|
|
+ |
|
|
+class ShowFrameFilterPriority(gdb.Command): |
|
|
+ """GDB command to show the priority of the specified frame-filter. |
|
|
+ |
|
|
+ Usage: show frame-filter priority DICTIONARY NAME |
|
|
+ |
|
|
+ DICTIONARY is the name of the frame filter dictionary on which to |
|
|
+ operate. Named dictionaries are: "global" for the global frame |
|
|
+ filter dictionary, "progspace" for the program space's framefilter |
|
|
+ dictionary. If either of these two are not specified, the |
|
|
+ dictionary name is assumed to be the name of the object-file name. |
|
|
+ |
|
|
+ NAME matches the name of the frame-filter to operate on. |
|
|
+ """ |
|
|
+ |
|
|
+ def __init__(self): |
|
|
+ super(ShowFrameFilterPriority, self).__init__("show frame-filter " \ |
|
|
+ "priority", |
|
|
+ gdb.COMMAND_DATA) |
|
|
+ |
|
|
+ def _parse_pri_arg(self, arg): |
|
|
+ """Internal worker to parse a dictionary and name from a |
|
|
+ tuple. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ arg: Tuple which contains the arguments from the command. |
|
|
+ |
|
|
+ Returns: |
|
|
+ A tuple containing the dictionary, and frame filter name. |
|
|
+ |
|
|
+ Raises: |
|
|
+ gdb.GdbError: An error parsing the arguments. |
|
|
+ """ |
|
|
+ |
|
|
+ argv = gdb.string_to_argv(arg); |
|
|
+ argc = len(argv) |
|
|
+ if argc != 2: |
|
|
+ print("show frame-filter priority " \ |
|
|
+ "takes exactly two arguments.") |
|
|
+ return None |
|
|
+ |
|
|
+ return argv |
|
|
+ |
|
|
+ def get_filter_priority(self, frame_filters, name): |
|
|
+ """Worker for retrieving the priority of frame_filters. |
|
|
+ |
|
|
+ Arguments: |
|
|
+ frame_filters: Name of frame filter dictionary. |
|
|
+ name: object to select printers. |
|
|
+ |
|
|
+ Returns: |
|
|
+ The priority of the frame filter. |
|
|
+ |
|
|
+ Raises: |
|
|
+ gdb.GdbError: A frame filter cannot be found. |
|
|
+ """ |
|
|
+ |
|
|
+ op_list = gdb.frames.return_list(frame_filters) |
|
|
+ |
|
|
+ try: |
|
|
+ ff = op_list[name] |
|
|
+ except KeyError: |
|
|
+ msg = "frame-filter '" + str(name) + "' not found." |
|
|
+ raise gdb.GdbError(msg) |
|
|
+ |
|
|
+ return gdb.frames.get_priority(ff) |
|
|
+ |
|
|
+ def complete(self, text, word): |
|
|
+ """Completion function for both frame filter dictionary, and |
|
|
+ frame filter name.""" |
|
|
+ |
|
|
+ if text.count(" ") == 0: |
|
|
+ return _complete_frame_filter_list(text, word, False) |
|
|
+ else: |
|
|
+ printer_list = frame._return_list(text.split()[0].rstrip()) |
|
|
+ return _complete_frame_filter_name(word, printer_list) |
|
|
+ |
|
|
+ def invoke(self, arg, from_tty): |
|
|
+ command_tuple = self._parse_pri_arg(arg) |
|
|
+ if command_tuple == None: |
|
|
+ return |
|
|
+ filter_name = command_tuple[1] |
|
|
+ list_name = command_tuple[0] |
|
|
+ try: |
|
|
+ priority = self.get_filter_priority(list_name, filter_name); |
|
|
+ except Exception as e: |
|
|
+ print("Error printing filter priority for '"+name+"':"+str(e)) |
|
|
+ else: |
|
|
+ print("Priority of filter '" + filter_name + "' in list '" \ |
|
|
+ + list_name + "' is: " + str(priority)) |
|
|
+ |
|
|
+# Register commands |
|
|
+SetFilterPrefixCmd() |
|
|
+ShowFilterPrefixCmd() |
|
|
+InfoFrameFilter() |
|
|
+EnableFrameFilter() |
|
|
+DisableFrameFilter() |
|
|
+SetFrameFilterPriority() |
|
|
+ShowFrameFilterPriority() |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-gdb.py.in |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-gdb.py.in 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -0,0 +1,48 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+# This file is part of the GDB testsuite. It tests Python-based |
|
|
+# frame-filters. |
|
|
+import gdb |
|
|
+import itertools |
|
|
+from gdb.FrameDecorator import FrameDecorator |
|
|
+ |
|
|
+ |
|
|
+class FrameObjFile (): |
|
|
+ |
|
|
+ def __init__ (self): |
|
|
+ self.name = "Filter1" |
|
|
+ self.priority = 1 |
|
|
+ self.enabled = False |
|
|
+ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self |
|
|
+ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self |
|
|
+ |
|
|
+ def filter (self, frame_iter): |
|
|
+ return frame_iter |
|
|
+ |
|
|
+class FrameObjFile2 (): |
|
|
+ |
|
|
+ def __init__ (self): |
|
|
+ self.name = "Filter2" |
|
|
+ self.priority = 100 |
|
|
+ self.enabled = True |
|
|
+ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self |
|
|
+ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self |
|
|
+ |
|
|
+ def filter (self, frame_iter): |
|
|
+ return frame_iter |
|
|
+ |
|
|
+FrameObjFile() |
|
|
+FrameObjFile2() |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.c |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.c 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -0,0 +1,138 @@ |
|
|
+/* This testcase is part of GDB, the GNU debugger. |
|
|
+ |
|
|
+ Copyright 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+ 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 <stdlib.h> |
|
|
+ |
|
|
+void funca(void); |
|
|
+int count = 0; |
|
|
+ |
|
|
+typedef struct |
|
|
+{ |
|
|
+ char *nothing; |
|
|
+ int f; |
|
|
+ short s; |
|
|
+} foobar; |
|
|
+ |
|
|
+void end_func (int foo, char *bar, foobar *fb, foobar bf) |
|
|
+{ |
|
|
+ const char *str = "The End"; |
|
|
+ const char *st2 = "Is Near"; |
|
|
+ int b = 12; |
|
|
+ short c = 5; |
|
|
+ { |
|
|
+ int d = 15; |
|
|
+ int e = 14; |
|
|
+ const char *foo = "Inside block"; |
|
|
+ { |
|
|
+ int f = 42; |
|
|
+ int g = 19; |
|
|
+ const char *bar = "Inside block x2"; |
|
|
+ { |
|
|
+ short h = 9; |
|
|
+ h = h +1; /* Inner test breakpoint */ |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ return; /* Backtrace end breakpoint */ |
|
|
+} |
|
|
+ |
|
|
+void funcb(int j) |
|
|
+{ |
|
|
+ struct foo |
|
|
+ { |
|
|
+ int a; |
|
|
+ int b; |
|
|
+ }; |
|
|
+ |
|
|
+ struct foo bar; |
|
|
+ |
|
|
+ bar.a = 42; |
|
|
+ bar.b = 84; |
|
|
+ |
|
|
+ funca(); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+void funca(void) |
|
|
+{ |
|
|
+ foobar fb; |
|
|
+ foobar *bf; |
|
|
+ |
|
|
+ if (count < 10) |
|
|
+ { |
|
|
+ count++; |
|
|
+ funcb(count); |
|
|
+ } |
|
|
+ |
|
|
+ fb.nothing = "Foo Bar"; |
|
|
+ fb.f = 42; |
|
|
+ fb.s = 19; |
|
|
+ |
|
|
+ bf = malloc (sizeof (foobar)); |
|
|
+ bf->nothing = malloc (128); |
|
|
+ bf->nothing = "Bar Foo"; |
|
|
+ bf->f = 24; |
|
|
+ bf->s = 91; |
|
|
+ |
|
|
+ end_func(21, "Param", bf, fb); |
|
|
+ free (bf->nothing); |
|
|
+ free (bf); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+ |
|
|
+void func1(void) |
|
|
+{ |
|
|
+ funca(); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+int func2(void) |
|
|
+{ |
|
|
+ func1(); |
|
|
+ return 1; |
|
|
+} |
|
|
+ |
|
|
+void func3(int i) |
|
|
+{ |
|
|
+ func2(); |
|
|
+ |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+int func4(int j) |
|
|
+{ |
|
|
+ func3(j); |
|
|
+ |
|
|
+ return 2; |
|
|
+} |
|
|
+ |
|
|
+int func5(int f, int d) |
|
|
+{ |
|
|
+ int i = 0; |
|
|
+ char *random = "random"; |
|
|
+ i=i+f; |
|
|
+ |
|
|
+ func4(i); |
|
|
+ return i; |
|
|
+} |
|
|
+ |
|
|
+main() |
|
|
+{ |
|
|
+ func5(3,5); |
|
|
+} |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.exp |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter-mi.exp 2013-06-10 14:31:08.368082436 +0200 |
|
|
@@ -0,0 +1,179 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+# This file is part of the GDB testsuite. It tests Python-based |
|
|
+# frame-filters. |
|
|
+load_lib mi-support.exp |
|
|
+load_lib gdb-python.exp |
|
|
+ |
|
|
+set MIFLAGS "-i=mi2" |
|
|
+ |
|
|
+gdb_exit |
|
|
+if [mi_gdb_start] { |
|
|
+ continue |
|
|
+} |
|
|
+ |
|
|
+standard_testfile py-framefilter-mi.c |
|
|
+set pyfile py-framefilter.py |
|
|
+ |
|
|
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } { |
|
|
+ untested ${testfile}.exp |
|
|
+ return -1 |
|
|
+} |
|
|
+ |
|
|
+mi_delete_breakpoints |
|
|
+mi_gdb_reinitialize_dir $srcdir/$subdir |
|
|
+mi_gdb_load ${binfile} |
|
|
+ |
|
|
+if {[lsearch -exact [mi_get_features] python] < 0} { |
|
|
+ unsupported "python support is disabled" |
|
|
+ return -1 |
|
|
+} |
|
|
+ |
|
|
+mi_runto main |
|
|
+ |
|
|
+set remote_python_file [remote_download host ${srcdir}/${subdir}/${pyfile}] |
|
|
+ |
|
|
+mi_gdb_test "python execfile ('${remote_python_file}')" ".*\\^done." \ |
|
|
+ "Load python file" |
|
|
+ |
|
|
+# Multiple blocks test |
|
|
+mi_continue_to_line [gdb_get_line_number {Inner test breakpoint} ${srcfile}] \ |
|
|
+ "step to breakpoint" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --all-values" \ |
|
|
+ "\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --all-values" |
|
|
+ |
|
|
+mi_gdb_test "-enable-frame-filters" ".*\\^done." "enable frame filters" |
|
|
+mi_gdb_test "-stack-list-locals --all-values" \ |
|
|
+ "\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --all-values frame filters enabled" |
|
|
+ |
|
|
+mi_continue_to_line [gdb_get_line_number {Backtrace end breakpoint} ${srcfile}] \ |
|
|
+ "step to breakpoint" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-frames" \ |
|
|
+ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*},frame={level=\"27\",addr=\"$hex\",func=\"niam\".*}\\\].*" \ |
|
|
+ "filtered stack listing" |
|
|
+mi_gdb_test "-stack-list-frames 0 3" \ |
|
|
+ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*}\\\]" \ |
|
|
+ "filtered stack list 0 3" |
|
|
+mi_gdb_test "-stack-list-frames 22 24" \ |
|
|
+ "\\^done,stack=\\\[frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*}\\\]" \ |
|
|
+ "filtered stack list 22 24" |
|
|
+ |
|
|
+#stack list arguments |
|
|
+ |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 0" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 0" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments --no-frame-filters 0" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments --no-frame-filters 0" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 0 0 3" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 0 0 3" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 0 22 27" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 0 22 27" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 1" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 1" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments --no-frame-filters 1" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments --no-frame-filters 1" |
|
|
+ |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 1 0 3" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 1 0 3" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 1 22 27" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 1 22 27" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 2" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"\}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 2" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments --no-frame-filters 2" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments --no-frame-filters 2" |
|
|
+ |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 2 0 3" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 2 0 3" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments 2 22 27" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments 2 22 27" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-arguments --no-frame-filters 2 22 27" \ |
|
|
+ "\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \ |
|
|
+ "stack-list-arguments --no-frame-filters 2 22 27" |
|
|
+ |
|
|
+#stack-list-locals |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters 0" \ |
|
|
+ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters 0" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters 1" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters 1" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters 2" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters 2" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters --no-values" \ |
|
|
+ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters --no-values" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters --all-values" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters --all-values" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals --no-frame-filters --simple-values" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals --no-frame-filters --simple-values" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals 0" \ |
|
|
+ "\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \ |
|
|
+ "stack-list-locals 0" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals 1" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals 1" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-locals 2" \ |
|
|
+ "\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \ |
|
|
+ "stack-list-locals 2" |
|
|
+ |
|
|
+# stack-list-variables |
|
|
+mi_gdb_test "-stack-list-variables --no-frame-filters 0" \ |
|
|
+ "\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \ |
|
|
+ "stack-list-variables --no-frame-filters 0" |
|
|
+ |
|
|
+mi_gdb_test "-stack-list-variables 0" \ |
|
|
+ "\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \ |
|
|
+ "stack-list-variables 0" |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.c |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.c 2013-06-10 14:31:08.369082436 +0200 |
|
|
@@ -0,0 +1,155 @@ |
|
|
+/* This testcase is part of GDB, the GNU debugger. |
|
|
+ |
|
|
+ Copyright 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+ 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 <stdlib.h> |
|
|
+ |
|
|
+void funca(void); |
|
|
+int count = 0; |
|
|
+ |
|
|
+typedef struct |
|
|
+{ |
|
|
+ char *nothing; |
|
|
+ int f; |
|
|
+ short s; |
|
|
+} foobar; |
|
|
+ |
|
|
+void end_func (int foo, char *bar, foobar *fb, foobar bf) |
|
|
+{ |
|
|
+ const char *str = "The End"; |
|
|
+ const char *st2 = "Is Near"; |
|
|
+ int b = 12; |
|
|
+ short c = 5; |
|
|
+ |
|
|
+ { |
|
|
+ int d = 15; |
|
|
+ int e = 14; |
|
|
+ const char *foo = "Inside block"; |
|
|
+ { |
|
|
+ int f = 42; |
|
|
+ int g = 19; |
|
|
+ const char *bar = "Inside block x2"; |
|
|
+ { |
|
|
+ short h = 9; |
|
|
+ h = h +1; /* Inner test breakpoint */ |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ return; /* Backtrace end breakpoint */ |
|
|
+} |
|
|
+ |
|
|
+void funcb(int j) |
|
|
+{ |
|
|
+ struct foo |
|
|
+ { |
|
|
+ int a; |
|
|
+ int b; |
|
|
+ }; |
|
|
+ |
|
|
+ struct foo bar; |
|
|
+ |
|
|
+ bar.a = 42; |
|
|
+ bar.b = 84; |
|
|
+ |
|
|
+ funca(); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+void funca(void) |
|
|
+{ |
|
|
+ foobar fb; |
|
|
+ foobar *bf = NULL; |
|
|
+ |
|
|
+ if (count < 10) |
|
|
+ { |
|
|
+ count++; |
|
|
+ funcb(count); |
|
|
+ } |
|
|
+ |
|
|
+ fb.nothing = "Foo Bar"; |
|
|
+ fb.f = 42; |
|
|
+ fb.s = 19; |
|
|
+ |
|
|
+ bf = alloca (sizeof (foobar)); |
|
|
+ bf->nothing = alloca (128); |
|
|
+ bf->nothing = "Bar Foo"; |
|
|
+ bf->f = 24; |
|
|
+ bf->s = 91; |
|
|
+ |
|
|
+ end_func(21, "Param", bf, fb); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+ |
|
|
+void func1(void) |
|
|
+{ |
|
|
+ funca(); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+int func2(int f) |
|
|
+{ |
|
|
+ int c; |
|
|
+ const char *elided = "Elided frame"; |
|
|
+ foobar fb; |
|
|
+ foobar *bf = NULL; |
|
|
+ |
|
|
+ fb.nothing = "Elided Foo Bar"; |
|
|
+ fb.f = 84; |
|
|
+ fb.s = 38; |
|
|
+ |
|
|
+ bf = alloca (sizeof (foobar)); |
|
|
+ bf->nothing = alloca (128); |
|
|
+ bf->nothing = "Elided Bar Foo"; |
|
|
+ bf->f = 48; |
|
|
+ bf->s = 182; |
|
|
+ |
|
|
+ func1(); |
|
|
+ return 1; |
|
|
+} |
|
|
+ |
|
|
+void func3(int i) |
|
|
+{ |
|
|
+ func2(i); |
|
|
+ |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+int func4(int j) |
|
|
+{ |
|
|
+ func3(j); |
|
|
+ |
|
|
+ return 2; |
|
|
+} |
|
|
+ |
|
|
+int func5(int f, int d) |
|
|
+{ |
|
|
+ int i = 0; |
|
|
+ char *random = "random"; |
|
|
+ i=i+f; |
|
|
+ |
|
|
+ func4(i); |
|
|
+ return i; |
|
|
+} |
|
|
+ |
|
|
+main() |
|
|
+{ |
|
|
+ int z = 32; |
|
|
+ int y = 44; |
|
|
+ const char *foo1 = "Test"; |
|
|
+ func5(3,5); |
|
|
+} |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.exp |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.exp 2013-06-10 14:31:08.369082436 +0200 |
|
|
@@ -0,0 +1,239 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+# This file is part of the GDB testsuite. It tests Python-based |
|
|
+# frame-filters. |
|
|
+ |
|
|
+load_lib gdb-python.exp |
|
|
+ |
|
|
+standard_testfile |
|
|
+ |
|
|
+# We cannot use prepare_for_testing as we have to set the safe-patch |
|
|
+# to check objfile and progspace printers. |
|
|
+if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} { |
|
|
+ return -1 |
|
|
+} |
|
|
+ |
|
|
+# Start with a fresh gdb. |
|
|
+gdb_exit |
|
|
+gdb_start |
|
|
+ |
|
|
+# Skip all tests if Python scripting is not enabled. |
|
|
+if { [skip_python_tests] } { continue } |
|
|
+ |
|
|
+# Make the -gdb.py script available to gdb, it is automagically loaded by gdb. |
|
|
+# Care is taken to put it in the same directory as the binary so that |
|
|
+# gdb will find it. |
|
|
+set remote_obj_python_file \ |
|
|
+ [remote_download \ |
|
|
+ host ${srcdir}/${subdir}/${testfile}-gdb.py.in \ |
|
|
+ ${subdir}/${testfile}-gdb.py] |
|
|
+ |
|
|
+gdb_reinitialize_dir $srcdir/$subdir |
|
|
+gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \ |
|
|
+ "set auto-load safe-path" |
|
|
+gdb_load ${binfile} |
|
|
+# Verify gdb loaded the script. |
|
|
+gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \ |
|
|
+ "Test auto-load had loaded python scripts" |
|
|
+ |
|
|
+if ![runto_main] then { |
|
|
+ perror "couldn't run to breakpoint" |
|
|
+ return |
|
|
+} |
|
|
+gdb_test_no_output "set python print-stack full" \ |
|
|
+ "Set python print-stack to full" |
|
|
+ |
|
|
+# Load global frame-filters |
|
|
+set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] |
|
|
+gdb_test_no_output "python execfile ('${remote_python_file}')" \ |
|
|
+ "Load python file" |
|
|
+ |
|
|
+gdb_breakpoint [gdb_get_line_number "Backtrace end breakpoint"] |
|
|
+gdb_breakpoint [gdb_get_line_number "Inner test breakpoint"] |
|
|
+gdb_continue_to_breakpoint "Inner test breakpoint" |
|
|
+ |
|
|
+# Test multiple local blocks. |
|
|
+gdb_test "bt full no-filters" \ |
|
|
+ ".*#0.*end_func.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ |
|
|
+ "bt full no-filters" |
|
|
+gdb_test "bt full" \ |
|
|
+ ".*#0.*cnuf_dne.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ |
|
|
+ "bt full with filters" |
|
|
+ |
|
|
+gdb_continue_to_breakpoint "Backtrace end breakpoint" |
|
|
+ |
|
|
+# Test set/show |
|
|
+gdb_test "info frame-filter" \ |
|
|
+ ".*900.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ |
|
|
+ "info frame filter before setting priority" |
|
|
+gdb_test "show frame-filter priority global Elider" \ |
|
|
+ "Priority of filter 'Elider' in list 'global' is: 900" \ |
|
|
+ "show frame-filter priority global Elider before setting" |
|
|
+gdb_test_no_output "set frame-filter priority global Elider 1000" \ |
|
|
+ "set frame-filter priotiy global Elider 1000" |
|
|
+gdb_test "show frame-filter priority global Elider" \ |
|
|
+ "Priority of filter 'Elider' in list 'global' is: 1000" \ |
|
|
+ "show frame-filter priority global Elider after setting" |
|
|
+gdb_test "info frame-filter" \ |
|
|
+ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ |
|
|
+ "info frame filter after setting priority" |
|
|
+ |
|
|
+# Test enable/disable |
|
|
+gdb_test "info frame-filter" \ |
|
|
+ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ |
|
|
+ "info frame filter before disable frame filter" |
|
|
+gdb_test_no_output "disable frame-filter global Elider" \ |
|
|
+ "disable frame-filter global Elider" |
|
|
+gdb_test "info frame-filter" \ |
|
|
+ ".*1000.*No.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ |
|
|
+ "info frame filter after disable frame filter" |
|
|
+gdb_test_no_output "enable frame-filter global Elider" \ |
|
|
+ "enable frame-filter global Elider" |
|
|
+gdb_test "info frame-filter" \ |
|
|
+ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ |
|
|
+ "info frame filter after reenabling frame filter" |
|
|
+ |
|
|
+# Test no-filters |
|
|
+gdb_test "bt no-filters" \ |
|
|
+ ".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \ |
|
|
+ "bt no-filters" |
|
|
+ |
|
|
+# Test reverse |
|
|
+gdb_test "bt" \ |
|
|
+ ".*#0.*cnuf_dne.*#22.*in 1cnuf.*#27.*in niam \\(\\).*" \ |
|
|
+ "bt with frame filters" |
|
|
+ |
|
|
+# Disable Reverse |
|
|
+gdb_test_no_output "disable frame-filter global Reverse" \ |
|
|
+ "disable frame-filter global Reverse" |
|
|
+gdb_test "bt" \ |
|
|
+ ".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \ |
|
|
+ "bt with frame-filter Reverse disabled" |
|
|
+gdb_test "bt -2" \ |
|
|
+ ".*#26.*func5.*#27.*in main \\(\\).*" \ |
|
|
+ "bt -2 with frame-filter Reverse disabled" |
|
|
+gdb_test "bt 3" \ |
|
|
+ ".*#0.*end_func.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*" \ |
|
|
+ "bt 3 with frame-filter Reverse disabled" |
|
|
+gdb_test "bt no-filter full" \ |
|
|
+ ".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*" \ |
|
|
+ "bt no-filters full with Reverse disabled" |
|
|
+gdb_test "bt full" \ |
|
|
+ ".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*#22.*in func1 \\(\\).*#23.*in func2 \\(f=3\\).*elided = $hex \"Elided frame\".*fb = \{nothing = $hex \"Elided Foo Bar\", f = 84, s = 38\}.*bf = $hex.*" \ |
|
|
+ "bt full with Reverse disabled" |
|
|
+ |
|
|
+# Test set print frame-arguments |
|
|
+# none |
|
|
+gdb_test_no_output "set print frame-arguments none" \ |
|
|
+ "turn off frame arguments" |
|
|
+gdb_test "bt no-filter 1" \ |
|
|
+ "#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt no-filter 1 no args" |
|
|
+gdb_test "bt 1" \ |
|
|
+ "#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt 1 no args" |
|
|
+ |
|
|
+# scalars |
|
|
+gdb_test_no_output "set print frame-arguments scalars" \ |
|
|
+ "turn frame arguments to scalars only" |
|
|
+gdb_test "bt no-filter 1" \ |
|
|
+ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt no-filter 1 scalars" |
|
|
+gdb_test "bt 1" \ |
|
|
+ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt 1 scalars" |
|
|
+ |
|
|
+# all |
|
|
+gdb_test_no_output "set print frame-arguments all" \ |
|
|
+ "turn on frame arguments" |
|
|
+gdb_test "bt no-filter 1" \ |
|
|
+ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt no-filter 1 all args" |
|
|
+gdb_test "bt 1" \ |
|
|
+ "#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt 1 all args" |
|
|
+ |
|
|
+# set print address off |
|
|
+gdb_test_no_output "set print address off" \ |
|
|
+ "Turn off address printing" |
|
|
+gdb_test "bt no-filter 1" \ |
|
|
+ "#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt no-filter 1 no address" |
|
|
+gdb_test "bt 1" \ |
|
|
+ "#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \ |
|
|
+ "bt 1 no addresss" |
|
|
+ |
|
|
+remote_file host delete ${remote_python_file} |
|
|
+ |
|
|
+# Test with no debuginfo |
|
|
+ |
|
|
+# We cannot use prepare_for_testing as we have to set the safe-patch |
|
|
+# to check objfile and progspace printers. |
|
|
+if {[build_executable $testfile.exp $testfile $srcfile {nodebug}] == -1} { |
|
|
+ return -1 |
|
|
+} |
|
|
+ |
|
|
+# Start with a fresh gdb. |
|
|
+gdb_exit |
|
|
+gdb_start |
|
|
+ |
|
|
+# Skip all tests if Python scripting is not enabled. |
|
|
+if { [skip_python_tests] } { continue } |
|
|
+ |
|
|
+# Make the -gdb.py script available to gdb, it is automagically loaded by gdb. |
|
|
+# Care is taken to put it in the same directory as the binary so that |
|
|
+# gdb will find it. |
|
|
+set remote_obj_python_file \ |
|
|
+ [remote_download \ |
|
|
+ host ${srcdir}/${subdir}/${testfile}-gdb.py.in \ |
|
|
+ ${subdir}/${testfile}-gdb.py] |
|
|
+ |
|
|
+gdb_reinitialize_dir $srcdir/$subdir |
|
|
+gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \ |
|
|
+ "set auto-load safe-path for no debug info" |
|
|
+gdb_load ${binfile} |
|
|
+ |
|
|
+# Verify gdb loaded the script. |
|
|
+gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \ |
|
|
+ "Set autoload path for no debug info tests" |
|
|
+if ![runto_main] then { |
|
|
+ perror "couldn't run to breakpoint" |
|
|
+ return |
|
|
+} |
|
|
+ |
|
|
+gdb_test_no_output "set python print-stack full" \ |
|
|
+ "set python print-stack full for no debuginfo tests" |
|
|
+ |
|
|
+# Load global frame-filters |
|
|
+set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] |
|
|
+gdb_test_no_output "python execfile ('${remote_python_file}')" \ |
|
|
+ "Load python file for no debuginfo tests" |
|
|
+ |
|
|
+# Disable Reverse |
|
|
+gdb_test_no_output "disable frame-filter global Reverse" \ |
|
|
+ "disable frame-filter gloval Reverse for no debuginfo" |
|
|
+gdb_test "bt" \ |
|
|
+ ".*#0..*in main \\(\\).*" \ |
|
|
+ "bt for no debuginfo" |
|
|
+gdb_test "bt full" \ |
|
|
+ ".*#0..*in main \\(\\).*" \ |
|
|
+ "bt full for no debuginfo" |
|
|
+gdb_test "bt no-filters" \ |
|
|
+ ".*#0..*in main \\(\\).*" \ |
|
|
+ "bt no filters for no debuginfo" |
|
|
+gdb_test "bt no-filters full" \ |
|
|
+ ".*#0..*in main \\(\\).*" \ |
|
|
+ "bt no-filters full no debuginfo" |
|
|
Index: gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.py |
|
|
=================================================================== |
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
|
|
+++ gdb-7.6/gdb/testsuite/gdb.python/py-framefilter.py 2013-06-10 14:31:08.369082436 +0200 |
|
|
@@ -0,0 +1,117 @@ |
|
|
+# Copyright (C) 2013 Free Software Foundation, Inc. |
|
|
+ |
|
|
+# 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/>. |
|
|
+ |
|
|
+# This file is part of the GDB testsuite. It tests Python-based |
|
|
+# frame-filters. |
|
|
+import gdb |
|
|
+import itertools |
|
|
+from gdb.FrameDecorator import FrameDecorator |
|
|
+import copy |
|
|
+ |
|
|
+class Reverse_Function (FrameDecorator): |
|
|
+ |
|
|
+ def __init__(self, fobj): |
|
|
+ super(Reverse_Function, self).__init__(fobj) |
|
|
+ self.fobj = fobj |
|
|
+ |
|
|
+ def function (self): |
|
|
+ fname = str (self.fobj.function()) |
|
|
+ if (fname == None or fname == ""): |
|
|
+ return None |
|
|
+ else: |
|
|
+ fname = fname[::-1] |
|
|
+ return fname |
|
|
+ |
|
|
+class Dummy (FrameDecorator): |
|
|
+ |
|
|
+ def __init__(self, fobj): |
|
|
+ super(Dummy, self).__init__(fobj) |
|
|
+ self.fobj = fobj |
|
|
+ |
|
|
+ def function (self): |
|
|
+ return "Dummy function" |
|
|
+ |
|
|
+ def address (self): |
|
|
+ return 0x123 |
|
|
+ |
|
|
+ def filename (self): |
|
|
+ return "Dummy filename" |
|
|
+ |
|
|
+ def frame_args (self): |
|
|
+ return [("Foo",gdb.Value(12)),("Bar","Stuff"), ("FooBar",42)] |
|
|
+ |
|
|
+ def frame_locals (self): |
|
|
+ return [] |
|
|
+ |
|
|
+ def line (self): |
|
|
+ return 0 |
|
|
+ |
|
|
+ def elided (self): |
|
|
+ return None |
|
|
+ |
|
|
+class FrameFilter (): |
|
|
+ |
|
|
+ def __init__ (self): |
|
|
+ self.name = "Reverse" |
|
|
+ self.priority = 100 |
|
|
+ self.enabled = True |
|
|
+ gdb.frame_filters [self.name] = self |
|
|
+ |
|
|
+ def filter (self, frame_iter): |
|
|
+ frame_iter = itertools.imap (Reverse_Function, |
|
|
+ frame_iter) |
|
|
+ return frame_iter |
|
|
+ |
|
|
+class ElidingFrameDecorator(FrameDecorator): |
|
|
+ |
|
|
+ def __init__(self, frame, elided_frames): |
|
|
+ super(ElidingFrameDecorator, self).__init__(frame) |
|
|
+ self.elided_frames = elided_frames |
|
|
+ |
|
|
+ def elided(self): |
|
|
+ return iter(self.elided_frames) |
|
|
+ |
|
|
+class ElidingIterator: |
|
|
+ def __init__(self, ii): |
|
|
+ self.input_iterator = ii |
|
|
+ |
|
|
+ def __iter__(self): |
|
|
+ return self |
|
|
+ |
|
|
+ def next(self): |
|
|
+ frame = next(self.input_iterator) |
|
|
+ if str(frame.function()) != 'func1': |
|
|
+ return frame |
|
|
+ |
|
|
+ # Suppose we want to return the 'func1' frame but elide the |
|
|
+ # next frame. E.g., if call in our interpreter language takes |
|
|
+ # two C frames to implement, and the first one we see is the |
|
|
+ # "sentinel". |
|
|
+ elided = next(self.input_iterator) |
|
|
+ return ElidingFrameDecorator(frame, [elided]) |
|
|
+ |
|
|
+class FrameElider (): |
|
|
+ |
|
|
+ def __init__ (self): |
|
|
+ self.name = "Elider" |
|
|
+ self.priority = 900 |
|
|
+ self.enabled = True |
|
|
+ gdb.frame_filters [self.name] = self |
|
|
+ |
|
|
+ def filter (self, frame_iter): |
|
|
+ return ElidingIterator (frame_iter) |
|
|
+ |
|
|
+FrameFilter() |
|
|
+FrameElider()
|
|
|
|