gdb/gdb-archer.patch

19855 lines
607 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

http://sourceware.org/gdb/wiki/ProjectArcher
http://sourceware.org/gdb/wiki/ArcherBranchManagement
GIT snapshot:
commit 81810a20b2d2c3bf18e151de3cddfc96445b3c46
branch `archer' - the merge of branches:
archer-tromey-delayed-symfile
archer-tromey-python
archer-pmuldoon-next-over-throw
archer-jankratochvil-fortran-module
archer-jankratochvil-watchpoint
archer-jankratochvil-vla
TODO:archer-keiths-expr-cumulative
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ff8b86e..f450a7b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -167,6 +167,12 @@ TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
# Did the user give us a --with-gdb-datadir option?
+GDB_DATADIR_PATH = @GDB_DATADIR_PATH@
+
+# The argument to --with-pythondir. If not given, this is
+# GDB_DATADIR_PATH/python.
+pythondir = @pythondir@
+
GDB_DATADIR = @GDB_DATADIR@
# Helper code from gnulib.
@@ -267,23 +273,39 @@ SUBDIR_TUI_CFLAGS= \
#
SUBDIR_PYTHON_OBS = \
python.o \
+ py-block.o \
+ py-breakpoint.o \
py-cmd.o \
py-frame.o \
py-function.o \
+ py-hooks.o \
+ py-inferior.o \
+ py-infthread.o \
py-lazy-string.o \
py-objfile.o \
+ py-param.o \
py-prettyprint.o \
+ py-symbol.o \
+ py-symtab.o \
py-type.o \
py-utils.o \
py-value.o
SUBDIR_PYTHON_SRCS = \
python/python.c \
+ python/py-block.c \
+ python/py-breakpoint.c \
python/py-cmd.c \
python/py-frame.c \
python/py-function.c \
+ python/py-hooks.c \
+ python/py-inferior.c \
+ python/py-infthread.c \
python/py-lazy-string.c \
python/py-objfile.c \
+ python/py-param.c \
python/py-prettyprint.c \
+ python/py-symbol.c \
+ python/py-symtab.c \
python/py-type.c \
python/py-utils.c \
python/py-value.c
@@ -756,7 +778,8 @@ config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \
annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
-gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h
+gdb_usleep.h jit.h python/python.h python/python-internal.h \
+xml-syscall.h ada-operator.inc microblaze-tdep.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1270,6 +1293,12 @@ stamp-h: $(srcdir)/config.in config.status
CONFIG_LINKS= \
$(SHELL) config.status
+.gdbinit: $(srcdir)/gdbinit.in config.status
+ CONFIG_FILES=".gdbinit:gdbinit.in" \
+ CONFIG_COMMANDS= \
+ CONFIG_HEADERS= \
+ $(SHELL) config.status
+
config.status: $(srcdir)/configure configure.tgt configure.host
$(SHELL) config.status --recheck
@@ -1970,6 +1999,14 @@ python.o: $(srcdir)/python/python.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
$(POSTCOMPILE)
+py-block.o: $(srcdir)/python/py-block.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c
+ $(POSTCOMPILE)
+
+py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
+ $(POSTCOMPILE)
+
py-cmd.o: $(srcdir)/python/py-cmd.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
$(POSTCOMPILE)
@@ -1982,6 +2019,18 @@ py-function.o: $(srcdir)/python/py-function.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
$(POSTCOMPILE)
+py-hooks.o: $(srcdir)/python/py-hooks.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-hooks.c
+ $(POSTCOMPILE)
+
+py-inferior.o: $(srcdir)/python/py-inferior.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c
+ $(POSTCOMPILE)
+
+py-infthread.o: $(srcdir)/python/py-infthread.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c
+ $(POSTCOMPILE)
+
py-lazy-string.o: $(srcdir)/python/py-lazy-string.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c
$(POSTCOMPILE)
@@ -1990,10 +2039,22 @@ py-objfile.o: $(srcdir)/python/py-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c
$(POSTCOMPILE)
+py-param.o: $(srcdir)/python/py-param.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-param.c
+ $(POSTCOMPILE)
+
py-prettyprint.o: $(srcdir)/python/py-prettyprint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-prettyprint.c
$(POSTCOMPILE)
+py-symbol.o: $(srcdir)/python/py-symbol.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c
+ $(POSTCOMPILE)
+
+py-symtab.o: $(srcdir)/python/py-symtab.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c
+ $(POSTCOMPILE)
+
py-type.o: $(srcdir)/python/py-type.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c
$(POSTCOMPILE)
@@ -2006,6 +2067,36 @@ py-value.o: $(srcdir)/python/py-value.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-value.c
$(POSTCOMPILE)
+# All python library files, with the "python/lib" stripped off.
+# Note that we should only install files in the "gdb" module.
+PY_FILES = gdb/FrameIterator.py gdb/FrameWrapper.py gdb/command/alias.py \
+ gdb/command/backtrace.py gdb/command/require.py \
+ gdb/command/pahole.py gdb/command/upto.py gdb/command/__init__.py \
+ gdb/command/ignore_errors.py gdb/command/save_breakpoints.py \
+ gdb/function/caller_is.py gdb/function/in_scope.py \
+ gdb/function/__init__.py gdb/backtrace.py gdb/__init__.py
+
+# Install the Python library. Python library files go under
+# $(pythondir).
+install-python:
+ files='$(PY_FILES)'; for file in $$files; do \
+ dir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \
+ $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(pythondir)/$$dir; \
+ $(INSTALL_DATA) $(srcdir)/python/lib/$$file $(DESTDIR)$(pythondir)/$$file; \
+ done
+
+# Other packages may have their files installed in $(pythondir).
+uninstall-python:
+ files='$(PY_FILES)'; for file in $$files; do \
+ slashdir=`echo "/$$file" | sed 's,/[^/]*$$,,'`; \
+ rm -f $(DESTDIR)$(pythondir)/$$file; \
+ while test "x$$file" != "x$$slashdir"; do \
+ rmdir 2>/dev/null "$(DESTDIR)$(pythondir)$$slashdir"; \
+ file="$$slashdir"; \
+ slashdir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \
+ done \
+ done
+
#
# Dependency tracking. Most of this is conditional on GNU Make being
# found by configure; if GNU Make is not found, we fall back to a
diff --git a/gdb/NEWS b/gdb/NEWS
index 17d64fb..e0eb160 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -669,6 +669,13 @@ x86/x86_64 Darwin i[34567]86-*-darwin*
x86_64 MinGW x86_64-*-mingw*
+* New native configurations
+
+x86/x86_64 Darwin i[34567]86-*-darwin*
+
+info os processes
+ Show operating system information about processes.
+
* New targets
Lattice Mico32 lm32-*
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 24def95..4682045 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1644,7 +1644,7 @@ ada_type_of_array (struct value *arr, int bounds)
return NULL;
while (arity > 0)
{
- struct type *range_type = alloc_type_copy (value_type (arr));
+ struct type *range_type = alloc_type_copy (value_type (arr));
struct type *array_type = alloc_type_copy (value_type (arr));
struct value *low = desc_one_bound (descriptor, arity, 0);
struct value *high = desc_one_bound (descriptor, arity, 1);
@@ -10937,6 +10937,40 @@ ada_operator_length (struct expression *exp, int pc, int *oplenp, int *argsp)
}
}
+/* Implementation of the exp_descriptor method operator_check. */
+
+static int
+ada_operator_check (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
+ int (*objfile_func) (struct objfile *objfile, void *data),
+ void *data)
+{
+ const union exp_element *const elts = exp->elts;
+ struct type *type = NULL;
+
+ switch (elts[pos].opcode)
+ {
+ case UNOP_IN_RANGE:
+ case UNOP_QUAL:
+ type = elts[pos + 1].type;
+ break;
+
+ default:
+ return operator_check_standard (exp, pos, type_func, objfile_func,
+ data);
+ }
+
+ /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
+
+ if (type && type_func && (*type_func) (type, data))
+ return 1;
+ if (type && TYPE_OBJFILE (type) && objfile_func
+ && (*objfile_func) (TYPE_OBJFILE (type), data))
+ return 1;
+
+ return 0;
+}
+
static char *
ada_op_name (enum exp_opcode opcode)
{
@@ -11325,6 +11359,7 @@ parse (void)
static const struct exp_descriptor ada_exp_descriptor = {
ada_print_subexp,
ada_operator_length,
+ ada_operator_check,
ada_op_name,
ada_dump_subexp_body,
ada_evaluate_subexp
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 5c9e558..55a1873 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -350,6 +350,20 @@ amd64_linux_dr_unset_status (unsigned long mask)
}
}
+/* See i386_dr_low_type.detach. Do not use wrappers amd64_linux_dr_set_control
+ or amd64_linux_dr_reset_addr as they would modify the register cache
+ (amd64_linux_dr). */
+
+static void
+amd64_linux_dr_detach (void)
+{
+ int regnum;
+
+ amd64_linux_dr_set (inferior_ptid, DR_CONTROL, 0);
+ amd64_linux_dr_unset_status (~0UL);
+ for (regnum = DR_FIRSTADDR; regnum <= DR_LASTADDR; regnum++)
+ amd64_linux_dr_set (inferior_ptid, regnum, 0);
+}
static void
amd64_linux_new_thread (ptid_t ptid)
@@ -702,6 +716,7 @@ _initialize_amd64_linux_nat (void)
i386_dr_low.reset_addr = amd64_linux_dr_reset_addr;
i386_dr_low.get_status = amd64_linux_dr_get_status;
i386_dr_low.unset_status = amd64_linux_dr_unset_status;
+ i386_dr_low.detach = amd64_linux_dr_detach;
i386_set_debug_register_length (8);
/* Override the GNU/Linux inferior startup hook. */
diff --git a/gdb/block.c b/gdb/block.c
index 48ac21b..80003b8 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -318,6 +318,25 @@ allocate_block (struct obstack *obstack)
BLOCK_SUPERBLOCK (bl) = NULL;
BLOCK_DICT (bl) = NULL;
BLOCK_NAMESPACE (bl) = NULL;
+ BLOCK_FORTRAN_USE (bl) = NULL;
return bl;
}
+
+/* Return OBJFILE in which BLOCK is located or NULL if we cannot find it for
+ whatever reason. */
+
+struct objfile *
+block_objfile (const struct block *block)
+{
+ struct symbol *func;
+
+ if (block == NULL)
+ return NULL;
+
+ func = block_linkage_function (block);
+ if (func == NULL)
+ return NULL;
+
+ return SYMBOL_SYMTAB (func)->objfile;
+}
diff --git a/gdb/block.h b/gdb/block.h
index 7eedb6c..b147826 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -96,6 +96,15 @@ struct block
cplus_specific;
}
language_specific;
+
+ /* FIXME: It should be in the LANGUAGE_SPECIFIC region but the
+ BLOCK_NAMESPACE accessor is not protected by the C language check. */
+
+ struct
+ {
+ struct fortran_using *use;
+ }
+ fortran_specific;
};
#define BLOCK_START(bl) (bl)->startaddr
@@ -104,6 +113,7 @@ struct block
#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
#define BLOCK_DICT(bl) (bl)->dict
#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace
+#define BLOCK_FORTRAN_USE(bl) (bl)->fortran_specific.use
/* Macro to loop through all symbols in a block BL, in no particular
order. ITER helps keep track of the iteration, and should be a
@@ -166,4 +176,6 @@ extern const struct block *block_global_block (const struct block *block);
extern struct block *allocate_block (struct obstack *obstack);
+extern struct objfile *block_objfile (const struct block *block);
+
#endif /* BLOCK_H */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0dc8474..1a309b5 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -61,6 +61,7 @@
#include "valprint.h"
#include "jit.h"
#include "xml-syscall.h"
+#include "parser-defs.h"
/* readline include files */
#include "readline/readline.h"
@@ -616,6 +617,53 @@ get_breakpoint (int num)
}
+/* Set break condition of breakpoint B to EXP. */
+
+void
+set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty)
+{
+ struct bp_location *loc = b->loc;
+
+ for (; loc; loc = loc->next)
+ {
+ if (loc->cond)
+ {
+ xfree (loc->cond);
+ loc->cond = 0;
+ }
+ }
+
+ if (b->cond_string != NULL)
+ xfree (b->cond_string);
+
+ if (*exp == 0)
+ {
+ b->cond_string = NULL;
+ if (from_tty)
+ printf_filtered (_("Breakpoint %d now unconditional.\n"), b->number);
+ }
+ else
+ {
+ char *arg = exp;
+
+ /* I don't know if it matters whether this is the string the user
+ typed in or the decompiled expression. */
+ b->cond_string = xstrdup (arg);
+ b->condition_not_parsed = 0;
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ arg = exp;
+ loc->cond =
+ parse_exp_1 (&arg, block_for_pc (loc->address), 0);
+ if (*arg)
+ error (_("Junk at end of expression"));
+ }
+ }
+
+ breakpoints_changed ();
+ observer_notify_breakpoint_modified (b->number);
+}
+
/* condition N EXP -- set break condition of breakpoint N to EXP. */
static void
@@ -636,42 +684,7 @@ condition_command (char *arg, int from_tty)
ALL_BREAKPOINTS (b)
if (b->number == bnum)
{
- struct bp_location *loc = b->loc;
- for (; loc; loc = loc->next)
- {
- if (loc->cond)
- {
- xfree (loc->cond);
- loc->cond = 0;
- }
- }
- if (b->cond_string != NULL)
- xfree (b->cond_string);
-
- if (*p == 0)
- {
- b->cond_string = NULL;
- if (from_tty)
- printf_filtered (_("Breakpoint %d now unconditional.\n"), bnum);
- }
- else
- {
- arg = p;
- /* I don't know if it matters whether this is the string the user
- typed in or the decompiled expression. */
- b->cond_string = xstrdup (arg);
- b->condition_not_parsed = 0;
- for (loc = b->loc; loc; loc = loc->next)
- {
- arg = p;
- loc->cond =
- parse_exp_1 (&arg, block_for_pc (loc->address), 0);
- if (*arg)
- error (_("Junk at end of expression"));
- }
- }
- breakpoints_changed ();
- observer_notify_breakpoint_modified (b->number);
+ set_breakpoint_condition (b, p, from_tty);
return;
}
@@ -1870,6 +1883,36 @@ create_longjmp_master_breakpoint (char *func_name)
do_cleanups (old_chain);
}
+/* Install a master breakpoint on the unwinder's debug hook. */
+
+void
+create_exception_master_breakpoint (void)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *debug_hook;
+
+ debug_hook = lookup_minimal_symbol_text ("_Unwind_DebugHook", objfile);
+ if (debug_hook != NULL)
+ {
+ CORE_ADDR pc;
+ struct breakpoint *b;
+
+ pc = find_function_start_pc (get_objfile_arch (objfile),
+ SYMBOL_VALUE_ADDRESS (debug_hook),
+ SYMBOL_OBJ_SECTION (debug_hook));
+ b = create_internal_breakpoint (get_objfile_arch (objfile),
+ pc, bp_exception_master);
+ b->addr_string = xstrdup ("_Unwind_DebugHook");
+ b->enable_state = bp_disabled;
+ }
+ }
+
+ update_global_location_list (1);
+}
+
void
update_breakpoints_after_exec (void)
{
@@ -1911,7 +1954,7 @@ update_breakpoints_after_exec (void)
/* Thread event breakpoints must be set anew after an exec(),
as must overlay event and longjmp master breakpoints. */
if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
+ || b->type == bp_longjmp_master || b->type == bp_exception_master)
{
delete_breakpoint (b);
continue;
@@ -1926,7 +1969,8 @@ update_breakpoints_after_exec (void)
/* Longjmp and longjmp-resume breakpoints are also meaningless
after an exec. */
- if (b->type == bp_longjmp || b->type == bp_longjmp_resume)
+ if (b->type == bp_longjmp || b->type == bp_longjmp_resume
+ || b->type == bp_exception || b->type == bp_exception_resume)
{
delete_breakpoint (b);
continue;
@@ -1987,6 +2031,7 @@ update_breakpoints_after_exec (void)
create_longjmp_master_breakpoint ("_longjmp");
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
+ create_exception_master_breakpoint ();
}
int
@@ -2010,6 +2055,7 @@ detach_breakpoints (int pid)
if (b->inserted)
val |= remove_breakpoint_1 (b, mark_inserted);
}
+ val |= target_detach_watchpoints ();
do_cleanups (old_chain);
return val;
}
@@ -2109,12 +2155,14 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
return val;
b->inserted = (is == mark_inserted);
}
- else if (b->loc_type == bp_loc_hardware_watchpoint)
+ /* bp_loc_hardware_watchpoint with mark_inserted is being handled by
+ target_detach_watchpoints. */
+ else if (b->loc_type == bp_loc_hardware_watchpoint && is == mark_uninserted)
{
struct value *v;
struct value *n;
- b->inserted = (is == mark_inserted);
+ b->inserted = 0;
val = target_remove_watchpoint (b->address, b->length,
b->watchpoint_type);
@@ -2894,6 +2942,12 @@ print_it_typical (bpstat bs)
result = PRINT_NOTHING;
break;
+ case bp_exception_master:
+ /* These should never be enabled. */
+ printf_filtered (_("Exception Master Breakpoint: gdb should not stop!\n"));
+ result = PRINT_NOTHING;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
@@ -2981,6 +3035,8 @@ print_it_typical (bpstat bs)
case bp_none:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
@@ -3385,8 +3441,12 @@ bpstat_check_location (const struct bp_location *bl,
/* If BS refers to a watchpoint, determine if the watched values
has actually changed, and we should stop. If not, set BS->stop
- to 0. */
-static void
+ to 0.
+ Return 0 for watchpoints which could not be the cause of this trap.
+ In such case PRINT_IT will be print_it_noop and STOP will be 0.
+ Otherwise return 1 but in such case it is not guaranteed whether this
+ breakpoint did or did not trigger this trap. */
+static int
bpstat_check_watchpoint (bpstat bs)
{
const struct bp_location *bl = bs->breakpoint_at;
@@ -3475,8 +3535,10 @@ bpstat_check_watchpoint (bpstat bs)
anything for this watchpoint. */
bs->print_it = print_it_noop;
bs->stop = 0;
+ return 0;
}
}
+ return 1;
}
@@ -3590,6 +3652,8 @@ bpstat_stop_status (struct address_space *aspace,
for (bl = b->loc; bl != NULL; bl = bl->next)
{
+ bpstat bs_prev = bs;
+
/* For hardware watchpoints, we look only at the first location.
The watchpoint_check function will work on entire expression,
not the individual locations. For read watchopints, the
@@ -3607,6 +3671,7 @@ bpstat_stop_status (struct address_space *aspace,
/* Come here if it's a watchpoint, or if the break address matches */
bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */
+ gdb_assert (bs_prev->next == bs);
/* Assume we stop. Should we find watchpoint that is not actually
triggered, or if condition of breakpoint is false, we'll reset
@@ -3614,12 +3679,22 @@ bpstat_stop_status (struct address_space *aspace,
bs->stop = 1;
bs->print = 1;
- bpstat_check_watchpoint (bs);
- if (!bs->stop)
- continue;
+ if (!bpstat_check_watchpoint (bs))
+ {
+ /* Ensure bpstat_explains_signal stays false if this BL could not be
+ the cause of this trap. */
+
+ gdb_assert (bs->print_it == print_it_noop);
+ gdb_assert (!bs->stop);
+ xfree (bs);
+ bs = bs_prev;
+ bs->next = NULL;
+ continue;
+ }
if (b->type == bp_thread_event || b->type == bp_overlay_event
- || b->type == bp_longjmp_master)
+ || b->type == bp_longjmp_master
+ || b->type == bp_exception_master)
/* We do not stop for these. */
bs->stop = 0;
else
@@ -3829,6 +3904,7 @@ bpstat_what (bpstat bs)
struct bpstat_what retval;
retval.call_dummy = 0;
+ retval.is_longjmp = 0;
for (; bs != NULL; bs = bs->next)
{
enum class bs_class = no_effect;
@@ -3875,10 +3951,15 @@ bpstat_what (bpstat bs)
bs_class = no_effect;
break;
case bp_longjmp:
+ case bp_exception:
bs_class = long_jump;
+ retval.is_longjmp = bs->breakpoint_at->owner->type == bp_longjmp;
break;
case bp_longjmp_resume:
+ case bp_exception_resume:
bs_class = long_resume;
+ retval.is_longjmp
+ = bs->breakpoint_at->owner->type == bp_longjmp_resume;
break;
case bp_step_resume:
if (bs->stop)
@@ -3901,6 +3982,7 @@ bpstat_what (bpstat bs)
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_exception_master:
bs_class = bp_nostop;
break;
case bp_catchpoint:
@@ -4045,6 +4127,8 @@ print_one_breakpoint_location (struct breakpoint *b,
{bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
+ {bp_exception, "exception"},
+ {bp_exception_resume, "exception resume"},
{bp_step_resume, "step resume"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
@@ -4052,6 +4136,7 @@ print_one_breakpoint_location (struct breakpoint *b,
{bp_thread_event, "thread events"},
{bp_overlay_event, "overlay events"},
{bp_longjmp_master, "longjmp master"},
+ {bp_exception_master, "exception master"},
{bp_catchpoint, "catchpoint"},
{bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"},
@@ -4176,6 +4261,8 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
@@ -4183,6 +4270,7 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_thread_event:
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_exception_master:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_jit_event:
@@ -4821,6 +4909,8 @@ allocate_bp_location (struct breakpoint *bpt)
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
@@ -4829,6 +4919,7 @@ allocate_bp_location (struct breakpoint *bpt)
case bp_overlay_event:
case bp_jit_event:
case bp_longjmp_master:
+ case bp_exception_master:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
@@ -5015,8 +5106,7 @@ make_breakpoint_permanent (struct breakpoint *b)
}
/* Call this routine when stepping and nexting to enable a breakpoint
- if we do a longjmp() in THREAD. When we hit that breakpoint, call
- set_longjmp_resume_breakpoint() to figure out where we are going. */
+ if we do a longjmp() or 'throw' in THREAD. */
void
set_longjmp_breakpoint (int thread)
@@ -5029,10 +5119,11 @@ set_longjmp_breakpoint (int thread)
clones of those and enable them for the requested thread. */
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->pspace == current_program_space
- && b->type == bp_longjmp_master)
+ && (b->type == bp_longjmp_master
+ || b->type == bp_exception_master))
{
struct breakpoint *clone = clone_momentary_breakpoint (b);
- clone->type = bp_longjmp;
+ clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
clone->thread = thread;
}
}
@@ -5044,7 +5135,7 @@ delete_longjmp_breakpoint (int thread)
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_longjmp)
+ if (b->type == bp_longjmp || b->type == bp_exception)
{
if (b->thread == thread)
delete_breakpoint (b);
@@ -6119,6 +6210,8 @@ mention (struct breakpoint *b)
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_call_dummy:
case bp_watchpoint_scope:
@@ -6127,6 +6220,7 @@ mention (struct breakpoint *b)
case bp_overlay_event:
case bp_jit_event:
case bp_longjmp_master:
+ case bp_exception_master:
break;
}
@@ -7511,6 +7605,7 @@ struct until_break_command_continuation_args
{
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2;
+ int thread_num;
};
/* This function is called by fetch_inferior_event via the
@@ -7525,6 +7620,7 @@ until_break_command_continuation (void *arg)
delete_breakpoint (a->breakpoint);
if (a->breakpoint2)
delete_breakpoint (a->breakpoint2);
+ delete_longjmp_breakpoint (a->thread_num);
}
void
@@ -7536,6 +7632,8 @@ until_break_command (char *arg, int from_tty, int anywhere)
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
+ int thread;
+ struct thread_info *tp;
clear_proceed_status ();
@@ -7574,6 +7672,9 @@ until_break_command (char *arg, int from_tty, int anywhere)
old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ tp = inferior_thread ();
+ thread = tp->num;
+
/* Keep within the current frame, or in frames called by the current
one. */
@@ -7586,6 +7687,10 @@ until_break_command (char *arg, int from_tty, int anywhere)
frame_unwind_caller_id (frame),
bp_until);
make_cleanup_delete_breakpoint (breakpoint2);
+
+ set_longjmp_breakpoint (thread);
+ tp->initiating_frame = frame_unwind_caller_id (frame);
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
@@ -7602,6 +7707,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
args->breakpoint = breakpoint;
args->breakpoint2 = breakpoint2;
+ args->thread_num = thread;
discard_cleanups (old_chain);
add_continuation (inferior_thread (),
@@ -8823,6 +8929,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_thread_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
+ && b->type != bp_exception_master
&& b->number >= 0)
{
breaks_to_delete = 1;
@@ -8842,6 +8949,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_jit_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
+ && b->type != bp_exception_master
&& b->number >= 0)
delete_breakpoint (b);
}
@@ -9152,6 +9260,7 @@ breakpoint_re_set_one (void *bint)
reset later by breakpoint_re_set. */
case bp_overlay_event:
case bp_longjmp_master:
+ case bp_exception_master:
delete_breakpoint (b);
break;
@@ -9174,6 +9283,8 @@ breakpoint_re_set_one (void *bint)
case bp_step_resume:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_jit_event:
break;
}
@@ -9216,6 +9327,7 @@ breakpoint_re_set (void)
create_longjmp_master_breakpoint ("_longjmp");
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
+ create_exception_master_breakpoint ();
}
/* Reset the thread number of this breakpoint:
@@ -10177,6 +10289,22 @@ all_tracepoints ()
return tp_vec;
}
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+breakpoint_types_mark_used (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ {
+ if (b->exp)
+ exp_types_mark_used (b->exp);
+ if (b->val)
+ type_mark_used (value_type (b->val));
+ }
+}
+
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -10721,4 +10849,5 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);
+ observer_attach_mark_used (breakpoint_types_mark_used);
}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 6b373a3..59aa412 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -56,6 +56,13 @@ enum bptype
bp_longjmp, /* secret breakpoint to find longjmp() */
bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
+ /* An internal breakpoint that is installed on the unwinder's
+ debug hook. */
+ bp_exception,
+ /* An internal breakpoint that is set at the point where an
+ exception will land. */
+ bp_exception_resume,
+
/* Used by wait_for_inferior for stepping over subroutine calls, for
stepping over signal handlers, and for skipping prologues. */
bp_step_resume,
@@ -118,6 +125,9 @@ enum bptype
bp_longjmp_master,
+ /* Like bp_longjmp_master, but for exceptions. */
+ bp_exception_master,
+
bp_catchpoint,
bp_tracepoint,
@@ -603,6 +613,10 @@ struct bpstat_what
continuing from a call dummy without popping the frame is not a
useful one). */
int call_dummy;
+
+ /* Used for BPSTAT_WHAT_SET_LONGJMP_RESUME. True if we are
+ handling a longjmp, false if we are handling an exception. */
+ int is_longjmp;
};
/* The possible return values for print_bpstat, print_it_normal,
@@ -985,6 +999,9 @@ extern int catching_syscall_number (int syscall_number);
/* Tell a breakpoint to be quiet. */
extern void make_breakpoint_silent (struct breakpoint *);
+/* Set break condition of breakpoint B to EXP. */
+extern void set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty);
+
/* Return a tracepoint with the given number if found. */
extern struct breakpoint *get_tracepoint (int num);
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index d620881..d4a229d 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -717,7 +717,7 @@ c_get_string (struct value *value, gdb_byte **buffer, int *length,
If length returned from read_string was > 0, return the number of
characters read by dividing the number of bytes by width. */
if (*length != 0)
- *length = *length / width;
+ *length = *length / width;
*char_type = element_type;
@@ -1040,6 +1040,9 @@ evaluate_subexp_c (struct type *expect_type, struct expression *exp,
return evaluate_subexp_standard (expect_type, exp, pos, noside);
}
+
+/* Preprocessing and parsing C and C++ expressions. */
+
/* Table mapping opcodes into strings for printing operators
@@ -1140,6 +1143,7 @@ static const struct exp_descriptor exp_descriptor_c =
{
print_subexp_standard,
operator_length_standard,
+ operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_c
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index d1af481..1c930b5 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -558,7 +558,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
fprintf_filtered (stream, ")");
fprintf_filtered (stream, "[");
- if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0
+ if (TYPE_ARRAY_UPPER_BOUND_IS_DWARF_BLOCK (type))
+ {
+ /* No _() - printed sources should not be locale dependent. */
+ fprintf_filtered (stream, "variable");
+ }
+ else if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0
&& !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type))
fprintf_filtered (stream, "%d",
(TYPE_LENGTH (type)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 4833898..992c46f 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -47,6 +47,8 @@ extern void disconnect_or_stop_tracing (int from_tty);
#include "cli/cli-setshow.h"
#include "cli/cli-cmds.h"
+#include "python/python.h"
+
#ifdef TUI
#include "tui/tui.h" /* For tui_active et.al. */
#endif
@@ -184,6 +186,7 @@ struct cmd_list_element *showchecklist;
/* Command tracing state. */
+static int source_python = 0;
int source_verbose = 0;
int trace_commands = 0;
@@ -448,6 +451,7 @@ source_script (char *file, int from_tty)
struct cleanup *old_cleanups;
char *full_pathname = NULL;
int fd;
+ int is_python;
if (file == NULL || *file == 0)
{
@@ -480,8 +484,16 @@ source_script (char *file, int from_tty)
}
}
+ is_python = source_python;
+ if (strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py"))
+ is_python = 1;
+
stream = fdopen (fd, FOPEN_RT);
- script_from_file (stream, file);
+
+ if (is_python)
+ source_python_script (stream, file);
+ else
+ script_from_file (stream, file);
do_cleanups (old_cleanups);
}
@@ -495,15 +507,30 @@ source_verbose_cleanup (void *old_value)
xfree (old_value);
}
+/* A helper for source_command. Look for an argument in *ARGS.
+ Update *ARGS by stripping leading whitespace. If an argument is
+ found, return it (a character). Otherwise, return 0. */
+static int
+find_argument (char **args)
+{
+ int result = 0;
+ while (isspace ((*args)[0]))
+ ++*args;
+ if ((*args)[0] == '-' && isalpha ((*args)[1]))
+ {
+ result = (*args)[1];
+ *args += 3;
+ }
+ return result;
+}
+
static void
source_command (char *args, int from_tty)
{
struct cleanup *old_cleanups;
- char *file = args;
- int *old_source_verbose = xmalloc (sizeof(int));
- *old_source_verbose = source_verbose;
- old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose);
+ old_cleanups = make_cleanup_restore_integer (&source_verbose);
+ make_cleanup_restore_integer (&source_python);
/* -v causes the source command to run in verbose mode.
We still have to be able to handle filenames with spaces in a
@@ -511,23 +538,28 @@ source_command (char *args, int from_tty)
if (args)
{
- /* Make sure leading white space does not break the comparisons. */
- while (isspace(args[0]))
- args++;
-
- /* Is -v the first thing in the string? */
- if (args[0] == '-' && args[1] == 'v' && isspace (args[2]))
+ while (1)
{
- source_verbose = 1;
-
- /* Trim -v and whitespace from the filename. */
- file = &args[3];
- while (isspace (file[0]))
- file++;
+ int arg = find_argument (&args);
+ if (!arg)
+ break;
+ switch (arg)
+ {
+ case 'v':
+ source_verbose = 1;
+ break;
+ case 'p':
+ source_python = 1;
+ break;
+ default:
+ error (_("unrecognized option -%c"), arg);
+ }
}
}
- source_script (file, from_tty);
+ source_script (args, from_tty);
+
+ do_cleanups (old_cleanups);
}
@@ -1309,7 +1341,9 @@ Read commands from a file named FILE.\n\
Optional -v switch (before the filename) causes each command in\n\
FILE to be echoed as it is executed.\n\
Note that the file \"%s\" is read automatically in this way\n\
-when GDB is started."), gdbinit);
+when GDB is started.\n\
+Optional -p switch (before the filename) causes FILE to be evaluated\n\
+as Python code."), gdbinit);
c = add_cmd ("source", class_support, source_command,
source_help_text, &cmdlist);
set_cmd_completer (c, filename_completer);
diff --git a/gdb/coffread.c b/gdb/coffread.c
index eca6618..0579ce6 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2126,6 +2126,7 @@ static struct sym_fns coff_sym_fns =
coff_new_init, /* sym_new_init: init anything gbl to entire symtab */
coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
coff_symfile_read, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
coff_symfile_finish, /* sym_finish: finished with file, cleanup */
default_symfile_offsets, /* sym_offsets: xlate external to internal form */
default_symfile_segments, /* sym_segments: Get segment information from
diff --git a/gdb/config.in b/gdb/config.in
index ebde876..907b275 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -46,11 +46,10 @@
language is requested. */
#undef ENABLE_NLS
-/* look for global separate data files in this path [DATADIR/gdb] */
+/* Global directory for GDB data files. */
#undef GDB_DATADIR
-/* Define if the gdb-datadir directory should be relocated when GDB is moved.
- */
+/* Define if GDB datadir should be relocated when GDB is moved. */
#undef GDB_DATADIR_RELOCATABLE
/* Define to be a string naming the default host character set. */
@@ -653,6 +652,9 @@
'ptrdiff_t'. */
#undef PTRDIFF_T_SUFFIX
+/* Define to install path for Python sources */
+#undef PYTHONDIR
+
/* Relocated directory for source files. */
#undef RELOC_SRCDIR
diff --git a/gdb/config/i386/nm-i386.h b/gdb/config/i386/nm-i386.h
new file mode 100644
index 0000000..5f237cc
--- /dev/null
+++ b/gdb/config/i386/nm-i386.h
@@ -0,0 +1,125 @@
+/* Native macro definitions for GDB on an Intel i[3456]86.
+ Copyright 2001, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef NM_I386_H
+#define NM_I386_H 1
+
+/* Hardware-assisted breakpoints and watchpoints. */
+
+/* Targets should define this to use the generic x86 watchpoint support. */
+#ifdef I386_USE_GENERIC_WATCHPOINTS
+
+/* Add watchpoint methods to the provided target_ops. Targets which call
+ this should also define I386_WATCHPOINTS_IN_TARGET_VECTOR. */
+struct target_ops;
+void i386_use_watchpoints (struct target_ops *);
+
+/* Clear the reference counts and forget everything we knew about DRi. */
+extern void i386_cleanup_dregs (void);
+
+/* Insert a watchpoint to watch a memory region which starts at
+ address ADDR and whose length is LEN bytes. Watch memory accesses
+ of the type TYPE. Return 0 on success, -1 on failure. */
+extern int i386_insert_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Remove a watchpoint that watched the memory region which starts at
+ address ADDR, whose length is LEN bytes, and for accesses of the
+ type TYPE. Return 0 on success, -1 on failure. */
+extern int i386_remove_watchpoint (CORE_ADDR addr, int len, int type);
+
+/* Return non-zero if we can watch a memory region that starts at
+ address ADDR and whose length is LEN bytes. */
+extern int i386_region_ok_for_watchpoint (CORE_ADDR addr, int len);
+
+/* Return non-zero if the inferior has some break/watchpoint that
+ triggered. */
+extern int i386_stopped_by_hwbp (void);
+
+/* If the inferior has some break/watchpoint that triggered, set
+ the address associated with that break/watchpoint and return
+ true. Otherwise, return false. */
+extern int i386_stopped_data_address (struct target_ops *, CORE_ADDR *);
+
+/* Insert a hardware-assisted breakpoint at BP_TGT->placed_address.
+ Return 0 on success, EBUSY on failure. */
+struct bp_target_info;
+extern int i386_insert_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address.
+ Return 0 on success, -1 on failure. */
+extern int i386_remove_hw_breakpoint (struct bp_target_info *bp_tgt);
+
+extern int i386_stopped_by_watchpoint (void);
+
+#ifndef I386_WATCHPOINTS_IN_TARGET_VECTOR
+
+/* Returns the number of hardware watchpoints of type TYPE that we can
+ set. Value is positive if we can set CNT watchpoints, zero if
+ setting watchpoints of type TYPE is not supported, and negative if
+ CNT is more than the maximum number of watchpoints of type TYPE
+ that we can support. TYPE is one of bp_hardware_watchpoint,
+ bp_read_watchpoint, bp_write_watchpoint, or bp_hardware_breakpoint.
+ CNT is the number of such watchpoints used so far (including this
+ one). OTHERTYPE is non-zero if other types of watchpoints are
+ currently enabled.
+
+ We always return 1 here because we don't have enough information
+ about possible overlap of addresses that they want to watch. As an
+ extreme example, consider the case where all the watchpoints watch
+ the same address and the same region length: then we can handle a
+ virtually unlimited number of watchpoints, due to debug register
+ sharing implemented via reference counts in i386-nat.c. */
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
+
+/* Returns non-zero if we can use hardware watchpoints to watch a
+ region whose address is ADDR and whose length is LEN. */
+
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) \
+ i386_region_ok_for_watchpoint (addr, len)
+
+/* After a watchpoint trap, the PC points to the instruction after the
+ one that caused the trap. Therefore we don't need to step over it.
+ But we do need to reset the status register to avoid another trap. */
+
+#define HAVE_CONTINUABLE_WATCHPOINT 1
+
+#define STOPPED_BY_WATCHPOINT(W) (i386_stopped_by_watchpoint () != 0)
+
+#define target_stopped_data_address(target, x) \
+ i386_stopped_data_address(target, x)
+
+/* Use these macros for watchpoint insertion/removal. */
+
+#define target_insert_watchpoint(addr, len, type) \
+ i386_insert_watchpoint (addr, len, type)
+
+#define target_remove_watchpoint(addr, len, type) \
+ i386_remove_watchpoint (addr, len, type)
+
+#define target_insert_hw_breakpoint(bp_tgt) \
+ i386_insert_hw_breakpoint (bp_tgt)
+
+#define target_remove_hw_breakpoint(bp_tgt) \
+ i386_remove_hw_breakpoint (bp_tgt)
+
+#endif /* I386_WATCHPOINTS_IN_TARGET_VECTOR */
+
+#endif /* I386_USE_GENERIC_WATCHPOINTS */
+
+#endif /* NM_I386_H */
diff --git a/gdb/config/i386/nm-linux64.h b/gdb/config/i386/nm-linux64.h
new file mode 100644
index 0000000..19d710a
--- /dev/null
+++ b/gdb/config/i386/nm-linux64.h
@@ -0,0 +1,54 @@
+/* Native support for GNU/Linux x86-64.
+
+ Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+ Free Software Foundation, Inc.
+
+ Contributed by Jiri Smid, SuSE Labs.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef NM_LINUX64_H
+#define NM_LINUX64_H
+
+/* GNU/Linux supports the i386 hardware debugging registers. */
+#define I386_USE_GENERIC_WATCHPOINTS
+#define I386_WATCHPOINTS_IN_TARGET_VECTOR
+
+#include "i386/nm-i386.h"
+#include "config/nm-linux.h"
+
+/* Support for 8-byte wide hardware watchpoints. */
+#define TARGET_HAS_DR_LEN_8 1
+
+/* Provide access to the i386 hardware debugging registers. */
+
+extern void amd64_linux_dr_set_control (unsigned long control);
+#define I386_DR_LOW_SET_CONTROL(control) \
+ amd64_linux_dr_set_control (control)
+
+extern void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+#define I386_DR_LOW_SET_ADDR(regnum, addr) \
+ amd64_linux_dr_set_addr (regnum, addr)
+
+extern void amd64_linux_dr_reset_addr (int regnum);
+#define I386_DR_LOW_RESET_ADDR(regnum) \
+ amd64_linux_dr_reset_addr (regnum)
+
+extern unsigned long amd64_linux_dr_get_status (void);
+#define I386_DR_LOW_GET_STATUS() \
+ amd64_linux_dr_get_status ()
+
+#endif /* nm-linux64.h */
diff --git a/gdb/config/mips/nm-irix5.h b/gdb/config/mips/nm-irix5.h
new file mode 100644
index 0000000..49ac420
--- /dev/null
+++ b/gdb/config/mips/nm-irix5.h
@@ -0,0 +1,44 @@
+/* Definitions for native support of irix5.
+
+ Copyright 1993, 1996, 1998, 1999, 2000, 2007, 2008, 2009
+ 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/>. */
+
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+
+/* TARGET_CAN_USE_HARDWARE_WATCHPOINT is now defined to go through
+ the target vector. For Irix5, procfs_can_use_hw_watchpoint()
+ should be invoked. */
+
+/* When a hardware watchpoint fires off the PC will be left at the
+ instruction which caused the watchpoint. It will be necessary for
+ GDB to step over the watchpoint. */
+
+#define STOPPED_BY_WATCHPOINT(W) \
+ procfs_stopped_by_watchpoint(inferior_ptid)
+extern int procfs_stopped_by_watchpoint (ptid_t);
+
+/* Use these macros for watchpoint insertion/deletion. */
+/* type can be 0: write watch, 1: read watch, 2: access watch (read/write) */
+#define target_insert_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, LEN, TYPE, 0)
+#define target_remove_watchpoint(ADDR, LEN, TYPE) \
+ procfs_set_watchpoint (inferior_ptid, ADDR, 0, 0, 0)
+extern int procfs_set_watchpoint (ptid_t, CORE_ADDR, int, int, int);
+
+#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(SIZE) 1
+
diff --git a/gdb/configure b/gdb/configure
index 7f26c64..0542f7e 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -676,6 +676,8 @@ REPORT_BUGS_TO
PKGVERSION
TARGET_OBS
subdirs
+pythondir
+GDB_DATADIR_PATH
GDB_DATADIR
DEBUGDIR
am__fastdepCC_FALSE
@@ -885,6 +887,7 @@ enable_dependency_tracking
with_separate_debug_dir
with_gdb_datadir
with_relocated_sources
+with_pythondir
enable_targets
enable_64_bit_bfd
enable_gdbcli
@@ -1586,6 +1589,10 @@ Optional Packages:
[DATADIR/gdb]
--with-relocated-sources=PATH
automatically relocate this path for source files
+ --with-gdb-datadir look for global separate data files in this path
+ [DATADIR/gdb]
+ --with-pythondir install Python data files in this path
+ [DATADIR/gdb/python]
--with-libunwind use libunwind frame unwinding support
--with-curses use the curses library instead of the termcap
library
@@ -6866,6 +6873,73 @@ _ACEOF
fi
+# GDB's datadir relocation
+
+gdbdatadir=${datadir}/gdb
+
+
+# Check whether --with-gdb-datadir was given.
+if test "${with_gdb_datadir+set}" = set; then :
+ withval=$with_gdb_datadir; gdbdatadir="${withval}"
+fi
+
+
+
+ test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+ ac_define_dir=`eval echo $gdbdatadir`
+ ac_define_dir=`eval echo $ac_define_dir`
+
+cat >>confdefs.h <<_ACEOF
+#define GDB_DATADIR "$ac_define_dir"
+_ACEOF
+
+
+
+if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then
+ if test "x$prefix" = xNONE; then
+ test_prefix=/usr/local
+ else
+ test_prefix=$prefix
+ fi
+else
+ test_prefix=$exec_prefix
+fi
+
+case ${gdbdatadir} in
+ "${test_prefix}"|"${test_prefix}/"*|\
+ '${exec_prefix}'|'${exec_prefix}/'*)
+
+$as_echo "#define GDB_DATADIR_RELOCATABLE 1" >>confdefs.h
+
+ ;;
+esac
+GDB_DATADIR_PATH=${gdbdatadir}
+
+
+
+# Check whether --with-pythondir was given.
+if test "${with_pythondir+set}" = set; then :
+ withval=$with_pythondir; pythondir="${withval}"
+else
+ pythondir=no
+fi
+
+
+# If the user passed in a path, define it. Otherwise, compute it at
+# runtime based on the possibly-relocatable datadir.
+if test "$pythondir" = "no"; then
+ pythondir='$(GDB_DATADIR_PATH)/python'
+else
+
+cat >>confdefs.h <<_ACEOF
+#define PYTHONDIR "$pythondir"
+_ACEOF
+
+fi
+
+
+
subdirs="$subdirs doc testsuite"
@@ -9604,6 +9678,8 @@ $as_echo "#define HAVE_PYTHON 1" >>confdefs.h
CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)"
CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)"
CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)"
+ CONFIG_INSTALL="$CONFIG_INSTALL install-python"
+ CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python"
ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)"
# Flags needed to compile Python code (taken from python-config --cflags).
diff --git a/gdb/configure.ac b/gdb/configure.ac
index ebb0a95..c8ebafe 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -108,6 +108,51 @@ AS_HELP_STRING([--with-relocated-sources=PATH], [automatically relocate this pat
[Relocated directory for source files. ])
])
+# GDB's datadir relocation
+
+gdbdatadir=${datadir}/gdb
+
+AC_ARG_WITH([gdb-datadir],
+ [AS_HELP_STRING([--with-gdb-datadir],
+ [look for global separate data files in this path [DATADIR/gdb]])], [gdbdatadir="${withval}"])
+
+AC_DEFINE_DIR(GDB_DATADIR, gdbdatadir,
+ [Global directory for GDB data files. ])
+
+if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then
+ if test "x$prefix" = xNONE; then
+ test_prefix=/usr/local
+ else
+ test_prefix=$prefix
+ fi
+else
+ test_prefix=$exec_prefix
+fi
+
+case ${gdbdatadir} in
+ "${test_prefix}"|"${test_prefix}/"*|\
+ '${exec_prefix}'|'${exec_prefix}/'*)
+ AC_DEFINE(GDB_DATADIR_RELOCATABLE, 1, [Define if GDB datadir should be relocated when GDB is moved.])
+ ;;
+esac
+GDB_DATADIR_PATH=${gdbdatadir}
+AC_SUBST(GDB_DATADIR_PATH)
+
+AC_ARG_WITH([pythondir],
+ [AS_HELP_STRING([--with-pythondir],
+ [install Python data files in this path [DATADIR/gdb/python]])], [pythondir="${withval}"], [pythondir=no])
+
+# If the user passed in a path, define it. Otherwise, compute it at
+# runtime based on the possibly-relocatable datadir.
+if test "$pythondir" = "no"; then
+ pythondir='$(GDB_DATADIR_PATH)/python'
+else
+ AC_DEFINE_UNQUOTED(PYTHONDIR, "$pythondir",
+ [Define to install path for Python sources])
+fi
+AC_SUBST(pythondir)
+
+
AC_CONFIG_SUBDIRS(doc testsuite)
# Check whether to support alternative target configurations
@@ -674,6 +719,8 @@ if test "${have_libpython}" = yes; then
CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)"
CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)"
CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)"
+ CONFIG_INSTALL="$CONFIG_INSTALL install-python"
+ CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python"
ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)"
# Flags needed to compile Python code (taken from python-config --cflags).
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 816a355..e9f56f9 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -3570,6 +3570,7 @@ static struct sym_fns aout_sym_fns =
dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */
dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */
dbx_symfile_read, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
dbx_symfile_finish, /* sym_finish: finished with file, cleanup */
default_symfile_offsets, /* sym_offsets: parse user's offsets to
internal form */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 253e251..6d73fc5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -962,8 +962,10 @@ Connect to process ID @var{number}, as with the @code{attach} command.
@itemx -x @var{file}
@cindex @code{--command}
@cindex @code{-x}
-Execute @value{GDBN} commands from file @var{file}. @xref{Command
-Files,, Command files}.
+Execute commands from file @var{file}. If @var{file} ends in
+@samp{.py}, then the file is evaluated as Python code. If Python
+support is not enabled in this @value{GDBN}, then an error occurs.
+@xref{Command Files,, Command files}.
@item -eval-command @var{command}
@itemx -ex @var{command}
@@ -1155,6 +1157,16 @@ for remote debugging.
Run using @var{device} for your program's standard input and output.
@c FIXME: kingdon thinks there is more to -tty. Investigate.
+@item -P
+@cindex @code{-P}
+@itemx --python
+@cindex @code{--python}
+Change interpretation of command line so that the argument immediately
+following this switch is taken to be the name of a Python script file.
+This option stops option processing; subsequent options are passed to
+Python as @code{sys.argv}. This option is only available if Python
+scripting support was enabled when @value{GDBN} was configured.
+
@c resolve the situation of these eventually
@item -tui
@cindex @code{--tui}
@@ -19101,7 +19113,7 @@ command:
@table @code
@kindex source
@cindex execute commands from a file
-@item source [@code{-v}] @var{filename}
+@item source [@code{-v}] [@code{-p}] @var{filename}
Execute the command file @var{filename}.
@end table
@@ -19118,6 +19130,11 @@ If @code{-v}, for verbose mode, is given then @value{GDBN} displays
each command as it is executed. The option must be given before
@var{filename}, and is interpreted as part of the filename anywhere else.
+If @var{filename} ends in @samp{.py}, or if @code{-p}, for Python, is
+given then @value{GDBN} evaluates the contents of the file as Python
+code. If Python support is not compiled in to @value{GDBN}, then an
+error occurs.
+
Commands that would ask for confirmation if used interactively proceed
without asking when used in a command file. Many @value{GDBN} commands that
normally print messages to say what they are doing omit the messages
@@ -19379,8 +19396,6 @@ containing @code{end}. For example:
@smallexample
(@value{GDBP}) python
-Type python script
-End with a line saying just "end".
>print 23
>end
23
@@ -19393,6 +19408,14 @@ in a Python script. This can be controlled using @code{maint set
python print-stack}: if @code{on}, the default, then Python stack
printing is enabled; if @code{off}, then Python stack printing is
disabled.
+
+@kindex maint set python auto-load
+@item maint set python auto-load
+By default, @value{GDBN} will attempt to automatically load Python
+code when an object file is opened. This can be controlled using
+@code{maint set python auto-load}: if @code{on}, the default, then
+Python auto-loading is enabled; if @code{off}, then Python
+auto-loading is disabled.
@end table
@node Python API
@@ -19400,6 +19423,14 @@ disabled.
@cindex python api
@cindex programming in python
+You can get quick online help for @value{GDBN}'s Python API by issuing
+the command @w{@kbd{python help (gdb)}}.
+
+Functions and methods which have two or more optional arguments allow
+them to be specified using keyword syntax. This allows passing some
+optional arguments while skipping others. Example:
+@w{@code{gdb.some_function ('foo', bar = 1, baz = 2)}}.
+
@cindex python stdout
@cindex python pagination
At startup, @value{GDBN} overrides Python's @code{sys.stdout} and
@@ -19412,13 +19443,17 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Basic Python:: Basic Python Functions.
* Exception Handling::
* Auto-loading:: Automatically loading Python code.
-* Values From Inferior::
+* Values From Inferior:: Python representation of values.
* Types In Python:: Python representation of types.
* Pretty Printing:: Pretty-printing values.
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
+* Inferiors In Python:: Python representation of inferiors (processes)
+* Threads In Python:: Accessing inferior threads from Python.
* Commands In Python:: Implementing new commands in Python.
+* Parameters In Python:: Adding new @value{GDBN} parameters.
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
+* Breakpoints In Python:: Manipulating breakpoints using Python.
* Frames In Python:: Acessing inferior stack frames from Python.
* Lazy Strings In Python:: Python representation of lazy strings.
@end menu
@@ -19446,6 +19481,12 @@ command as having originated from the user invoking it interactively.
It must be a boolean value. If omitted, it defaults to @code{False}.
@end defun
+@findex gdb.breakpoints
+@defun breakpoints
+Return a sequence holding all of @value{GDBN}'s breakpoints.
+@xref{Breakpoints In Python}, for more information.
+@end defun
+
@findex gdb.parameter
@defun parameter parameter
Return the value of a @value{GDBN} parameter. @var{parameter} is a
@@ -19462,6 +19503,7 @@ a Python value of the appropriate type, and returned.
@defun history number
Return a value from @value{GDBN}'s value history (@pxref{Value
History}). @var{number} indicates which history element to return.
+
If @var{number} is negative, then @value{GDBN} will take its absolute value
and count backward from the last element (i.e., the most recent element) to
find the value to return. If @var{number} is zero, then @value{GDBN} will
@@ -19486,6 +19528,21 @@ compute values, for example, it is the only way to get the value of a
convenience variable (@pxref{Convenience Vars}) as a @code{gdb.Value}.
@end defun
+@findex gdb.post_event
+@defun post_event event
+Put @var{event}, a callable object taking no arguments, into
+@value{GDBN}'s internal event queue. This callable will be invoked at
+some later point, during @value{GDBN}'s event processing. Events
+posted using @code{post_event} will be run in the order in which they
+were posted; however, there is no way to know when they will be
+processed relative to other events inside @value{GDBN}.
+
+@value{GDBN} is not thread-safe. If your Python program uses multiple
+threads, you must be careful to only call @value{GDBN}-specific
+functions in the main @value{GDBN} thread. @code{post_event} ensures
+this.
+@end defun
+
@findex gdb.write
@defun write string
Print a string to @value{GDBN}'s paginated standard output stream.
@@ -19500,6 +19557,11 @@ Flush @value{GDBN}'s paginated standard output stream. Flushing
function.
@end defun
+@findex gdb.solib_address
+@defun solib_address @var{address}
+Return the name of the shared library holding the given address, or None.
+@end defun
+
@node Exception Handling
@subsubsection Exception Handling
@cindex python exceptions
@@ -19738,6 +19800,9 @@ module:
This function looks up a type by name. @var{name} is the name of the
type to look up. It must be a string.
+If @var{block} is given, then @var{name} is looked up in that scope.
+Otherwise, it is searched for globally.
+
Ordinarily, this function will return an instance of @code{gdb.Type}.
If the named type cannot be found, it will throw an exception.
@end defun
@@ -19860,7 +19925,7 @@ If the type does not have a target, this method will throw an
exception.
@end defmethod
-@defmethod Type template_argument n
+@defmethod Type template_argument n [block]
If this @code{gdb.Type} is an instantiation of a template, this will
return a new @code{gdb.Type} which represents the type of the
@var{n}th template argument.
@@ -19868,7 +19933,8 @@ return a new @code{gdb.Type} which represents the type of the
If this @code{gdb.Type} is not a template type, this will throw an
exception. Ordinarily, only C@t{++} code will have template types.
-@var{name} is searched for globally.
+If @var{block} is given, then @var{name} is looked up in that scope.
+Otherwise, it is searched for globally.
@end defmethod
@end table
@@ -20222,6 +20288,121 @@ import gdb.libstdcxx.v6
gdb.libstdcxx.v6.register_printers (gdb.current_objfile ())
@end smallexample
+@node Inferiors In Python
+@subsubsection Inferiors In Python
+
+Programs which are being run under @value{GDBN} are called inferiors
+(@pxref{Inferiors and Programs}). Python scripts can access
+information about and manipulate inferiors controlled by @value{GDBN}
+via objects of the @code{gdb.Inferior} class.
+
+The following inferior-related functions are available in the @code{gdb}
+module:
+
+@defun inferiors
+Return a tuple containing all inferior objects.
+@end defun
+
+A @code{gdb.Inferior} object has the following attributes:
+
+@table @code
+@defivar Inferior num
+ID of inferior, as assigned by GDB.
+@end defivar
+
+@defivar Inferior pid
+Process ID of the inferior, assigned by the underlying OS.
+@end defivar
+
+@defivar Inferior was_attached
+Boolean signaling whether the inferior was created using `attach', or
+started by @value{GDBN} itself.
+@end defivar
+@end table
+
+A @code{gdb.Inferior} object has the following methods:
+
+@table @code
+@defmethod Inferior threads
+This method returns a tuple holding all the threads which are valid
+when it is called. If there are no valid threads, the method will
+return an empty list.
+@end defmethod
+
+@findex gdb.read_memory
+@defmethod Inferior read_memory @var{address} @var{length}
+Read @var{length} bytes of memory from the inferior, starting at
+@var{address}. Returns a buffer object, which behaves much like an array
+or a string. It can be modified and given to the @code{gdb.write_memory}
+function.
+@end defmethod
+
+@findex gdb.write_memory
+@defmethod Inferior write_memory @var{address} @var{buffer} @r{[}@var{length}@r{]}
+Write the contents of @var{buffer} (a Python object which supports the
+buffer protocol, i.e., a string, an array or the object returned from
+@code{gdb.read_memory}) to the inferior, starting at @var{address}.
+If given, @var{length} determines the number of bytes from @var{buffer} to
+be written.
+@end defmethod
+
+@findex gdb.search_memory
+@defmethod Inferior search_memory @var{address} @var{length} @var{pattern} @r{[}@var{size}@r{]} @r{[}@var{max_count}@r{]}
+Search a region of the inferior memory starting at @var{address} with the
+given @var{length}. @var{pattern} can be a string, a byte array, a buffer
+object, a number, a @code{gdb.Value} object (@pxref{Values From Inferior})
+or a list or tuple with elements in any combination of those types. If
+@var{size} is given and is non-zero, it specifies the size in bytes of a
+Python scalar or @code{gdb.Value} in the search pattern. If @var{size} is
+zero or not specified, it is taken from the value's type in the current
+language. This is useful when one wants to specify the search pattern as
+a mixture of types. Note that this means, for example, that in the case of
+C-like languages a search for an untyped 0x42 will search for
+@samp{(int) 0x42} which is typically four bytes. @var{max_count} is the
+highest number of matches to search for.
+@end defmethod
+@end table
+
+@node Threads In Python
+@subsubsection Threads In Python
+
+Python scripts can access information about and manipulate inferior threads
+controlled by @value{GDBN} via objects of the @code{gdb.InferiorThread} class.
+
+The following inferior-related functions are available in the @code{gdb}
+module:
+
+@findex gdb.selected_thread
+@defun selected_thread
+This function returns the thread object for the selected thread. If there
+is no selected thread, this will return @code{None}.
+@end defun
+
+A @code{gdb.InferiorThread} object has the following attributes:
+
+@table @code
+@defivar InferiorThread num
+ID of the thread, as assigned by GDB.
+@end defivar
+@end table
+
+A @code{gdb.InferiorThread} object has the following methods:
+
+@table @code
+@defmethod InferiorThread frames
+Return a tuple containing all frames in the thread.
+@end defmethod
+
+@defmethod InferiorThread newest_frame
+Return the newest frame thread's stack.
+@end defmethod
+
+@defmethod InferiorThread switch_to_thread
+This changes @value{GDBN}'s currently selected thread to the one represented
+by this object.
+@end defmethod
+@end table
+
@node Commands In Python
@subsubsection Commands In Python
@@ -20474,6 +20655,135 @@ registration of the command with @value{GDBN}. Depending on how the
Python code is read into @value{GDBN}, you may need to import the
@code{gdb} module explicitly.
+@node Parameters In Python
+@subsubsection Parameters In Python
+
+@cindex parameters in python
+@cindex python parameters
+@tindex gdb.Parameter
+@tindex Parameter
+You can implement new @value{GDBN} parameters using Python. A new
+parameter is implemented as an instance of the @code{gdb.Parameter}
+class. Parameters are exposed to the user via the @code{set} and
+@code{show} commands.
+
+@defmethod Parameter __init__ name @var{command-class} @var{parameter-class} @r{[}@var{enum-sequence}@r{]}
+The object initializer for @code{Parameter} registers the new
+parameter with @value{GDBN}. This initializer is normally invoked
+from the subclass' own @code{__init__} method.
+
+@var{name} is the name of the new parameter. If @var{name} consists
+of multiple words, then the initial words are looked for as prefix
+commands. In this case, if one of the prefix commands does not exist,
+an exception is raised.
+
+@var{command-class} should be one of the @samp{COMMAND_} constants
+(@pxref{Commands In Python}). This argument tells @value{GDBN} how to
+categorize the new parameter in the help system.
+
+@var{parameter-class} should be one of the @samp{PARAM_} constants
+defined below. This argument tells @value{GDBN} the type of the new
+parameter; this information is used for input validation and
+completion.
+
+If @var{parameter-class} is @code{PARAM_ENUM}, then
+@var{enum-sequence} must be a sequence of strings. These strings
+represent the possible values for the parameter.
+
+If @var{parameter-class} is not @code{PARAM_ENUM}, then the presence
+of a fourth argument will cause an exception to be thrown.
+
+The help text for the new parameter is taken from the Python
+documentation string for the parameter's class, if there is one. If
+there is no documentation string, a default value is used.
+@end defmethod
+
+@defivar Parameter set_doc
+If this attribute exists, and is a string, then its value is used as
+the help text for this parameter's @code{set} command. The value is
+examined when @code{Parameter.__init__} is invoked; subsequent changes
+have no effect.
+@end defivar
+
+@defivar Parameter show_doc
+If this attribute exists, and is a string, then its value is used as
+the help text for this parameter's @code{show} command. The value is
+examined when @code{Parameter.__init__} is invoked; subsequent changes
+have no effect.
+@end defivar
+
+@defivar Parameter value
+The @code{value} attribute holds the underlying value of the
+parameter. It can be read and assigned to just as any other
+attribute. @value{GDBN} does validation when assignments are made.
+@end defivar
+
+
+When a new parameter is defined, its type must be specified. The
+available types are represented by constants defined in the @code{gdb}
+module:
+
+@table @code
+@findex PARAM_BOOLEAN
+@findex gdb.PARAM_BOOLEAN
+@item PARAM_BOOLEAN
+The value is a plain boolean. The Python boolean values, @code{True}
+and @code{False} are the only valid values.
+
+@findex PARAM_AUTO_BOOLEAN
+@findex gdb.PARAM_AUTO_BOOLEAN
+@item PARAM_AUTO_BOOLEAN
+The value has three possible states: true, false, and @samp{auto}. In
+Python, true and false are represented using boolean constants, and
+@samp{auto} is represented using @code{None}.
+
+@findex PARAM_UINTEGER
+@findex gdb.PARAM_UINTEGER
+@item PARAM_UINTEGER
+The value is an unsigned integer. The value of 0 should be
+interpreted to mean ``unlimited''.
+
+@findex PARAM_INTEGER
+@findex gdb.PARAM_INTEGER
+@item PARAM_INTEGER
+The value is a signed integer. The value of 0 should be interpreted
+to mean ``unlimited''.
+
+@findex PARAM_STRING
+@findex gdb.PARAM_STRING
+@item PARAM_STRING
+The value is a string. When the user modifies the string, escapes are
+translated.
+
+@findex PARAM_STRING_NOESCAPE
+@findex gdb.PARAM_STRING_NOESCAPE
+@item PARAM_STRING_NOESCAPE
+The value is a string. When the user modifies the string, escapes are
+passed through untranslated.
+
+@findex PARAM_OPTIONAL_FILENAME
+@findex gdb.PARAM_OPTIONAL_FILENAME
+@item PARAM_OPTIONAL_FILENAME
+The value is a either a filename (a string), or @code{None}.
+
+@findex PARAM_FILENAME
+@findex gdb.PARAM_FILENAME
+@item PARAM_FILENAME
+The value is a filename (a string).
+
+@findex PARAM_ZINTEGER
+@findex gdb.PARAM_ZINTEGER
+@item PARAM_ZINTEGER
+The value is an integer. This is like @code{PARAM_INTEGER}, except 0
+is interpreted as itself.
+
+@findex PARAM_ENUM
+@findex gdb.PARAM_ENUM
+@item PARAM_ENUM
+The value is a string, which must be one of a collection string
+constants provided when the parameter is created.
+@end table
+
@node Functions In Python
@subsubsection Writing new convenience functions
@@ -20578,6 +20888,82 @@ which is used to format the value. @xref{Pretty Printing}, for more
information.
@end defivar
+@node Breakpoints In Python
+@subsubsection Manipulating breakpoints using Python
+
+@cindex breakpoints in python
+@cindex python breakpoints
+@tindex gdb.Breakpoint
+@tindex Breakpoint
+Python code can manipulate breakpoints via the @code{gdb.Breakpoint}
+class.
+
+@defmethod Breakpoint __init__ location
+Create a new breakpoint. @var{location} is a string naming the
+location of the breakpoint. The contents can be any location
+recognized by the @code{break} command.
+@end defmethod
+
+@defmethod Breakpoint is_valid
+Return @code{True} if this @code{Breakpoint} object is valid,
+@code{False} otherwise. A @code{Breakpoint} object can become invalid
+if the user deletes the breakpoint. In this case, the object still
+exists, but the underlying breakpoint does not.
+@end defmethod
+
+@defivar Breakpoint enabled
+This attribute is @code{True} if the breakpoint is enabled, and
+@code{False} otherwise. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint silent
+This attribute is @code{True} if the breakpoint is silent, and
+@code{False} otherwise. This attribute is writable.
+
+Note that a breakpoint can also be silent if it has commands and the
+first command is @code{silent}. This is not reported by the
+@code{silent} attribute.
+@end defivar
+
+@defivar Breakpoint thread
+If the breakpoint is thread-specific, this attribute holds the thread
+id. If the breakpoint is not thread-specific, this attribute is
+@code{None}. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint ignore_count
+This attribute holds the ignore count for the breakpoint, an integer.
+This attribute is writable.
+@end defivar
+
+@defivar Breakpoint number
+This attribute holds the breakpoint's number -- the identifier used by
+the user to manipulate the breakpoint. This attribute is not writable.
+@end defivar
+
+@defivar Breakpoint hit_count
+This attribute holds the hit count for the breakpoint, an integer.
+This attribute is writable, but currently it can only be set to zero.
+@end defivar
+
+@defivar Breakpoint location
+This attribute holds the location of the breakpoint, as specified by
+the user. It is a string. This attribute is not writable.
+@end defivar
+
+@defivar Breakpoint condition
+This attribute holds the condition of the breakpoint, as specified by
+the user. It is a string. If there is no condition, this attribute's
+value is @code{None}. This attribute is writable.
+@end defivar
+
+@defivar Breakpoint commands
+This attribute holds the commands attached to the breakpoint. If
+there are commands, this returns a string holding all the commands,
+separated by newlines. If there are no commands, this attribute is
+@code{None}. This attribute is not writable.
+@end defivar
+
@node Frames In Python
@subsubsection Acessing inferior stack frames from Python.
@@ -20642,6 +21028,14 @@ function to a string.
Returns the frame's resume address.
@end defmethod
+@defmethod Frame block
+Returns the frame's code block. @c (@pxref{Block,,Code Blocks and Scopes}).
+@end defmethod
+
+@defmethod Frame function
+Returns the symbol for the function corresponding to this frame. @c (@pxref{Symbols In Python}).
+@end defmethod
+
@defmethod Frame older
Return the frame that called this frame.
@end defmethod
@@ -20650,10 +21044,18 @@ Return the frame that called this frame.
Return the frame called by this frame.
@end defmethod
+@defmethod Frame find_sal
+Return the frame's symtab and line object. @c (@pxref{Symtab_and_line,, Symtab and line}).
+@end defmethod
+
@defmethod Frame read_var variable
Return the value of the given variable in this frame. @var{variable} must
be a string.
@end defmethod
+
+@defmethod Frame select
+Set this frame to be the user's selected frame.
+@end defmethod
@end table
@node Lazy Strings In Python
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index 347c860..5d7002e 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -2107,6 +2107,18 @@ time, and so we attempt to handle symbols incrementally. For instance,
we create @dfn{partial symbol tables} consisting of only selected
symbols, and only expand them to full symbol tables when necessary.
+@menu
+* Symbol Reading::
+* Partial Symbol Tables::
+* Types::
+* Object File Formats::
+* Debugging File Formats::
+* Adding a New Symbol Reader to GDB::
+* Memory Management for Symbol Files::
+* Memory Management for Types::
+@end menu
+
+@node Symbol Reading
@section Symbol Reading
@cindex symbol reading
@@ -2199,6 +2211,7 @@ symtab. Upon return, @code{pst->readin} should have been set to 1, and
zero if there were no symbols in that part of the symbol file.
@end table
+@node Partial Symbol Tables
@section Partial Symbol Tables
@value{GDBN} has three types of symbol tables:
@@ -2294,6 +2307,7 @@ and all the psymbols themselves are allocated in a pair of large arrays
on an obstack, so there is little to be gained by trying to free them
unless you want to do a lot more work.
+@node Types
@section Types
@unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}).
@@ -2316,6 +2330,7 @@ types map to one @code{TYPE_CODE_*} type, and are distinguished by
other members of the type struct, such as whether the type is signed
or unsigned, and how many bits it uses.
+@anchor{Builtin Types}
@unnumberedsubsec Builtin Types (e.g., @code{builtin_type_void}, @code{builtin_type_char}).
These are instances of type structs that roughly correspond to
@@ -2330,6 +2345,7 @@ only one instance exists, while @file{c-lang.c} builds as many
@code{TYPE_CODE_INT} types as needed, with each one associated with
some particular objfile.
+@node Object File Formats
@section Object File Formats
@cindex object file formats
@@ -2415,6 +2431,7 @@ SOM, which is a cross-language ABI).
The SOM reader is in @file{somread.c}.
+@node Debugging File Formats
@section Debugging File Formats
This section describes characteristics of debugging information that
@@ -2486,6 +2503,7 @@ DWARF 3 is an improved version of DWARF 2.
@cindex SOM debugging info
Like COFF, the SOM definition includes debugging information.
+@node Adding a New Symbol Reader to GDB
@section Adding a New Symbol Reader to @value{GDBN}
@cindex adding debugging info reader
@@ -2508,6 +2526,7 @@ will only ever be implemented by one object file format may be called
directly. This interface should be described in a file
@file{bfd/lib@var{xyz}.h}, which is included by @value{GDBN}.
+@node Memory Management for Symbol Files
@section Memory Management for Symbol Files
Most memory associated with a loaded symbol file is stored on
@@ -2519,10 +2538,45 @@ released when the objfile is unloaded or reloaded. Therefore one
objfile must not reference symbol or type data from another objfile;
they could be unloaded at different times.
-User convenience variables, et cetera, have associated types. Normally
-these types live in the associated objfile. However, when the objfile
-is unloaded, those types are deep copied to global memory, so that
-the values of the user variables and history items are not lost.
+@node Memory Management for Types
+@section Memory Management for Types
+@cindex memory management for types
+
+@findex TYPE_OBJFILE
+@code{TYPE_OBJFILE} macro indicates the current memory owner of the type.
+Non-@code{NULL} value indicates it is owned by an objfile (specifically by its
+obstack) and in such case the type remains valid till the objfile is unloaded
+or reloaded. For such types with an associated objfile no reference counting
+is being made.
+
+User convenience variables, et cetera, have associated types. Normally these
+types live in the associated objfile. However, when the objfile is unloaded,
+those types are deep copied to global memory, so that the values of the user
+variables and history items are not lost. During the copy they will get their
+@code{TYPE_OBJFILE} set to @code{NULL} and become so-called @dfn{reclaimable}
+types.
+
+Types with null @code{TYPE_OBJFILE} can be either permanent types
+(@pxref{Builtin Types}) or reclaimable types which will be deallocated at the
+first idle @value{GDBN} moment if the last object referencing them is removed.
+Permanent types are allocated by the function @code{alloc_type} (and its
+derivations like @code{init_type}) specifying objfile as @code{NULL}. The
+reclaimable types are created the same way but moreover they need to have
+@code{type_init_group} called to start their tracking as being possibly
+deallocatable.
+
+@findex free_all_types
+When @value{GDBN} gets idle it always calls the @code{free_all_types} function
+which deallocates any unused types. All types currently not owned by an
+objfile must be marked as used on each @code{free_all_types} call as they would
+get deallocated as unused otherwise.
+
+@code{free_all_types} automatically checks for any cross-type references such
+as through @code{TYPE_TARGET_TYPE}, @code{TYPE_POINTER_TYPE} etc.@: and
+prevents early deallocation for any such existing references. Reclaimable
+types may reference any other reclaimable types or even permanent types. But
+permanent types must not reference reclaimable types (nor an objfile associated
+type).
@node Language Support
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index db3d114..759200f 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -213,6 +213,11 @@ Bytes from @var{data} to @var{data} + @var{len} have been written
to the current inferior at @var{addr}.
@end deftypefun
+@deftypefun void mark_used (void)
+Mark any possibly reclaimable objects as used during a mark-and-sweep garbage
+collector pass. Currently only @code{type_mark_used} marker is supported.
+@end deftypefun
+
@deftypefun void test_notification (int @var{somearg})
This observer is used for internal testing. Do not use.
See testsuite/gdb.gdb/observer.exp.
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 99100d7..5915249 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -38,6 +38,7 @@
#include "complaints.h"
#include "dwarf2-frame.h"
+#include "addrmap.h"
struct comp_unit;
@@ -1582,6 +1583,14 @@ dwarf2_frame_find_fde (CORE_ADDR *pc)
CORE_ADDR offset;
CORE_ADDR seek_pc;
+ if (objfile->quick_addrmap)
+ {
+ if (!addrmap_find (objfile->quick_addrmap, *pc))
+ continue;
+ }
+ /* FIXME: Read-in only .debug_frame/.eh_frame without .debug_info? */
+ require_partial_symbols (objfile);
+
fde_table = objfile_data (objfile, dwarf2_frame_objfile_data);
if (fde_table == NULL)
continue;
diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 5e27d38..628ba88 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -848,6 +848,13 @@ execute_stack_op (struct dwarf_expr_context *ctx,
ctx->initialized = 0;
goto no_push;
+ case DW_OP_push_object_address:
+ if (ctx->get_object_address == NULL)
+ error (_("DWARF-2 expression error: DW_OP_push_object_address must "
+ "have a value to push."));
+ result = (ctx->get_object_address) (ctx->baton);
+ break;
+
default:
error (_("Unhandled dwarf expression opcode 0x%x"), op);
}
diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h
index 437ca39..f7fce92 100644
--- a/gdb/dwarf2expr.h
+++ b/gdb/dwarf2expr.h
@@ -102,10 +102,10 @@ struct dwarf_expr_context
The result must be live until the current expression evaluation
is complete. */
unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length);
+#endif
/* Return the `object address' for DW_OP_push_object_address. */
CORE_ADDR (*get_object_address) (void *baton);
-#endif
/* The current depth of dwarf expression recursion, via DW_OP_call*,
DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 6679d74..54d2bae 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -121,6 +121,9 @@ struct dwarf_expr_baton
{
struct frame_info *frame;
struct objfile *objfile;
+ /* From DW_TAG_variable's DW_AT_location (not DW_TAG_type's
+ DW_AT_data_location) for DW_OP_push_object_address. */
+ CORE_ADDR object_address;
};
/* Helper functions for dwarf2_evaluate_loc_desc. */
@@ -189,22 +192,33 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc,
symbaton = SYMBOL_LOCATION_BATON (framefunc);
*start = find_location_expression (symbaton, length, pc);
}
- else
+ else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_locexpr_funcs)
{
struct dwarf2_locexpr_baton *symbaton;
+
symbaton = SYMBOL_LOCATION_BATON (framefunc);
- if (symbaton != NULL)
- {
- *length = symbaton->size;
- *start = symbaton->data;
- }
- else
- *start = NULL;
+ gdb_assert (symbaton != NULL);
+ *start = symbaton->data;
+ *length = symbaton->size;
}
+ else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_missing_funcs)
+ {
+ struct dwarf2_locexpr_baton *symbaton;
+
+ symbaton = SYMBOL_LOCATION_BATON (framefunc);
+ gdb_assert (symbaton == NULL);
+ *start = NULL;
+ *length = 0; /* unused */
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ _("Unsupported SYMBOL_COMPUTED_OPS %p for \"%s\""),
+ SYMBOL_COMPUTED_OPS (framefunc),
+ SYMBOL_PRINT_NAME (framefunc));
if (*start == NULL)
error (_("Could not find the frame base for \"%s\"."),
- SYMBOL_NATURAL_NAME (framefunc));
+ SYMBOL_PRINT_NAME (framefunc));
}
/* Helper function for dwarf2_evaluate_loc_desc. Computes the CFA for
@@ -227,6 +241,129 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset)
return target_translate_tls_address (debaton->objfile, offset);
}
+static CORE_ADDR
+dwarf_expr_object_address (void *baton)
+{
+ struct dwarf_expr_baton *debaton = baton;
+
+ /* The message is suppressed in DWARF_BLOCK_EXEC. */
+ if (debaton->object_address == 0)
+ error (_("Cannot resolve DW_OP_push_object_address for a missing object"));
+
+ return debaton->object_address;
+}
+
+/* Address of the variable we are currently referring to. It is set from
+ DW_TAG_variable's DW_AT_location (not DW_TAG_type's DW_AT_data_location) for
+ DW_OP_push_object_address. */
+
+static CORE_ADDR object_address;
+
+/* Callers use object_address_set while their callers use the result set so we
+ cannot run the cleanup at the local block of our direct caller. Still we
+ should reset OBJECT_ADDRESS at least for the next GDB command. */
+
+static void
+object_address_cleanup (void *prev_save_voidp)
+{
+ CORE_ADDR *prev_save = prev_save_voidp;
+
+ object_address = *prev_save;
+ xfree (prev_save);
+}
+
+/* Set the base address - DW_AT_location - of a variable. It is being later
+ used to derive other object addresses by DW_OP_push_object_address.
+
+ It would be useful to sanity check ADDRESS - such as for some objects with
+ unset value_raw_address - but some valid addresses may be zero (such as first
+ objects in relocatable .o files). */
+
+void
+object_address_set (CORE_ADDR address)
+{
+ CORE_ADDR *prev_save;
+
+ prev_save = xmalloc (sizeof *prev_save);
+ *prev_save = object_address;
+ make_cleanup (object_address_cleanup, prev_save);
+
+ object_address = address;
+}
+
+/* Evaluate DWARF expression at DATA ... DATA + SIZE with its result readable
+ by dwarf_expr_fetch (RETVAL, 0). FRAME parameter can be NULL to call
+ get_selected_frame to find it. Returned dwarf_expr_context freeing is
+ pushed on the cleanup chain. */
+
+static struct dwarf_expr_context *
+dwarf_expr_prep_ctx (struct frame_info *frame, gdb_byte *data,
+ unsigned short size, struct dwarf2_per_cu_data *per_cu)
+{
+ struct dwarf_expr_context *ctx;
+ struct dwarf_expr_baton baton;
+
+ if (!frame)
+ frame = get_selected_frame (NULL);
+
+ baton.frame = frame;
+ baton.objfile = dwarf2_per_cu_objfile (per_cu);
+ baton.object_address = object_address;
+
+ ctx = new_dwarf_expr_context ();
+ make_cleanup_free_dwarf_expr_context (ctx);
+
+ ctx->gdbarch = get_objfile_arch (baton.objfile);
+ ctx->addr_size = dwarf2_per_cu_addr_size (per_cu);
+ ctx->baton = &baton;
+ ctx->read_reg = dwarf_expr_read_reg;
+ ctx->read_mem = dwarf_expr_read_mem;
+ ctx->get_frame_base = dwarf_expr_frame_base;
+ ctx->get_frame_cfa = dwarf_expr_frame_cfa;
+ ctx->get_tls_address = dwarf_expr_tls_address;
+ ctx->get_object_address = dwarf_expr_object_address;
+
+ dwarf_expr_eval (ctx, data, size);
+
+ /* It was used only during dwarf_expr_eval. */
+ ctx->baton = NULL;
+
+ return ctx;
+}
+
+/* Evaluate DWARF expression at DLBATON expecting it produces exactly one
+ CORE_ADDR result on the DWARF stack stack. */
+
+CORE_ADDR
+dwarf_locexpr_baton_eval (struct dwarf2_locexpr_baton *dlbaton)
+{
+ struct dwarf_expr_context *ctx;
+ CORE_ADDR retval;
+ struct cleanup *back_to = make_cleanup (null_cleanup, 0);
+
+ ctx = dwarf_expr_prep_ctx (NULL, dlbaton->data, dlbaton->size,
+ dlbaton->per_cu);
+ if (ctx->num_pieces > 0)
+ error (_("DW_OP_*piece is unsupported for DW_FORM_block"));
+
+ retval = dwarf_expr_fetch (ctx, 0);
+
+ if (ctx->location == DWARF_VALUE_REGISTER)
+ {
+ /* Inlined dwarf_expr_read_reg as we no longer have the baton. */
+
+ int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (ctx->gdbarch, retval);
+ struct type *type = builtin_type (ctx->gdbarch)->builtin_data_ptr;
+ struct frame_info *frame = get_selected_frame (NULL);
+
+ retval = address_from_register (type, gdb_regnum, frame);
+ }
+
+ do_cleanups (back_to);
+
+ return retval;
+}
+
struct piece_closure
{
/* The number of pieces used to describe this variable. */
@@ -408,9 +545,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
struct dwarf2_per_cu_data *per_cu)
{
struct value *retval;
- struct dwarf_expr_baton baton;
struct dwarf_expr_context *ctx;
- struct cleanup *old_chain;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, 0);
if (size == 0)
{
@@ -420,22 +556,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
return retval;
}
- baton.frame = frame;
- baton.objfile = dwarf2_per_cu_objfile (per_cu);
-
- ctx = new_dwarf_expr_context ();
- old_chain = make_cleanup_free_dwarf_expr_context (ctx);
-
- ctx->gdbarch = get_objfile_arch (baton.objfile);
- ctx->addr_size = dwarf2_per_cu_addr_size (per_cu);
- ctx->baton = &baton;
- ctx->read_reg = dwarf_expr_read_reg;
- ctx->read_mem = dwarf_expr_read_mem;
- ctx->get_frame_base = dwarf_expr_frame_base;
- ctx->get_frame_cfa = dwarf_expr_frame_cfa;
- ctx->get_tls_address = dwarf_expr_tls_address;
+ ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu);
- dwarf_expr_eval (ctx, data, size);
if (ctx->num_pieces > 0)
{
struct piece_closure *c;
@@ -465,6 +587,11 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
CORE_ADDR address = dwarf_expr_fetch (ctx, 0);
int in_stack_memory = dwarf_expr_fetch_in_stack_memory (ctx, 0);
+ /* object_address_set called here is required in ALLOCATE_VALUE's
+ CHECK_TYPEDEF for the object's possible
+ DW_OP_push_object_address. */
+ object_address_set (address);
+
retval = allocate_value (SYMBOL_TYPE (var));
VALUE_LVAL (retval) = lval_memory;
set_value_lazy (retval, 1);
@@ -872,7 +999,7 @@ static int
loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
{
/* FIXME: Could print the entire list of locations. */
- fprintf_filtered (stream, "a variable with multiple locations");
+ fprintf_filtered (stream, _("a variable with multiple locations"));
return 1;
}
@@ -888,16 +1015,56 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
data = find_location_expression (dlbaton, &size, ax->scope);
if (data == NULL)
- error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol));
+ error (_("Variable \"%s\" is not available."), SYMBOL_PRINT_NAME (symbol));
dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size);
}
-/* The set of location functions used with the DWARF-2 expression
- evaluator and location lists. */
+/* The set of location functions used with the DWARF-2 location lists. */
const struct symbol_computed_ops dwarf2_loclist_funcs = {
loclist_read_variable,
loclist_read_needs_frame,
loclist_describe_location,
loclist_tracepoint_var_ref
};
+
+static struct value *
+missing_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ gdb_assert (dlbaton == NULL);
+ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol));
+}
+
+static int
+missing_read_needs_frame (struct symbol *symbol)
+{
+ return 0;
+}
+
+static int
+missing_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+ fprintf_filtered (stream, _("a variable we are unable to resolve"));
+ return 1;
+}
+
+static void
+missing_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ gdb_assert (dlbaton == NULL);
+ error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol));
+}
+
+/* The set of location functions used with the DWARF-2 evaluator when we are
+ unable to resolve the symbols. */
+const struct symbol_computed_ops dwarf2_missing_funcs = {
+ missing_read_variable,
+ missing_read_needs_frame,
+ missing_describe_location,
+ missing_tracepoint_var_ref
+};
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index fa0bd11..fdea2b4 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -72,5 +72,11 @@ struct dwarf2_loclist_baton
extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
extern const struct symbol_computed_ops dwarf2_loclist_funcs;
+extern const struct symbol_computed_ops dwarf2_missing_funcs;
+
+extern void object_address_set (CORE_ADDR address);
+
+extern CORE_ADDR dwarf_locexpr_baton_eval
+ (struct dwarf2_locexpr_baton *dlbaton);
#endif /* dwarf2loc.h */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 243859c..2fccec5 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -48,6 +48,8 @@
#include "gdbcmd.h"
#include "block.h"
#include "addrmap.h"
+#include "block.h"
+#include "f-lang.h"
#include <fcntl.h>
#include "gdb_string.h"
@@ -96,7 +98,7 @@ typedef struct pubnames_header
_PUBNAMES_HEADER;
#define _ACTUAL_PUBNAMES_HEADER_SIZE 13
-/* .debug_pubnames header
+/* .debug_aranges header
Because of alignment constraints, this structure has padding and cannot
be mapped directly onto the beginning of the .debug_info section. */
typedef struct aranges_header
@@ -153,7 +155,10 @@ struct dwarf2_section_info
asection *asection;
gdb_byte *buffer;
bfd_size_type size;
- int was_mmapped;
+ /* A function to call to deallocate BUFFER. If NULL, no
+ deallocation is needed. A pointer to this structure is passed as
+ the only argument. */
+ void (*destructor) (struct dwarf2_section_info *);
};
struct dwarf2_per_objfile
@@ -333,6 +338,19 @@ struct dwarf2_cu
DIEs for namespaces, we don't need to try to infer them
from mangled names. */
unsigned int has_namespace_info : 1;
+
+ /* Fields are valid according to the LANGUAGE field. */
+ union
+ {
+ /* language_fortran */
+ struct
+ {
+ /* Module names imported to the block being currently read in. */
+ struct fortran_using *use;
+ }
+ fortran;
+ }
+ language_specific;
};
/* Persistent data held for a compilation unit, even when not
@@ -788,6 +806,9 @@ static void scan_partial_symbols (struct partial_die_info *,
static void add_partial_symbol (struct partial_die_info *,
struct dwarf2_cu *);
+static gdb_byte *read_comp_unit_head (struct comp_unit_head *, gdb_byte *,
+ bfd *);
+
static int pdi_needs_namespace (enum dwarf_tag tag);
static void add_partial_namespace (struct partial_die_info *pdi,
@@ -813,6 +834,10 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *);
static void psymtab_to_symtab_1 (struct partial_symtab *);
+static void dwarf2_read_section_1 (struct objfile *objfile,
+ struct obstack *obstack,
+ struct dwarf2_section_info *info);
+
static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu);
static void dwarf2_free_abbrev_table (void *);
@@ -995,6 +1020,15 @@ static void read_module (struct die_info *die, struct dwarf2_cu *cu);
static void read_import_statement (struct die_info *die, struct dwarf2_cu *);
+static struct type *read_module_type (struct die_info *die,
+ struct dwarf2_cu *cu);
+
+static void read_fortran_imported_module (struct die_info *die,
+ struct dwarf2_cu *cu);
+
+static void read_fortran_imported_declaration (struct die_info *die,
+ struct dwarf2_cu *cu);
+
static const char *namespace_name (struct die_info *die,
int *is_anonymous, struct dwarf2_cu *);
@@ -1030,6 +1064,9 @@ static void process_die (struct die_info *, struct dwarf2_cu *);
static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *);
+static char *fortran_module_linkage_name (struct die_info *die,
+ struct dwarf2_cu *cu);
+
static char *dwarf2_canonicalize_name (char *, struct dwarf2_cu *,
struct obstack *);
@@ -1144,6 +1181,9 @@ static void age_cached_comp_units (void);
static void free_one_cached_comp_unit (void *);
+static void fetch_die_type_attrs (struct die_info *die, struct type *type,
+ struct dwarf2_cu *cu);
+
static struct type *set_die_type (struct die_info *, struct type *,
struct dwarf2_cu *);
@@ -1163,22 +1203,31 @@ static void dwarf2_clear_marks (struct dwarf2_per_cu_data *);
static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu);
+static void destroy_section (struct dwarf2_section_info *info);
+
+static struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton
+ (struct attribute *attr, struct dwarf2_cu *cu);
+
/* Try to locate the sections we need for DWARF 2 debugging
information and return true if we have enough to do something. */
int
dwarf2_has_info (struct objfile *objfile)
{
- struct dwarf2_per_objfile *data;
-
- /* Initialize per-objfile state. */
- data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data));
- memset (data, 0, sizeof (*data));
- set_objfile_data (objfile, dwarf2_objfile_data_key, data);
- dwarf2_per_objfile = data;
+ dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key);
+ if (!dwarf2_per_objfile)
+ {
+ /* Initialize per-objfile state. */
+ struct dwarf2_per_objfile *data
+ = obstack_alloc (&objfile->objfile_obstack, sizeof (*data));
+ memset (data, 0, sizeof (*data));
+ set_objfile_data (objfile, dwarf2_objfile_data_key, data);
+ dwarf2_per_objfile = data;
- bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL);
- return (data->info.asection != NULL && data->abbrev.asection != NULL);
+ bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL);
+ }
+ return (dwarf2_per_objfile->info.asection != NULL
+ && dwarf2_per_objfile->abbrev.asection != NULL);
}
/* When loading sections, we can either look for ".<name>", or for
@@ -1271,10 +1320,13 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr)
}
/* Decompress a section that was compressed using zlib. Store the
- decompressed buffer, and its size, in OUTBUF and OUTSIZE. */
+ decompressed buffer, and its size, in OUTBUF and OUTSIZE. The
+ result is allocated on OBSTACK; if OBSTACK is NULL, xmalloc is
+ used. */
static void
-zlib_decompress_section (struct objfile *objfile, asection *sectp,
+zlib_decompress_section (struct objfile *objfile, struct obstack *obstack,
+ asection *sectp,
gdb_byte **outbuf, bfd_size_type *outsize)
{
bfd *abfd = objfile->obfd;
@@ -1291,6 +1343,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
z_stream strm;
int rc;
int header_size = 12;
+ struct cleanup *old = NULL;
if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
|| bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size)
@@ -1320,8 +1373,13 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
strm.avail_in = compressed_size - header_size;
strm.next_in = (Bytef*) compressed_buffer + header_size;
strm.avail_out = uncompressed_size;
- uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack,
- uncompressed_size);
+ if (obstack)
+ uncompressed_buffer = obstack_alloc (obstack, uncompressed_size);
+ else
+ {
+ uncompressed_buffer = xmalloc (uncompressed_size);
+ old = make_cleanup (xfree, uncompressed_buffer);
+ }
rc = inflateInit (&strm);
while (strm.avail_in > 0)
{
@@ -1342,26 +1400,176 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"),
bfd_get_filename (abfd), rc);
+ if (old)
+ discard_cleanups (old);
do_cleanups (cleanup);
*outbuf = uncompressed_buffer;
*outsize = uncompressed_size;
#endif
}
-/* Read the contents of the section SECTP from object file specified by
- OBJFILE, store info about the section into INFO.
- If the section is compressed, uncompress it before returning. */
+/* A cleanup that calls destroy_section. */
static void
-dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
+destroy_section_cleanup (void *arg)
+{
+ destroy_section (arg);
+}
+
+/* Read the .debug_aranges section and construct an address map. */
+
+void
+dwarf2_create_quick_addrmap (struct objfile *objfile)
+{
+ char *aranges_buffer, *aranges_ptr;
+ bfd *abfd = objfile->obfd;
+ CORE_ADDR baseaddr;
+ struct cleanup *old;
+ struct obstack temp_obstack;
+ struct addrmap *mutable_map;
+
+ if (!dwarf2_per_objfile->aranges.asection)
+ return;
+
+ baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+ dwarf2_read_section_1 (objfile, NULL, &dwarf2_per_objfile->aranges);
+ aranges_buffer = dwarf2_per_objfile->aranges.buffer;
+ aranges_ptr = aranges_buffer;
+ old = make_cleanup (destroy_section_cleanup, &dwarf2_per_objfile->aranges);
+
+ obstack_init (&temp_obstack);
+ make_cleanup_obstack_free (&temp_obstack);
+ mutable_map = addrmap_create_mutable (&temp_obstack);
+
+ while ((aranges_ptr - aranges_buffer) < dwarf2_per_objfile->aranges.size)
+ {
+ struct comp_unit_head cu_header;
+ unsigned int bytes_read, segment_size, delta;
+ LONGEST info_offset;
+ struct dwarf2_cu cu;
+ char *end_ptr;
+
+ cu_header.initial_length_size = 0;
+ end_ptr = aranges_ptr;
+ aranges_ptr = read_comp_unit_head (&cu_header, aranges_ptr, abfd);
+ end_ptr += cu_header.initial_length_size + cu_header.length;
+
+ /* Sanity check. */
+ if (end_ptr - aranges_ptr >= dwarf2_per_objfile->aranges.size)
+ {
+ do_cleanups (old);
+ complaint (&symfile_complaints,
+ _("aranges entry runs off end of `.debug_aranges' section, ignored"));
+ return;
+ }
+ if (cu_header.addr_size == 0)
+ {
+ do_cleanups (old);
+ complaint (&symfile_complaints,
+ _("aranges entry has zero addr_size, ignored"));
+ return;
+ }
+
+ segment_size = read_1_byte (abfd, aranges_ptr);
+ aranges_ptr += 1;
+
+ /* Align the pointer to twice the pointer size. I didn't see
+ this in the spec but it appears to be required. */
+ delta = (aranges_ptr - aranges_buffer) % (2 * cu_header.addr_size);
+ delta = (2 * cu_header.addr_size - delta) % (2 * cu_header.addr_size);
+ aranges_ptr += delta;
+
+ memset (&cu, 0, sizeof (cu));
+ cu.header.addr_size = cu_header.addr_size;
+
+ while (1)
+ {
+ CORE_ADDR address, length;
+
+ address = read_address (abfd, aranges_ptr, &cu, &bytes_read);
+ aranges_ptr += bytes_read;
+
+ length = read_address (abfd, aranges_ptr, &cu, &bytes_read);
+ aranges_ptr += bytes_read;
+
+ if (address == 0 && length == 0)
+ break;
+
+ if (length == 0)
+ {
+ do_cleanups (old);
+ complaint (&symfile_complaints,
+ _("aranges entry has zero length, ignored"));
+ return;
+ }
+
+ address += baseaddr;
+
+ addrmap_set_empty (mutable_map, address, address + length - 1,
+ objfile);
+ }
+
+ /* Some older versions of GCC incorrectly started the arange
+ with a (0,0) pair. If we encounter any oddity while reading
+ the section, just abandon the attempt; falling back to the
+ slower code is always safe. */
+ if (aranges_ptr != end_ptr)
+ {
+ do_cleanups (old);
+ complaint (&symfile_complaints,
+ _("aranges entry ends early, ignored"));
+ return;
+ }
+ }
+
+ objfile->quick_addrmap = addrmap_create_fixed (mutable_map,
+ &objfile->objfile_obstack);
+ do_cleanups (old);
+}
+
+/* Free a section buffer allocated with xmalloc. */
+
+static void
+xfree_section_buffer (struct dwarf2_section_info *info)
+{
+ xfree (info->buffer);
+}
+
+/* If section described by INFO was mmapped, munmap it now. */
+
+static void
+munmap_section_buffer (struct dwarf2_section_info *info)
+{
+#ifdef HAVE_MMAP
+ intptr_t begin = (intptr_t) info->buffer;
+ intptr_t map_begin = begin & ~(pagesize - 1);
+ size_t map_length = info->size + begin - map_begin;
+ gdb_assert (munmap ((void *) map_begin, map_length) == 0);
+#else
+ /* Without HAVE_MMAP, we should never be here to begin with. */
+ gdb_assert (0);
+#endif
+}
+
+/* Read the contents of the section at OFFSET and of size SIZE from
+ the object file specified by OBJFILE into OBSTACK and store it into
+ INFO. If OBSTACK is NULL, xmalloc is used instead. If the section
+ is compressed, uncompress it before returning. */
+
+static void
+dwarf2_read_section_1 (struct objfile *objfile,
+ struct obstack *obstack,
+ struct dwarf2_section_info *info)
{
bfd *abfd = objfile->obfd;
asection *sectp = info->asection;
gdb_byte *buf, *retbuf;
unsigned char header[4];
+ struct cleanup *old = NULL;
info->buffer = NULL;
- info->was_mmapped = 0;
+ info->destructor = 0;
if (info->asection == NULL || info->size == 0)
return;
@@ -1374,7 +1582,7 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
/* Upon decompression, update the buffer and its size. */
if (strncmp (header, "ZLIB", sizeof (header)) == 0)
{
- zlib_decompress_section (objfile, sectp, &info->buffer,
+ zlib_decompress_section (objfile, obstack, sectp, &info->buffer,
&info->size);
return;
}
@@ -1397,7 +1605,7 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
if (retbuf != MAP_FAILED)
{
- info->was_mmapped = 1;
+ info->destructor = munmap_section_buffer;
info->buffer = retbuf + (sectp->filepos & (pagesize - 1)) ;
return;
}
@@ -1405,8 +1613,15 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
#endif
/* If we get here, we are a normal, not-compressed section. */
- info->buffer = buf
- = obstack_alloc (&objfile->objfile_obstack, info->size);
+ if (obstack)
+ buf = obstack_alloc (obstack, info->size);
+ else
+ {
+ buf = xmalloc (info->size);
+ old = make_cleanup (xfree, buf);
+ info->destructor = xfree_section_buffer;
+ }
+ info->buffer = buf;
/* When debugging .o files, we may need to apply relocations; see
http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html .
@@ -1415,6 +1630,8 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
retbuf = symfile_relocate_debug_section (abfd, sectp, buf);
if (retbuf != NULL)
{
+ if (old)
+ discard_cleanups (old);
info->buffer = retbuf;
return;
}
@@ -1423,6 +1640,19 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
|| bfd_bread (buf, info->size, abfd) != info->size)
error (_("Dwarf Error: Can't read DWARF data from '%s'"),
bfd_get_filename (abfd));
+
+ if (old)
+ discard_cleanups (old);
+}
+
+/* Read the contents of the section SECTP from object file specified by
+ OBJFILE, store info about the section into INFO.
+ If the section is compressed, uncompress it before returning. */
+
+static void
+dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info)
+{
+ dwarf2_read_section_1 (objfile, &objfile->objfile_obstack, info);
}
/* Fill in SECTP, BUFP and SIZEP with section info, given OBJFILE and
@@ -2548,6 +2778,13 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
&objfile->global_psymbols,
0, (CORE_ADDR) 0, cu->language, objfile);
break;
+ case DW_TAG_module:
+ add_psymbol_to_list (actual_name, strlen (actual_name),
+ built_actual_name,
+ MODULE_DOMAIN, LOC_STATIC,
+ &objfile->global_psymbols,
+ 0, (CORE_ADDR) 0, cu->language, objfile);
+ break;
case DW_TAG_class_type:
case DW_TAG_interface_type:
case DW_TAG_structure_type:
@@ -2661,12 +2898,12 @@ static void
add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
CORE_ADDR *highpc, int need_pc, struct dwarf2_cu *cu)
{
- /* Now scan partial symbols in that module.
+ /* Add a symbol for the module. */
- FIXME: Support the separate Fortran module namespaces. */
+ add_partial_symbol (pdi, cu);
- if (pdi->has_children)
- scan_partial_symbols (pdi->die_child, lowpc, highpc, need_pc, cu);
+ /* Partial symbols in that module are not scanned as they are never globally
+ visible. They get imported to the specific scopes on the full read. */
}
/* Read a partial die corresponding to a subprogram and create a partial
@@ -3330,6 +3567,14 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
case DW_TAG_imported_declaration:
case DW_TAG_imported_module:
processing_has_namespace_info = 1;
+ if (cu->language == language_fortran)
+ {
+ if (die->tag == DW_TAG_imported_declaration)
+ read_fortran_imported_declaration (die, cu);
+ else
+ read_fortran_imported_module (die, cu);
+ break;
+ }
if (die->child != NULL && (die->tag == DW_TAG_imported_declaration
|| cu->language != language_fortran))
complaint (&symfile_complaints, _("Tag '%s' has unexpected children"),
@@ -3881,6 +4126,13 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
cu->list_in_scope = &local_symbols;
+ switch (cu->language)
+ {
+ case language_fortran:
+ cu->language_specific.fortran.use = NULL;
+ break;
+ }
+
if (die->child != NULL)
{
child_die = die->child;
@@ -3904,6 +4156,13 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
determine_prefix (die, cu),
processing_has_namespace_info);
+ switch (cu->language)
+ {
+ case language_fortran:
+ BLOCK_FORTRAN_USE (block) = cu->language_specific.fortran.use;
+ break;
+ }
+
/* If we have address ranges, record them. */
dwarf2_record_block_ranges (die, block, baseaddr, cu);
@@ -5385,6 +5644,29 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
new_symbol (die, this_type, cu);
}
+/* Create a new array dimension referencing its target type TYPE.
+
+ Multidimensional arrays are internally represented as a stack of
+ singledimensional arrays being referenced by their TYPE_TARGET_TYPE. */
+
+static struct type *
+create_single_array_dimension (struct type *type, struct type *range_type,
+ struct die_info *die, struct dwarf2_cu *cu)
+{
+ type = create_array_type (NULL, type, range_type);
+
+ /* These generic type attributes need to be fetched by
+ evaluate_subexp_standard <multi_f77_subscript>'s call of
+ value_subscripted_rvalue only for the innermost array type. */
+ fetch_die_type_attrs (die, type, cu);
+
+ /* These generic type attributes are checked for allocated/associated
+ validity while accessing FIELD_LOC_KIND_DWARF_BLOCK. */
+ fetch_die_type_attrs (die, range_type, cu);
+
+ return type;
+}
+
/* Extract all information from a DW_TAG_array_type DIE and put it in
the DIE's type field. For now, this only handles one dimensional
arrays. */
@@ -5398,7 +5680,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
struct type *element_type, *range_type, *index_type;
struct type **range_types = NULL;
struct attribute *attr;
- int ndim = 0;
+ int ndim = 0, i;
struct cleanup *back_to;
char *name;
@@ -5445,16 +5727,11 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu)
type = element_type;
if (read_array_order (die, cu) == DW_ORD_col_major)
- {
- int i = 0;
- while (i < ndim)
- type = create_array_type (NULL, type, range_types[i++]);
- }
- else
- {
- while (ndim-- > 0)
- type = create_array_type (NULL, type, range_types[ndim]);
- }
+ for (i = 0; i < ndim; i++)
+ type = create_single_array_dimension (type, range_types[i], die, cu);
+ else /* (read_array_order (die, cu) == DW_ORD_row_major) */
+ for (i = ndim - 1; i >= 0; i--)
+ type = create_single_array_dimension (type, range_types[i], die, cu);
/* Understand Dwarf2 support for vector types (like they occur on
the PowerPC w/ AltiVec). Gcc just adds another attribute to the
@@ -5659,20 +5936,155 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu)
}
}
-/* Read a Fortran module. */
+/* Read a Fortran module as global symbol which can be later looked up by
+ f_lookup_symbol_nonlocal. */
static void
read_module (struct die_info *die, struct dwarf2_cu *cu)
{
- struct die_info *child_die = die->child;
+ struct type *type;
- /* FIXME: Support the separate Fortran module namespaces. */
+ type = read_module_type (die, cu);
+
+ if (type)
+ new_symbol (die, type, cu);
+}
+/* Read a Fortran module as type.
+
+ Modules present only as declarations - being used only for DW_AT_import of
+ DW_TAG_imported_module - are ignored here. They are read in only in form of
+ the module name by read_fortran_imported_module. */
+
+static struct type *
+read_module_type (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct die_info *child_die;
+ struct type *type;
+ char *module_name;
+ struct context_stack *new;
+ struct pending *save_file_symbols;
+ struct pending *save_global_symbols;
+ struct pending **save_list_in_scope;
+
+ if (die_is_declaration (die, cu))
+ return NULL;
+
+ module_name = dwarf2_name (die, cu);
+ if (!module_name)
+ complaint (&symfile_complaints, _("DW_TAG_module has no name, offset 0x%x"),
+ die->offset);
+ type = init_type (TYPE_CODE_MODULE, 0, 0, module_name, objfile);
+
+ /* Create a context for reading the module variables. */
+
+ new = push_context (0, 0);
+
+ save_file_symbols = file_symbols;
+ file_symbols = NULL;
+ save_global_symbols = global_symbols;
+ global_symbols = NULL;
+ save_list_in_scope = cu->list_in_scope;
+
+ /* Process the child DIEs. */
+
+ child_die = die->child;
while (child_die && child_die->tag)
{
+ /* Any DW_TAG_subprogram will reset LIST_IN_SCOPE to LOCAL_SYMBOLS. */
+ cu->list_in_scope = &global_symbols;
+
process_die (child_die, cu);
child_die = sibling_die (child_die);
}
+
+ /* Finish this module and restore the context. */
+
+ TYPE_MODULE_BLOCK (type) = finish_block (NULL, &global_symbols,
+ new->old_blocks, 0, 0, objfile);
+
+ if (file_symbols)
+ complaint (&symfile_complaints, _("DW_TAG_module contains static symbols"));
+ if (local_symbols)
+ complaint (&symfile_complaints, _("DW_TAG_module contains local symbols"));
+ if (param_symbols)
+ complaint (&symfile_complaints, _("DW_TAG_module contains function "
+ "parameters"));
+
+ file_symbols = save_file_symbols;
+ global_symbols = save_global_symbols;
+ cu->list_in_scope = save_list_in_scope;
+
+ pop_context ();
+
+ set_die_type (die, type, cu);
+
+ return type;
+}
+
+/* Import a Fortran module. Only store the module name for its later lookup by
+ f_lookup_symbol_nonlocal. */
+
+static void
+read_fortran_imported_module (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct attribute *attr;
+ struct die_info *module_die;
+ char *module_name;
+ struct fortran_using *use;
+
+ attr = dwarf2_attr (die, DW_AT_import, cu);
+ if (attr == NULL)
+ return;
+
+ module_die = follow_die_ref (die, attr, &cu);
+ module_name = dwarf2_name (module_die, cu);
+ if (module_name == NULL)
+ {
+ complaint (&symfile_complaints,
+ _("Imported DIE at offset 0x%x has no name"), die->offset);
+ return;
+ }
+
+ /* Fortran does not allow any duplicity between local and any of the imported
+ symbols. Therefore the order of the USE statements is not portant.
+ gfortran prints:
+ Error: Name 'X' at (1) is an ambiguous reference to 'X' from module 'Y' */
+
+ use = obstack_alloc (&objfile->objfile_obstack, sizeof (*use)
+ + strlen (module_name));
+ strcpy (use->module_name, module_name);
+ gdb_assert (cu->language == language_fortran);
+ use->next = cu->language_specific.fortran.use;
+ cu->language_specific.fortran.use = use;
+}
+
+/* Import a single Fortran declaration and possibly rename it. */
+
+static void
+read_fortran_imported_declaration (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+ struct die_info *imported_die;
+ struct symbol *sym;
+ char *rename = dwarf2_name (die, cu);
+
+ attr = dwarf2_attr (die, DW_AT_import, cu);
+ if (attr == NULL)
+ {
+ complaint (&symfile_complaints,
+ _("Fortran DW_TAG_imported_declaration is missing "
+ "DW_AT_import at offset 0x%x"), die->offset);
+ return;
+ }
+ imported_die = follow_die_ref (die, attr, &cu);
+
+ sym = new_symbol (imported_die, NULL, cu);
+
+ if (sym && rename)
+ SYMBOL_CPLUS_DEMANGLED_NAME (sym) = rename;
}
/* Return the name of the namespace represented by DIE. Set
@@ -5837,29 +6249,113 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu)
struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct type *type, *range_type, *index_type, *char_type;
struct attribute *attr;
- unsigned int length;
+ int length;
+
+ index_type = objfile_type (objfile)->builtin_int;
+ /* RANGE_TYPE is allocated from OBJFILE, not as a permanent type. */
+ range_type = alloc_type (objfile);
+ /* LOW_BOUND and HIGH_BOUND are set for real below. */
+ range_type = create_range_type (range_type, index_type, 0, -1);
+
+ /* C/C++ should probably have the low bound 0 but C/C++ does not use
+ DW_TAG_string_type. */
+ TYPE_LOW_BOUND (range_type) = 1;
attr = dwarf2_attr (die, DW_AT_string_length, cu);
- if (attr)
- {
- length = DW_UNSND (attr);
+ if (attr && attr_form_is_block (attr))
+ {
+ /* Security check for a size overflow. */
+ if (DW_BLOCK (attr)->size + 2 < DW_BLOCK (attr)->size)
+ TYPE_HIGH_BOUND (range_type) = 1;
+ /* Extend the DWARF block by a new DW_OP_deref/DW_OP_deref_size
+ instruction as DW_AT_string_length specifies the length location, not
+ its value. */
+ else
+ {
+ struct dwarf2_locexpr_baton *length_baton = NULL;
+ struct dwarf_block *blk = DW_BLOCK (attr);
+
+ /* Turn any single DW_OP_reg* into DW_OP_breg*(0) but clearing
+ DW_OP_deref* in such case. */
+
+ if (blk->size == 1 && blk->data[0] >= DW_OP_reg0
+ && blk->data[0] <= DW_OP_reg31)
+ length_baton = dwarf2_attr_to_locexpr_baton (attr, cu);
+ else if (blk->size > 1 && blk->data[0] == DW_OP_regx)
+ {
+ ULONGEST ulongest;
+ gdb_byte *end;
+
+ end = read_uleb128 (&blk->data[1], &blk->data[blk->size],
+ &ulongest);
+ if (end == &blk->data[blk->size])
+ length_baton = dwarf2_attr_to_locexpr_baton (attr, cu);
+ }
+
+ if (length_baton == NULL)
+ {
+ struct attribute *size_attr;
+
+ length_baton = obstack_alloc (&cu->comp_unit_obstack,
+ sizeof (*length_baton));
+ length_baton->per_cu = cu->per_cu;
+ length_baton->size = DW_BLOCK (attr)->size + 2;
+ length_baton->data = obstack_alloc (&cu->comp_unit_obstack,
+ length_baton->size);
+ memcpy (length_baton->data, DW_BLOCK (attr)->data,
+ DW_BLOCK (attr)->size);
+
+ /* DW_AT_BYTE_SIZE existing together with DW_AT_STRING_LENGTH
+ specifies the size of an integer to fetch. */
+ size_attr = dwarf2_attr (die, DW_AT_byte_size, cu);
+ if (size_attr)
+ {
+ length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref_size;
+ length_baton->data[DW_BLOCK (attr)->size + 1] =
+ DW_UNSND (size_attr);
+ if (length_baton->data[DW_BLOCK (attr)->size + 1]
+ != DW_UNSND (size_attr))
+ complaint (&symfile_complaints,
+ _("DW_AT_string_length's DW_AT_byte_size "
+ "integer exceeds the byte size storage"));
+ }
+ else
+ {
+ length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref;
+ length_baton->data[DW_BLOCK (attr)->size + 1] = DW_OP_nop;
+ }
+ }
+
+ TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = length_baton;
+ TYPE_DYNAMIC (range_type) = 1;
+ }
}
else
{
- /* check for the DW_AT_byte_size attribute */
+ if (attr && attr_form_is_constant (attr))
+ {
+ /* We currently do not support a constant address where the location
+ should be read from - attr_form_is_block is expected instead. See
+ DWARF for the DW_AT_STRING_LENGTH vs. DW_AT_BYTE_SIZE difference.
+ */
+ /* PASSTHRU */
+ }
+
attr = dwarf2_attr (die, DW_AT_byte_size, cu);
- if (attr)
- {
- length = DW_UNSND (attr);
- }
+ if (attr && attr_form_is_block (attr))
+ {
+ TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && attr_form_is_constant (attr))
+ TYPE_HIGH_BOUND (range_type) = dwarf2_get_attr_constant_value (attr, 0);
else
- {
- length = 1;
- }
+ TYPE_HIGH_BOUND (range_type) = 1;
}
- index_type = objfile_type (objfile)->builtin_int;
- range_type = create_range_type (NULL, index_type, 1, length);
char_type = language_string_char_type (cu->language_defn, gdbarch);
type = create_string_type (NULL, char_type, range_type);
@@ -5959,7 +6455,6 @@ static struct type *
read_typedef (struct die_info *die, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->objfile;
- struct attribute *attr;
const char *name = NULL;
struct type *this_type;
@@ -6067,8 +6562,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
struct type *base_type;
struct type *range_type;
struct attribute *attr;
- LONGEST low = 0;
- LONGEST high = -1;
+ LONGEST low;
char *name;
LONGEST negative_mask;
@@ -6082,49 +6576,101 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu)
0, NULL, cu->objfile);
}
- if (cu->language == language_fortran)
- {
- /* FORTRAN implies a lower bound of 1, if not given. */
- low = 1;
- }
+ /* LOW_BOUND and HIGH_BOUND are set for real below. */
+ range_type = create_range_type (NULL, base_type, 0, -1);
+
+ negative_mask =
+ (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1);
- /* FIXME: For variable sized arrays either of these could be
- a variable rather than a constant value. We'll allow it,
- but we don't know how to handle it. */
attr = dwarf2_attr (die, DW_AT_lower_bound, cu);
- if (attr)
- low = dwarf2_get_attr_constant_value (attr, 0);
+ if (attr && attr_form_is_block (attr))
+ {
+ TYPE_LOW_BOUND_IS_DWARF_BLOCK (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->low.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ /* For setting a default if DW_AT_UPPER_BOUND would be missing. */
+ low = 0;
+ }
+ else
+ {
+ if (attr && attr_form_is_constant (attr))
+ low = dwarf2_get_attr_constant_value (attr, 0);
+ else
+ {
+ if (cu->language == language_fortran)
+ {
+ /* FORTRAN implies a lower bound of 1, if not given. */
+ low = 1;
+ }
+ else
+ {
+ /* According to DWARF we should assume the value 0 only for
+ LANGUAGE_C and LANGUAGE_CPLUS. */
+ low = 0;
+ }
+ }
+ if (!TYPE_UNSIGNED (base_type) && (low & negative_mask))
+ low |= negative_mask;
+ TYPE_LOW_BOUND (range_type) = low;
+ if (low >= 0)
+ TYPE_UNSIGNED (range_type) = 1;
+ }
attr = dwarf2_attr (die, DW_AT_upper_bound, cu);
- if (attr)
- {
- if (attr->form == DW_FORM_block1)
- {
- /* GCC encodes arrays with unspecified or dynamic length
- with a DW_FORM_block1 attribute.
- FIXME: GDB does not yet know how to handle dynamic
- arrays properly, treat them as arrays with unspecified
- length for now.
-
- FIXME: jimb/2003-09-22: GDB does not really know
- how to handle arrays of unspecified length
- either; we just represent them as zero-length
- arrays. Choose an appropriate upper bound given
- the lower bound we've computed above. */
- high = low - 1;
- }
- else
- high = dwarf2_get_attr_constant_value (attr, 1);
+ if (!attr || (!attr_form_is_block (attr) && !attr_form_is_constant (attr)))
+ {
+ attr = dwarf2_attr (die, DW_AT_count, cu);
+ /* It does not hurt but it is needlessly ineffective in check_typedef. */
+ if (attr && (attr_form_is_block (attr) || attr_form_is_constant (attr)))
+ {
+ TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1;
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ /* Pass it now as the regular DW_AT_upper_bound. */
}
- negative_mask =
- (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1);
- if (!TYPE_UNSIGNED (base_type) && (low & negative_mask))
- low |= negative_mask;
- if (!TYPE_UNSIGNED (base_type) && (high & negative_mask))
- high |= negative_mask;
+ if (attr && attr_form_is_block (attr))
+ {
+ TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->high.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else
+ {
+ if (attr && attr_form_is_constant (attr))
+ {
+ LONGEST high;
- range_type = create_range_type (NULL, base_type, low, high);
+ high = dwarf2_get_attr_constant_value (attr, 0);
+ if (!TYPE_UNSIGNED (base_type) && (high & negative_mask))
+ high |= negative_mask;
+ TYPE_HIGH_BOUND (range_type) = high;
+ }
+ else
+ {
+ TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1;
+ TYPE_HIGH_BOUND (range_type) = low - 1;
+ }
+ }
+
+ /* DW_AT_bit_stride is currently unsupported as we count in bytes. */
+ attr = dwarf2_attr (die, DW_AT_byte_stride, cu);
+ if (attr && attr_form_is_block (attr))
+ {
+ TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (range_type) = 1;
+ TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_block =
+ dwarf2_attr_to_locexpr_baton (attr, cu);
+ TYPE_DYNAMIC (range_type) = 1;
+ }
+ else if (attr && attr_form_is_constant (attr))
+ {
+ TYPE_BYTE_STRIDE (range_type) = dwarf2_get_attr_constant_value (attr, 0);
+ if (TYPE_BYTE_STRIDE (range_type) == 0)
+ complaint (&symfile_complaints,
+ _("Found DW_AT_byte_stride with unsupported value 0"));
+ }
name = dwarf2_name (die, cu);
if (name)
@@ -6583,6 +7129,7 @@ load_partial_dies (bfd *abfd, gdb_byte *buffer, gdb_byte *info_ptr,
&& abbrev->tag != DW_TAG_lexical_block
&& abbrev->tag != DW_TAG_variable
&& abbrev->tag != DW_TAG_namespace
+ && abbrev->tag != DW_TAG_module
&& abbrev->tag != DW_TAG_member)
{
/* Otherwise we skip to the next sibling, if any. */
@@ -8331,10 +8878,12 @@ var_decode_location (struct attribute *attr, struct symbol *sym,
(i.e. when the value of a register or memory location is
referenced, or a thread-local block, etc.). Then again, it might
not be worthwhile. I'm assuming that it isn't unless performance
- or memory numbers show me otherwise. */
+ or memory numbers show me otherwise.
+
+ SYMBOL_CLASS may get overriden by dwarf2_symbol_mark_computed. */
- dwarf2_symbol_mark_computed (attr, sym, cu);
SYMBOL_CLASS (sym) = LOC_COMPUTED;
+ dwarf2_symbol_mark_computed (attr, sym, cu);
}
/* Given a pointer to a DWARF information entry, figure out if we need
@@ -8367,10 +8916,17 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
sizeof (struct symbol));
OBJSTAT (objfile, n_syms++);
memset (sym, 0, sizeof (struct symbol));
+ /* Some methods are called w/o checking SYMBOL_COMPUTED_OPS validity. */
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_missing_funcs;
/* Cache this symbol's name and the name's demangled form (if any). */
SYMBOL_LANGUAGE (sym) = cu->language;
SYMBOL_SET_NAMES (sym, name, strlen (name), 0, objfile);
+ if (cu->language == language_fortran)
+ {
+ SYMBOL_CPLUS_DEMANGLED_NAME (sym) = SYMBOL_LINKAGE_NAME (sym);
+ SYMBOL_LINKAGE_NAME (sym) = fortran_module_linkage_name (die, cu);
+ }
/* Default assumptions.
Use the passed type or decode it from the die. */
@@ -8470,7 +9026,18 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
var_decode_location (attr, sym, cu);
attr2 = dwarf2_attr (die, DW_AT_external, cu);
if (attr2 && (DW_UNSND (attr2) != 0))
- add_symbol_to_list (sym, &global_symbols);
+ {
+ /* Workaround gfortran PR debug/40040 - it uses
+ DW_AT_location for variables in -fPIC libraries which may
+ get overriden by other libraries/executable and get
+ a different address. Resolve it by .dynsym instead. */
+
+ if (cu->language == language_fortran && die->parent
+ && die->parent->tag == DW_TAG_module)
+ SYMBOL_CLASS (sym) = LOC_UNRESOLVED;
+
+ add_symbol_to_list (sym, &global_symbols);
+ }
else
add_symbol_to_list (sym, cu->list_in_scope);
}
@@ -8631,6 +9198,11 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
add_symbol_to_list (sym, &global_symbols);
break;
+ case DW_TAG_module:
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_DOMAIN (sym) = MODULE_DOMAIN;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
default:
/* Not a tag we recognize. Hopefully we aren't processing
trash data, but since we must specifically ignore things
@@ -8957,12 +9529,18 @@ read_type_die (struct die_info *die, struct dwarf2_cu *cu)
case DW_TAG_namespace:
this_type = read_namespace_type (die, cu);
break;
+ case DW_TAG_module:
+ this_type = read_module_type (die, cu);
+ break;
default:
complaint (&symfile_complaints, _("unexpected tag in read_type_die: '%s'"),
dwarf_tag_name (die->tag));
break;
}
+ if (this_type)
+ finalize_type (this_type);
+
return this_type;
}
@@ -9110,6 +9688,39 @@ dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu)
return dwarf2_name (die, cu);
}
+/* Return the fully qualified .symtab name for symbols contained in Fortran
+ modules. Return DWARF2_NAME otherwise. */
+
+static char *
+fortran_module_linkage_name (struct die_info *die, struct dwarf2_cu *cu)
+{
+ char *name;
+
+ gdb_assert (cu->language == language_fortran);
+
+ name = dwarf2_name (die, cu);
+
+ if (name && die->parent && die->parent->tag == DW_TAG_module)
+ {
+ char *module_name = dwarf2_name (die->parent, cu);
+
+ if (module_name)
+ {
+ char *retval;
+
+ /* `__modulename_MOD_variablename0'. */
+ retval = obstack_alloc (&cu->objfile->objfile_obstack,
+ 2 + strlen (module_name) + 5 + strlen (name)
+ + 1);
+ sprintf (retval, "__%s_MOD_%s", module_name, name);
+
+ return retval;
+ }
+ }
+
+ return name;
+}
+
/* Get name of a die, return NULL if not found. */
static char *
@@ -11455,6 +12066,34 @@ attr_form_is_constant (struct attribute *attr)
}
}
+/* Convert DW_BLOCK into struct dwarf2_locexpr_baton. ATTR must be a DW_BLOCK
+ attribute type. */
+
+static struct dwarf2_locexpr_baton *
+dwarf2_attr_to_locexpr_baton (struct attribute *attr, struct dwarf2_cu *cu)
+{
+ struct dwarf2_locexpr_baton *baton;
+
+ gdb_assert (attr_form_is_block (attr));
+
+ baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (*baton));
+ baton->per_cu = cu->per_cu;
+ gdb_assert (baton->per_cu);
+
+ /* Note that we're just copying the block's data pointer
+ here, not the actual data. We're still pointing into the
+ info_buffer for SYM's objfile; right now we never release
+ that buffer, but when we do clean up properly this may
+ need to change. */
+ baton->size = DW_BLOCK (attr)->size;
+ baton->data = DW_BLOCK (attr)->data;
+ gdb_assert (baton->size == 0 || baton->data != NULL);
+
+ return baton;
+}
+
+/* SYM may get its SYMBOL_CLASS overriden on invalid ATTR content. */
+
static void
dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
struct dwarf2_cu *cu)
@@ -11484,35 +12123,25 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
SYMBOL_COMPUTED_OPS (sym) = &dwarf2_loclist_funcs;
SYMBOL_LOCATION_BATON (sym) = baton;
}
+ else if (attr_form_is_block (attr))
+ {
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
+ SYMBOL_LOCATION_BATON (sym) = dwarf2_attr_to_locexpr_baton (attr, cu);
+ }
else
{
- struct dwarf2_locexpr_baton *baton;
+ dwarf2_invalid_attrib_class_complaint ("location description",
+ SYMBOL_NATURAL_NAME (sym));
- baton = obstack_alloc (&cu->objfile->objfile_obstack,
- sizeof (struct dwarf2_locexpr_baton));
- baton->per_cu = cu->per_cu;
- gdb_assert (baton->per_cu);
+ /* Some methods are called w/o checking SYMBOL_COMPUTED_OPS validity. */
- if (attr_form_is_block (attr))
- {
- /* Note that we're just copying the block's data pointer
- here, not the actual data. We're still pointing into the
- info_buffer for SYM's objfile; right now we never release
- that buffer, but when we do clean up properly this may
- need to change. */
- baton->size = DW_BLOCK (attr)->size;
- baton->data = DW_BLOCK (attr)->data;
- }
- else
- {
- dwarf2_invalid_attrib_class_complaint ("location description",
- SYMBOL_NATURAL_NAME (sym));
- baton->size = 0;
- baton->data = NULL;
- }
-
- SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs;
- SYMBOL_LOCATION_BATON (sym) = baton;
+ SYMBOL_COMPUTED_OPS (sym) = &dwarf2_missing_funcs;
+ SYMBOL_LOCATION_BATON (sym) = NULL;
+
+ /* For functions a missing DW_AT_frame_base does not optimize out the
+ whole function definition, only its frame base resolving. */
+ if (attr->name == DW_AT_location)
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
}
}
@@ -11800,6 +12429,31 @@ offset_and_type_eq (const void *item_lhs, const void *item_rhs)
return ofs_lhs->offset == ofs_rhs->offset;
}
+/* Fill in generic attributes applicable for type DIEs. */
+
+static void
+fetch_die_type_attrs (struct die_info *die, struct type *type,
+ struct dwarf2_cu *cu)
+{
+ struct attribute *attr;
+
+ attr = dwarf2_attr (die, DW_AT_data_location, cu);
+ if (attr_form_is_block (attr))
+ TYPE_DATA_LOCATION_DWARF_BLOCK (type) = dwarf2_attr_to_locexpr_baton (attr,
+ cu);
+ gdb_assert (!TYPE_DATA_LOCATION_IS_ADDR (type));
+
+ attr = dwarf2_attr (die, DW_AT_allocated, cu);
+ if (attr_form_is_block (attr))
+ TYPE_ALLOCATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu);
+ gdb_assert (!TYPE_NOT_ALLOCATED (type));
+
+ attr = dwarf2_attr (die, DW_AT_associated, cu);
+ if (attr_form_is_block (attr))
+ TYPE_ASSOCIATED (type) = dwarf2_attr_to_locexpr_baton (attr, cu);
+ gdb_assert (!TYPE_NOT_ASSOCIATED (type));
+}
+
/* Set the type associated with DIE to TYPE. Save it in CU's hash
table if necessary. For convenience, return TYPE. */
@@ -11808,6 +12462,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu)
{
struct dwarf2_offset_and_type **slot, ofs;
+ fetch_die_type_attrs (die, type, cu);
+
/* For Ada types, make sure that the gnat-specific data is always
initialized (if not already set). There are a few types where
we should not be doing so, because the type-specific area is
@@ -11963,23 +12619,13 @@ show_dwarf2_cmd (char *args, int from_tty)
cmd_show_list (show_dwarf2_cmdlist, from_tty, "");
}
-/* If section described by INFO was mmapped, munmap it now. */
+/* A helper function to destroy a debug section. */
static void
-munmap_section_buffer (struct dwarf2_section_info *info)
+destroy_section (struct dwarf2_section_info *info)
{
- if (info->was_mmapped)
- {
-#ifdef HAVE_MMAP
- intptr_t begin = (intptr_t) info->buffer;
- intptr_t map_begin = begin & ~(pagesize - 1);
- size_t map_length = info->size + begin - map_begin;
- gdb_assert (munmap ((void *) map_begin, map_length) == 0);
-#else
- /* Without HAVE_MMAP, we should never be here to begin with. */
- gdb_assert (0);
-#endif
- }
+ if (info->destructor)
+ (*info->destructor) (info);
}
/* munmap debug sections for OBJFILE, if necessary. */
@@ -11988,15 +12634,15 @@ static void
dwarf2_per_objfile_free (struct objfile *objfile, void *d)
{
struct dwarf2_per_objfile *data = d;
- munmap_section_buffer (&data->info);
- munmap_section_buffer (&data->abbrev);
- munmap_section_buffer (&data->line);
- munmap_section_buffer (&data->str);
- munmap_section_buffer (&data->macinfo);
- munmap_section_buffer (&data->ranges);
- munmap_section_buffer (&data->loc);
- munmap_section_buffer (&data->frame);
- munmap_section_buffer (&data->eh_frame);
+ destroy_section (&data->info);
+ destroy_section (&data->abbrev);
+ destroy_section (&data->line);
+ destroy_section (&data->str);
+ destroy_section (&data->macinfo);
+ destroy_section (&data->ranges);
+ destroy_section (&data->loc);
+ destroy_section (&data->frame);
+ destroy_section (&data->eh_frame);
}
void _initialize_dwarf2_read (void);
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 78e9163..4e208d1 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -879,20 +879,13 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags)
str_sect->filepos,
bfd_section_size (abfd, str_sect));
}
- if (dwarf2_has_info (objfile))
- {
- /* DWARF 2 sections */
- dwarf2_build_psymtabs (objfile);
- }
-
- /* FIXME: kettenis/20030504: This still needs to be integrated with
- dwarf2read.c in a better way. */
- dwarf2_build_frame_info (objfile);
+ if (dwarf2_has_info (objfile))
+ dwarf2_create_quick_addrmap (objfile);
/* If the file has its own symbol tables it has no separate debug info.
`.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS.
`.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */
- if (!objfile_has_partial_symbols (objfile))
+ else
{
char *debugfile;
@@ -910,6 +903,20 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags)
}
}
+static void
+read_psyms (struct objfile *objfile)
+{
+ if (dwarf2_has_info (objfile))
+ {
+ /* DWARF 2 sections */
+ dwarf2_build_psymtabs (objfile);
+ }
+
+ /* FIXME: kettenis/20030504: This still needs to be integrated with
+ dwarf2read.c in a better way. */
+ dwarf2_build_frame_info (objfile);
+}
+
/* This cleans up the objfile's deprecated_sym_stab_info pointer, and
the chain of stab_section_info's, that might be dangling from
it. */
@@ -1052,6 +1059,7 @@ static struct sym_fns elf_sym_fns =
elf_new_init, /* sym_new_init: init anything gbl to entire symtab */
elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */
elf_symfile_read, /* sym_read: read a symbol file into symtab */
+ read_psyms, /* sym_read_psymbols */
elf_symfile_finish, /* sym_finish: finished with file, cleanup */
default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
elf_symfile_segments, /* sym_segments: Get segment information from
diff --git a/gdb/eval.c b/gdb/eval.c
index 3dbbc8b..4deb82d 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -39,10 +39,12 @@
#include "exceptions.h"
#include "regcache.h"
#include "user-regs.h"
+#include "python/python.h"
#include "valprint.h"
#include "gdb_obstack.h"
#include "objfiles.h"
#include "python/python.h"
+#include "dwarf2loc.h"
#include "gdb_assert.h"
@@ -696,6 +698,7 @@ evaluate_subexp_standard (struct type *expect_type,
long mem_offset;
struct type **arg_types;
int save_pos1;
+ struct cleanup *old_chain;
pc = (*pos)++;
op = exp->elts[pc].opcode;
@@ -1588,6 +1591,8 @@ evaluate_subexp_standard (struct type *expect_type,
/* First determine the type code we are dealing with. */
arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (arg1));
type = check_typedef (value_type (arg1));
code = TYPE_CODE (type);
@@ -1608,6 +1613,7 @@ evaluate_subexp_standard (struct type *expect_type,
code = TYPE_CODE (type);
}
}
+ do_cleanups (old_chain);
switch (code)
{
@@ -2040,13 +2046,19 @@ evaluate_subexp_standard (struct type *expect_type,
{
int subscript_array[MAX_FORTRAN_DIMS];
int array_size_array[MAX_FORTRAN_DIMS];
+ int byte_stride_array[MAX_FORTRAN_DIMS];
int ndimensions = 1, i;
struct type *tmp_type;
int offset_item; /* The array offset where the item lives */
+ CORE_ADDR offset_byte; /* byte_stride based offset */
+ unsigned element_size;
if (nargs > MAX_FORTRAN_DIMS)
error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS);
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (arg1));
+
tmp_type = check_typedef (value_type (arg1));
ndimensions = calc_f77_array_dims (type);
@@ -2076,6 +2088,9 @@ evaluate_subexp_standard (struct type *expect_type,
upper = f77_get_upperbound (tmp_type);
lower = f77_get_lowerbound (tmp_type);
+ byte_stride_array[nargs - i - 1] =
+ TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type);
+
array_size_array[nargs - i - 1] = upper - lower + 1;
/* Zero-normalize subscripts so that offsetting will work. */
@@ -2094,13 +2109,25 @@ evaluate_subexp_standard (struct type *expect_type,
tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type));
}
+ /* Kept for the f77_get_upperbound / f77_get_lowerbound calls above. */
+ do_cleanups (old_chain);
+
/* Now let us calculate the offset for this item */
- offset_item = subscript_array[ndimensions - 1];
+ offset_item = 0;
+ offset_byte = 0;
+
+ for (i = ndimensions - 1; i >= 0; --i)
+ {
+ offset_item *= array_size_array[i];
+ if (byte_stride_array[i] == 0)
+ offset_item += subscript_array[i];
+ else
+ offset_byte += subscript_array[i] * byte_stride_array[i];
+ }
- for (i = ndimensions - 1; i > 0; --i)
- offset_item =
- array_size_array[i - 1] * offset_item + subscript_array[i - 1];
+ element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tmp_type));
+ offset_byte += offset_item * element_size;
/* Let us now play a dirty trick: we will take arg1
which is a value node pointing to the topmost level
@@ -2110,7 +2137,7 @@ evaluate_subexp_standard (struct type *expect_type,
returns the correct type value */
deprecated_set_value_type (arg1, tmp_type);
- return value_subscripted_rvalue (arg1, offset_item, 0);
+ return value_subscripted_rvalue (arg1, offset_byte);
}
case BINOP_LOGICAL_AND:
@@ -2344,14 +2371,22 @@ evaluate_subexp_standard (struct type *expect_type,
if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+ old_chain = make_cleanup (null_cleanup, 0);
+ object_address_set (value_raw_address (arg1));
type = check_typedef (value_type (arg1));
if (TYPE_CODE (type) == TYPE_CODE_METHODPTR
|| TYPE_CODE (type) == TYPE_CODE_MEMBERPTR)
error (_("Attempt to dereference pointer to member without an object"));
if (noside == EVAL_SKIP)
- goto nosideret;
+ {
+ do_cleanups (old_chain);
+ goto nosideret;
+ }
if (unop_user_defined_p (op, arg1))
- return value_x_unop (arg1, op, noside);
+ {
+ do_cleanups (old_chain);
+ return value_x_unop (arg1, op, noside);
+ }
else if (noside == EVAL_AVOID_SIDE_EFFECTS)
{
type = check_typedef (value_type (arg1));
@@ -2360,12 +2395,18 @@ evaluate_subexp_standard (struct type *expect_type,
/* In C you can dereference an array to get the 1st elt. */
|| TYPE_CODE (type) == TYPE_CODE_ARRAY
)
- return value_zero (TYPE_TARGET_TYPE (type),
- lval_memory);
+ {
+ do_cleanups (old_chain);
+ return value_zero (TYPE_TARGET_TYPE (type),
+ lval_memory);
+ }
else if (TYPE_CODE (type) == TYPE_CODE_INT)
- /* GDB allows dereferencing an int. */
- return value_zero (builtin_type (exp->gdbarch)->builtin_int,
- lval_memory);
+ {
+ do_cleanups (old_chain);
+ /* GDB allows dereferencing an int. */
+ return value_zero (builtin_type (exp->gdbarch)->builtin_int,
+ lval_memory);
+ }
else
error (_("Attempt to take contents of a non-pointer value."));
}
@@ -2375,9 +2416,14 @@ evaluate_subexp_standard (struct type *expect_type,
do. "long long" variables are rare enough that
BUILTIN_TYPE_LONGEST would seem to be a mistake. */
if (TYPE_CODE (type) == TYPE_CODE_INT)
- return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
- (CORE_ADDR) value_as_address (arg1));
- return value_ind (arg1);
+ {
+ do_cleanups (old_chain);
+ return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int,
+ (CORE_ADDR) value_as_address (arg1));
+ }
+ arg1 = value_ind (arg1);
+ do_cleanups (old_chain);
+ return arg1;
case UNOP_ADDR:
/* C++: check for and handle pointer to members. */
@@ -2696,7 +2742,7 @@ evaluate_subexp_with_coercion (struct expression *exp,
{
enum exp_opcode op;
int pc;
- struct value *val;
+ struct value *val = NULL;
struct symbol *var;
struct type *type;
@@ -2707,12 +2753,17 @@ evaluate_subexp_with_coercion (struct expression *exp,
{
case OP_VAR_VALUE:
var = exp->elts[pc + 2].symbol;
+ /* address_of_variable will call object_address_set for check_typedef.
+ Call it only if required as it can error-out on VAR in register. */
+ if (TYPE_DYNAMIC (SYMBOL_TYPE (var)))
+ val = address_of_variable (var, exp->elts[pc + 1].block);
type = check_typedef (SYMBOL_TYPE (var));
if (TYPE_CODE (type) == TYPE_CODE_ARRAY
&& CAST_IS_CONVERSION)
{
(*pos) += 4;
- val = address_of_variable (var, exp->elts[pc + 1].block);
+ if (!val)
+ val = address_of_variable (var, exp->elts[pc + 1].block);
return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
val);
}
@@ -2764,9 +2815,13 @@ evaluate_subexp_for_sizeof (struct expression *exp, int *pos)
case OP_VAR_VALUE:
(*pos) += 4;
- type = check_typedef (SYMBOL_TYPE (exp->elts[pc + 2].symbol));
- return
- value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
+ /* We do not need to call read_var_value but the object evaluation may
+ need to have executed object_address_set which needs valid
+ SYMBOL_VALUE_ADDRESS of the symbol. Still VALUE returned by
+ read_var_value we left as lazy. */
+ type = value_type (read_var_value (exp->elts[pc + 2].symbol,
+ deprecated_safe_get_selected_frame ()));
+ return value_from_longest (size_type, (LONGEST) TYPE_LENGTH (type));
default:
val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
diff --git a/gdb/expression.h b/gdb/expression.h
index e4e8598..ca96b9b 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -445,4 +445,5 @@ extern char *op_string (enum exp_opcode);
extern void dump_raw_expression (struct expression *, struct ui_file *, char *);
extern void dump_prefix_expression (struct expression *, struct ui_file *);
+
#endif /* !defined (EXPRESSION_H) */
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index b914b49..79b46d2 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -31,6 +31,8 @@
#include "f-lang.h"
#include "valprint.h"
#include "value.h"
+#include "block.h"
+#include "gdb_assert.h"
/* Following is dubious stuff that had been in the xcoff reader. */
@@ -306,6 +308,48 @@ f_language_arch_info (struct gdbarch *gdbarch,
lai->bool_type_default = builtin->builtin_logical_s2;
}
+/* Find if NAME is not contained in any of the Fortran modules imported by the
+ Fortran USE statement.
+
+ As Fortran has no nested blocks such lookup can be processed from
+ lookup_symbol_nonlocal - when no local blocks could satisfy the lookup. */
+
+static struct symbol *
+f_lookup_symbol_nonlocal (const char *name,
+ const char *linkage_name,
+ const struct block *block,
+ const domain_enum domain)
+{
+ struct fortran_using *use;
+
+ if (!block)
+ return NULL;
+
+ for (use = BLOCK_FORTRAN_USE (block); use; use = use->next)
+ {
+ struct symbol *sym;
+ struct type *type;
+ struct symbol *retval;
+
+ sym = lookup_symbol_global (use->module_name, NULL, block, MODULE_DOMAIN);
+
+ /* Module name lookup should not fail with correct debug info. */
+ if (sym == NULL)
+ continue;
+
+ type = SYMBOL_TYPE (sym);
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_MODULE);
+ gdb_assert (TYPE_MODULE_BLOCK (type) != NULL);
+
+ retval = lookup_block_symbol (TYPE_MODULE_BLOCK (type), name,
+ linkage_name, domain);
+ if (retval)
+ return retval;
+ }
+
+ return NULL;
+}
+
/* This is declared in c-lang.h but it is silly to import that file for what
is already just a hack. */
extern int c_value_print (struct value *, struct ui_file *,
@@ -333,7 +377,7 @@ const struct language_defn f_language_defn =
c_value_print, /* FIXME */
NULL, /* Language specific skip_trampoline */
NULL, /* name_of_this */
- basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
+ f_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
basic_lookup_transparent_type,/* lookup_transparent_type */
NULL, /* Language specific symbol demangler */
NULL, /* Language specific class_name_from_physname */
diff --git a/gdb/f-lang.h b/gdb/f-lang.h
index b98c556..c68379a 100644
--- a/gdb/f-lang.h
+++ b/gdb/f-lang.h
@@ -28,6 +28,10 @@ extern void f_error (char *); /* Defined in f-exp.y */
extern void f_print_type (struct type *, char *, struct ui_file *, int,
int);
+extern const char *f_object_address_data_valid_print_to_stream
+ (struct type *type, struct ui_file *stream);
+extern void f_object_address_data_valid_or_error (struct type *type);
+
extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
struct ui_file *, int,
const struct value_print_options *);
@@ -125,3 +129,10 @@ struct builtin_f_type
/* Return the Fortran type table for the specified architecture. */
extern const struct builtin_f_type *builtin_f_type (struct gdbarch *gdbarch);
+/* List of module names being imported by a block though BLOCK_FORTRAN_USE. */
+
+struct fortran_using
+ {
+ struct fortran_using *next;
+ char module_name[1];
+ };
diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c
index 0332932..6e8668c 100644
--- a/gdb/f-typeprint.c
+++ b/gdb/f-typeprint.c
@@ -32,7 +32,7 @@
#include "gdbcore.h"
#include "target.h"
#include "f-lang.h"
-
+#include "dwarf2loc.h"
#include "gdb_string.h"
#include <errno.h>
@@ -49,6 +49,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *,
void f_type_print_base (struct type *, struct ui_file *, int, int);
+const char *
+f_object_address_data_valid_print_to_stream (struct type *type,
+ struct ui_file *stream)
+{
+ const char *msg;
+
+ msg = object_address_data_not_valid (type);
+ if (msg != NULL)
+ {
+ /* Assuming the content printed to STREAM should not be localized. */
+ fprintf_filtered (stream, "<%s>", msg);
+ }
+
+ return msg;
+}
+
+void
+f_object_address_data_valid_or_error (struct type *type)
+{
+ const char *msg;
+
+ msg = object_address_data_not_valid (type);
+ if (msg != NULL)
+ {
+ error (_("Cannot access it because the %s."), _(msg));
+ }
+}
+
/* LEVEL is the depth to indent lines by. */
void
@@ -58,6 +86,9 @@ f_print_type (struct type *type, char *varstring, struct ui_file *stream,
enum type_code code;
int demangled_args;
+ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL)
+ return;
+
f_type_print_base (type, stream, show, level);
code = TYPE_CODE (type);
if ((varstring != NULL && *varstring != '\0')
@@ -165,6 +196,9 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream,
QUIT;
+ if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF)
+ CHECK_TYPEDEF (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c
index 9bd3640..f52b858 100644
--- a/gdb/f-valprint.c
+++ b/gdb/f-valprint.c
@@ -54,15 +54,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2];
/* The following macro gives us the size of the nth dimension, Where
n is 1 based. */
-#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1])
+#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1])
-/* The following gives us the offset for row n where n is 1-based. */
+/* The following gives us the element size for row n where n is 1-based. */
-#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0])
+#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0])
int
f77_get_lowerbound (struct type *type)
{
+ f_object_address_data_valid_or_error (type);
+
if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type))
error (_("Lower bound may not be '*' in F77"));
@@ -72,14 +74,17 @@ f77_get_lowerbound (struct type *type)
int
f77_get_upperbound (struct type *type)
{
+ f_object_address_data_valid_or_error (type);
+
if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type))
{
- /* We have an assumed size array on our hands. Assume that
- upper_bound == lower_bound so that we show at least 1 element.
- If the user wants to see more elements, let him manually ask for 'em
- and we'll subscript the array and show him. */
+ /* We have an assumed size array on our hands. As type_length_get
+ already assumes a length zero of arrays with underfined bounds VALADDR
+ passed to the Fortran functions does not contained the real inferior
+ memory content. User should request printing of specific array
+ elements instead. */
- return f77_get_lowerbound (type);
+ return f77_get_lowerbound (type) - 1;
}
return TYPE_ARRAY_UPPER_BOUND_VALUE (type);
@@ -135,24 +140,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream)
upper = f77_get_upperbound (tmp_type);
lower = f77_get_lowerbound (tmp_type);
- F77_DIM_SIZE (ndimen) = upper - lower + 1;
+ F77_DIM_COUNT (ndimen) = upper - lower + 1;
+
+ F77_DIM_BYTE_STRIDE (ndimen) =
+ TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type);
tmp_type = TYPE_TARGET_TYPE (tmp_type);
ndimen++;
}
- /* Now we multiply eltlen by all the offsets, so that later we
+ /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we
can print out array elements correctly. Up till now we
- know an offset to apply to get the item but we also
+ know an eltlen to apply to get the item but we also
have to know how much to add to get to the next item */
ndimen--;
eltlen = TYPE_LENGTH (tmp_type);
- F77_DIM_OFFSET (ndimen) = eltlen;
+ if (F77_DIM_BYTE_STRIDE (ndimen) == 0)
+ F77_DIM_BYTE_STRIDE (ndimen) = eltlen;
while (--ndimen > 0)
{
- eltlen *= F77_DIM_SIZE (ndimen + 1);
- F77_DIM_OFFSET (ndimen) = eltlen;
+ eltlen *= F77_DIM_COUNT (ndimen + 1);
+ if (F77_DIM_BYTE_STRIDE (ndimen) == 0)
+ F77_DIM_BYTE_STRIDE (ndimen) = eltlen;
}
}
@@ -172,34 +182,34 @@ f77_print_array_1 (int nss, int ndimensions, struct type *type,
if (nss != ndimensions)
{
- for (i = 0; (i < F77_DIM_SIZE (nss) && (*elts) < options->print_max); i++)
+ for (i = 0; (i < F77_DIM_COUNT (nss) && (*elts) < options->print_max); i++)
{
fprintf_filtered (stream, "( ");
f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type),
- valaddr + i * F77_DIM_OFFSET (nss),
- address + i * F77_DIM_OFFSET (nss),
+ valaddr + i * F77_DIM_BYTE_STRIDE (nss),
+ address + i * F77_DIM_BYTE_STRIDE (nss),
stream, recurse, options, elts);
fprintf_filtered (stream, ") ");
}
- if (*elts >= options->print_max && i < F77_DIM_SIZE (nss))
+ if (*elts >= options->print_max && i < F77_DIM_COUNT (nss))
fprintf_filtered (stream, "...");
}
else
{
- for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < options->print_max;
+ for (i = 0; i < F77_DIM_COUNT (nss) && (*elts) < options->print_max;
i++, (*elts)++)
{
val_print (TYPE_TARGET_TYPE (type),
- valaddr + i * F77_DIM_OFFSET (ndimensions),
+ valaddr + i * F77_DIM_BYTE_STRIDE (ndimensions),
0,
- address + i * F77_DIM_OFFSET (ndimensions),
+ address + i * F77_DIM_BYTE_STRIDE (ndimensions),
stream, recurse, options, current_language);
- if (i != (F77_DIM_SIZE (nss) - 1))
+ if (i != (F77_DIM_COUNT (nss) - 1))
fprintf_filtered (stream, ", ");
if ((*elts == options->print_max - 1)
- && (i != (F77_DIM_SIZE (nss) - 1)))
+ && (i != (F77_DIM_COUNT (nss) - 1)))
fprintf_filtered (stream, "...");
}
}
@@ -253,6 +263,9 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
CORE_ADDR addr;
int index;
+ if (f_object_address_data_valid_print_to_stream (type, stream) != NULL)
+ return 0;
+
CHECK_TYPEDEF (type);
switch (TYPE_CODE (type))
{
diff --git a/gdb/findcmd.c b/gdb/findcmd.c
index c752316..df2687c 100644
--- a/gdb/findcmd.c
+++ b/gdb/findcmd.c
@@ -27,7 +27,7 @@
/* Copied from bfd_put_bits. */
-static void
+void
put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
{
int i;
@@ -45,6 +45,41 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p)
}
}
+/* Allocates a buffer in *PATTERN_BUF, with a hard-coded initial size which
+ will be returned in *PATTERN_BUF_SIZE. *PATTERN_BUF_END points to the same
+ place as *PATTERN_BUF, indicating that the buffer is initially empty. */
+
+void
+allocate_pattern_buffer (char **pattern_buf, char **pattern_buf_end,
+ ULONGEST *pattern_buf_size)
+{
+#define INITIAL_PATTERN_BUF_SIZE 100
+ *pattern_buf_size = INITIAL_PATTERN_BUF_SIZE;
+ *pattern_buf = xmalloc (*pattern_buf_size);
+ *pattern_buf_end = *pattern_buf;
+}
+
+/* Grows *PATTERN_BUF by a factor of two if it's not large enough to hold
+ VAL_BYTES more bytes or a 64-bit value, whichever is larger.
+ *PATTERN_BUF_END is updated as necessary. */
+
+void
+increase_pattern_buffer (char **pattern_buf, char **pattern_buf_end,
+ ULONGEST *pattern_buf_size, int val_bytes)
+{
+ /* Keep it simple and assume size == 'g' when watching for when we
+ need to grow the pattern buf. */
+ if ((*pattern_buf_end - *pattern_buf + max (val_bytes, sizeof (int64_t)))
+ > *pattern_buf_size)
+ {
+ size_t current_offset = *pattern_buf_end - *pattern_buf;
+
+ *pattern_buf_size *= 2;
+ *pattern_buf = xrealloc (*pattern_buf, *pattern_buf_size);
+ *pattern_buf_end = *pattern_buf + current_offset;
+ }
+}
+
/* Subroutine of find_command to simplify it.
Parse the arguments of the "find" command. */
@@ -61,8 +96,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
char *pattern_buf;
/* Current size of search pattern buffer.
We realloc space as needed. */
-#define INITIAL_PATTERN_BUF_SIZE 100
- ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE;
+ ULONGEST pattern_buf_size;
/* Pointer to one past the last in-use part of pattern_buf. */
char *pattern_buf_end;
ULONGEST pattern_len;
@@ -75,8 +109,7 @@ parse_find_args (char *args, ULONGEST *max_countp,
if (args == NULL)
error (_("Missing search parameters."));
- pattern_buf = xmalloc (pattern_buf_size);
- pattern_buf_end = pattern_buf;
+ allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size);
old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
/* Get search granularity and/or max count if specified.
@@ -173,16 +206,8 @@ parse_find_args (char *args, ULONGEST *max_countp,
v = parse_to_comma_and_eval (&s);
val_bytes = TYPE_LENGTH (value_type (v));
- /* Keep it simple and assume size == 'g' when watching for when we
- need to grow the pattern buf. */
- if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t)))
- > pattern_buf_size)
- {
- size_t current_offset = pattern_buf_end - pattern_buf;
- pattern_buf_size *= 2;
- pattern_buf = xrealloc (pattern_buf, pattern_buf_size);
- pattern_buf_end = pattern_buf + current_offset;
- }
+ increase_pattern_buffer (&pattern_buf, &pattern_buf_end,
+ &pattern_buf_size, val_bytes);
if (size != '\0')
{
@@ -237,6 +262,45 @@ parse_find_args (char *args, ULONGEST *max_countp,
discard_cleanups (old_cleanups);
}
+/* Drives target_search_memory to sweep through the specified search space,
+ possibly in several iterations (with one call to this function for each
+ iteration). *START_ADDR is the address where the search starts, and is
+ updated to the next starting address to continue the search.
+ *SEARCH_SPACE_LEN is the amount of bytes which will be searched, and is
+ updated for the next iteration. PATTERN_BUF holds the pattern to be searched
+ for, PATTERN_LEN is the size of the pattern in bytes. If a match is found,
+ it's address is put in *FOUND_ADDR.
+
+ Returns 1 if found, 0 if not found, and -1 if there was an error requiring
+ halting of the search (e.g. memory read error). */
+
+int
+search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len,
+ const char *pattern_buf, ULONGEST pattern_len,
+ CORE_ADDR *found_addr)
+{
+ /* Offset from start of this iteration to the next iteration. */
+ ULONGEST next_iter_incr;
+ int found;
+
+ found = target_search_memory (*start_addr, *search_space_len,
+ pattern_buf, pattern_len, found_addr);
+ if (found <= 0)
+ return found;
+
+ /* Begin next iteration at one byte past this match. */
+ next_iter_incr = (*found_addr - *start_addr) + 1;
+
+ /* For robustness, we don't let search_space_len go -ve here. */
+ if (*search_space_len >= next_iter_incr)
+ *search_space_len -= next_iter_incr;
+ else
+ *search_space_len = 0;
+ *start_addr += next_iter_incr;
+
+ return found;
+}
+
static void
find_command (char *args, int from_tty)
{
@@ -267,12 +331,11 @@ find_command (char *args, int from_tty)
while (search_space_len >= pattern_len
&& found_count < max_count)
{
- /* Offset from start of this iteration to the next iteration. */
- ULONGEST next_iter_incr;
CORE_ADDR found_addr;
- int found = target_search_memory (start_addr, search_space_len,
- pattern_buf, pattern_len, &found_addr);
+ int found;
+ found = search_memory (&start_addr, &search_space_len, pattern_buf,
+ pattern_len, &found_addr);
if (found <= 0)
break;
@@ -280,16 +343,6 @@ find_command (char *args, int from_tty)
printf_filtered ("\n");
++found_count;
last_found_addr = found_addr;
-
- /* Begin next iteration at one byte past this match. */
- next_iter_incr = (found_addr - start_addr) + 1;
-
- /* For robustness, we don't let search_space_len go -ve here. */
- if (search_space_len >= next_iter_incr)
- search_space_len -= next_iter_incr;
- else
- search_space_len = 0;
- start_addr += next_iter_incr;
}
/* Record and print the results. */
diff --git a/gdb/findvar.c b/gdb/findvar.c
index e117a8e..6bd3724 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -35,6 +35,7 @@
#include "user-regs.h"
#include "block.h"
#include "objfiles.h"
+#include "dwarf2loc.h"
/* Basic byte-swapping routines. All 'extract' functions return a
host-format integer from a target-format integer at ADDR which is
@@ -397,27 +398,16 @@ symbol_read_needs_frame (struct symbol *sym)
/* Given a struct symbol for a variable,
and a stack frame id, read the value of the variable
and return a (pointer to a) struct value containing the value.
- If the variable cannot be found, return a zero pointer. */
+ If the variable cannot be found, return a zero pointer.
+ We have to first find the address of the variable before allocating struct
+ value to return as its size may depend on DW_OP_PUSH_OBJECT_ADDRESS possibly
+ used by its type. */
struct value *
read_var_value (struct symbol *var, struct frame_info *frame)
{
- struct value *v;
struct type *type = SYMBOL_TYPE (var);
CORE_ADDR addr;
- int len;
-
- if (SYMBOL_CLASS (var) == LOC_COMPUTED
- || SYMBOL_CLASS (var) == LOC_REGISTER)
- /* These cases do not use V. */
- v = NULL;
- else
- {
- v = allocate_value (type);
- VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */
- }
-
- len = TYPE_LENGTH (type);
if (symbol_read_needs_frame (var))
gdb_assert (frame);
@@ -425,32 +415,40 @@ read_var_value (struct symbol *var, struct frame_info *frame)
switch (SYMBOL_CLASS (var))
{
case LOC_CONST:
- /* Put the constant back in target format. */
- store_signed_integer (value_contents_raw (v), len,
- gdbarch_byte_order (get_type_arch (type)),
- (LONGEST) SYMBOL_VALUE (var));
- VALUE_LVAL (v) = not_lval;
- return v;
+ {
+ /* Put the constant back in target format. */
+ struct value *v = allocate_value (type);
+ VALUE_LVAL (v) = not_lval;
+ store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type),
+ gdbarch_byte_order (get_type_arch (type)),
+ (LONGEST) SYMBOL_VALUE (var));
+ return v;
+ }
case LOC_LABEL:
- /* Put the constant back in target format. */
- if (overlay_debugging)
- {
- CORE_ADDR addr
- = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var),
- SYMBOL_OBJ_SECTION (var));
- store_typed_address (value_contents_raw (v), type, addr);
- }
- else
- store_typed_address (value_contents_raw (v), type,
- SYMBOL_VALUE_ADDRESS (var));
- VALUE_LVAL (v) = not_lval;
- return v;
+ {
+ /* Put the constant back in target format. */
+ struct value *v = allocate_value (type);
+ VALUE_LVAL (v) = not_lval;
+ if (overlay_debugging)
+ {
+ CORE_ADDR addr
+ = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var),
+ SYMBOL_OBJ_SECTION (var));
+ store_typed_address (value_contents_raw (v), type, addr);
+ }
+ else
+ store_typed_address (value_contents_raw (v), type,
+ SYMBOL_VALUE_ADDRESS (var));
+ return v;
+ }
case LOC_CONST_BYTES:
{
- memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len);
+ struct value *v = allocate_value (type);
VALUE_LVAL (v) = not_lval;
+ memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var),
+ TYPE_LENGTH (type));
return v;
}
@@ -492,12 +490,23 @@ read_var_value (struct symbol *var, struct frame_info *frame)
break;
case LOC_BLOCK:
- if (overlay_debugging)
- set_value_address (v, symbol_overlayed_address
- (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)));
- else
- set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (var)));
- return v;
+ {
+ CORE_ADDR addr;
+ struct value *v;
+
+ if (overlay_debugging)
+ addr = symbol_overlayed_address
+ (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var));
+ else
+ addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+ /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for
+ DW_OP_push_object_address. */
+ object_address_set (addr);
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory;
+ set_value_address (v, addr);
+ return v;
+ }
case LOC_REGISTER:
case LOC_REGPARM_ADDR:
@@ -516,7 +525,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
error (_("Value of register variable not available."));
addr = value_as_address (regval);
- VALUE_LVAL (v) = lval_memory;
}
else
{
@@ -559,18 +567,33 @@ read_var_value (struct symbol *var, struct frame_info *frame)
break;
case LOC_OPTIMIZED_OUT:
- VALUE_LVAL (v) = not_lval;
- set_value_optimized_out (v, 1);
- return v;
+ {
+ struct value *v = allocate_value (type);
+
+ VALUE_LVAL (v) = not_lval;
+ set_value_optimized_out (v, 1);
+ return v;
+ }
default:
error (_("Cannot look up value of a botched symbol."));
break;
}
- set_value_address (v, addr);
- set_value_lazy (v, 1);
- return v;
+ {
+ struct value *v;
+
+ /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for
+ DW_OP_PUSH_OBJECT_ADDRESS. */
+ object_address_set (addr);
+ v = allocate_value (type);
+ VALUE_LVAL (v) = lval_memory;
+ set_value_address (v, addr);
+
+ set_value_lazy (v, 1);
+
+ return v;
+ }
}
/* Install default attributes for register values. */
@@ -607,10 +630,11 @@ struct value *
value_from_register (struct type *type, int regnum, struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
- struct type *type1 = check_typedef (type);
struct value *v;
- if (gdbarch_convert_register_p (gdbarch, regnum, type1))
+ type = check_typedef (type);
+
+ if (gdbarch_convert_register_p (gdbarch, regnum, type))
{
/* The ISA/ABI need to something weird when obtaining the
specified value from this register. It might need to
@@ -624,7 +648,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
VALUE_FRAME_ID (v) = get_frame_id (frame);
VALUE_REGNUM (v) = regnum;
gdbarch_register_to_value (gdbarch,
- frame, regnum, type1, value_contents_raw (v));
+ frame, regnum, type, value_contents_raw (v));
}
else
{
diff --git a/gdb/gdbinit.in b/gdb/gdbinit.in
index ffb7f53..a2e7e94 100644
--- a/gdb/gdbinit.in
+++ b/gdb/gdbinit.in
@@ -1,5 +1,15 @@
echo Setting up the environment for debugging gdb.\n
+# Set up the Python library and "require" command.
+python
+from os.path import abspath
+gdb.datadir = abspath ('@srcdir@/python/lib')
+gdb.pythonlibdir = gdb.datadir
+gdb.__path__ = [gdb.datadir + '/gdb']
+sys.path.insert(0, gdb.datadir)
+end
+source @srcdir@/python/lib/gdb/__init__.py
+
set complaints 1
b internal_error
diff --git a/gdb/gdbserver/linux-i386-low.c b/gdb/gdbserver/linux-i386-low.c
new file mode 100644
index 0000000..b95c1b1
--- /dev/null
+++ b/gdb/gdbserver/linux-i386-low.c
@@ -0,0 +1,210 @@
+/* GNU/Linux/i386 specific low level interface, for the remote server for GDB.
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
+ 2007, 2008, 2009 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 "server.h"
+#include "linux-low.h"
+#include "i387-fp.h"
+
+#include "gdb_proc_service.h"
+
+#include <sys/ptrace.h>
+
+#ifdef HAVE_SYS_REG_H
+#include <sys/reg.h>
+#endif
+
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA 25
+#endif
+
+/* Defined in auto-generated file reg-i386-linux.c. */
+void init_registers_i386_linux (void);
+
+
+/* This module only supports access to the general purpose registers. */
+
+#define i386_num_regs 16
+
+/* This stuff comes from i386-linux-nat.c. */
+
+/* Mapping between the general-purpose registers in `struct user'
+ format and GDB's register array layout. */
+static int i386_regmap[] =
+{
+ EAX * 4, ECX * 4, EDX * 4, EBX * 4,
+ UESP * 4, EBP * 4, ESI * 4, EDI * 4,
+ EIP * 4, EFL * 4, CS * 4, SS * 4,
+ DS * 4, ES * 4, FS * 4, GS * 4
+};
+
+/* Called by libthread_db. */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base)
+{
+ unsigned int desc[4];
+
+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid,
+ (void *) idx, (unsigned long) &desc) < 0)
+ return PS_ERR;
+
+ *(int *)base = desc[1];
+ return PS_OK;
+}
+
+static int
+i386_cannot_store_register (int regno)
+{
+ return (regno >= i386_num_regs);
+}
+
+static int
+i386_cannot_fetch_register (int regno)
+{
+ return (regno >= i386_num_regs);
+}
+
+
+#ifdef HAVE_PTRACE_GETREGS
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+
+static void
+i386_fill_gregset (void *buf)
+{
+ int i;
+
+ for (i = 0; i < i386_num_regs; i++)
+ collect_register (i, ((char *) buf) + i386_regmap[i]);
+
+ collect_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
+}
+
+static void
+i386_store_gregset (const void *buf)
+{
+ int i;
+
+ for (i = 0; i < i386_num_regs; i++)
+ supply_register (i, ((char *) buf) + i386_regmap[i]);
+
+ supply_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
+}
+
+static void
+i386_fill_fpregset (void *buf)
+{
+ i387_cache_to_fsave (buf);
+}
+
+static void
+i386_store_fpregset (const void *buf)
+{
+ i387_fsave_to_cache (buf);
+}
+
+static void
+i386_fill_fpxregset (void *buf)
+{
+ i387_cache_to_fxsave (buf);
+}
+
+static void
+i386_store_fpxregset (const void *buf)
+{
+ i387_fxsave_to_cache (buf);
+}
+
+#endif /* HAVE_PTRACE_GETREGS */
+
+struct regset_info target_regsets[] = {
+#ifdef HAVE_PTRACE_GETREGS
+ { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+ GENERAL_REGS,
+ i386_fill_gregset, i386_store_gregset },
+# ifdef HAVE_PTRACE_GETFPXREGS
+ { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
+ EXTENDED_REGS,
+ i386_fill_fpxregset, i386_store_fpxregset },
+# endif
+ { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+ FP_REGS,
+ i386_fill_fpregset, i386_store_fpregset },
+#endif /* HAVE_PTRACE_GETREGS */
+ { 0, 0, -1, -1, NULL, NULL }
+};
+
+static const unsigned char i386_breakpoint[] = { 0xCC };
+#define i386_breakpoint_len 1
+
+extern int debug_threads;
+
+static CORE_ADDR
+i386_get_pc ()
+{
+ unsigned long pc;
+
+ collect_register_by_name ("eip", &pc);
+
+ if (debug_threads)
+ fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
+ return pc;
+}
+
+static void
+i386_set_pc (CORE_ADDR newpc)
+{
+ if (debug_threads)
+ fprintf (stderr, "set pc to %08lx\n", (long) newpc);
+ supply_register_by_name ("eip", &newpc);
+}
+
+static int
+i386_breakpoint_at (CORE_ADDR pc)
+{
+ unsigned char c;
+
+ read_inferior_memory (pc, &c, 1);
+ if (c == 0xCC)
+ return 1;
+
+ return 0;
+}
+
+struct linux_target_ops the_low_target = {
+ init_registers_i386_linux,
+ i386_num_regs,
+ i386_regmap,
+ i386_cannot_fetch_register,
+ i386_cannot_store_register,
+ i386_get_pc,
+ i386_set_pc,
+ i386_breakpoint,
+ i386_breakpoint_len,
+ NULL,
+ 1,
+ i386_breakpoint_at,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
diff --git a/gdb/gdbserver/linux-x86-64-low.c b/gdb/gdbserver/linux-x86-64-low.c
new file mode 100644
index 0000000..b8213f5
--- /dev/null
+++ b/gdb/gdbserver/linux-x86-64-low.c
@@ -0,0 +1,184 @@
+/* GNU/Linux/x86-64 specific low level interface, for the remote server
+ for GDB.
+ Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009
+ 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 "server.h"
+#include "linux-low.h"
+#include "i387-fp.h"
+
+#include "gdb_proc_service.h"
+
+/* Defined in auto-generated file reg-x86-64-linux.c. */
+void init_registers_x86_64_linux (void);
+
+#include <sys/reg.h>
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+
+/* This definition comes from prctl.h, but some kernels may not have it. */
+#ifndef PTRACE_ARCH_PRCTL
+#define PTRACE_ARCH_PRCTL 30
+#endif
+
+/* The following definitions come from prctl.h, but may be absent
+ for certain configurations. */
+#ifndef ARCH_GET_FS
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004
+#endif
+
+static int x86_64_regmap[] = {
+ RAX * 8, RBX * 8, RCX * 8, RDX * 8,
+ RSI * 8, RDI * 8, RBP * 8, RSP * 8,
+ R8 * 8, R9 * 8, R10 * 8, R11 * 8,
+ R12 * 8, R13 * 8, R14 * 8, R15 * 8,
+ RIP * 8, EFLAGS * 8, CS * 8, SS * 8,
+ DS * 8, ES * 8, FS * 8, GS * 8,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ ORIG_RAX * 8
+};
+
+#define X86_64_NUM_GREGS (sizeof(x86_64_regmap)/sizeof(int))
+
+/* Called by libthread_db. */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base)
+{
+ switch (idx)
+ {
+ case FS:
+ if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
+ return PS_OK;
+ break;
+ case GS:
+ if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
+ return PS_OK;
+ break;
+ default:
+ return PS_BADADDR;
+ }
+ return PS_ERR;
+}
+
+static void
+x86_64_fill_gregset (void *buf)
+{
+ int i;
+
+ for (i = 0; i < X86_64_NUM_GREGS; i++)
+ if (x86_64_regmap[i] != -1)
+ collect_register (i, ((char *) buf) + x86_64_regmap[i]);
+}
+
+static void
+x86_64_store_gregset (const void *buf)
+{
+ int i;
+
+ for (i = 0; i < X86_64_NUM_GREGS; i++)
+ if (x86_64_regmap[i] != -1)
+ supply_register (i, ((char *) buf) + x86_64_regmap[i]);
+}
+
+static void
+x86_64_fill_fpregset (void *buf)
+{
+ i387_cache_to_fxsave (buf);
+}
+
+static void
+x86_64_store_fpregset (const void *buf)
+{
+ i387_fxsave_to_cache (buf);
+}
+
+struct regset_info target_regsets[] = {
+ { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+ GENERAL_REGS,
+ x86_64_fill_gregset, x86_64_store_gregset },
+ { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+ FP_REGS,
+ x86_64_fill_fpregset, x86_64_store_fpregset },
+ { 0, 0, -1, -1, NULL, NULL }
+};
+
+static const unsigned char x86_64_breakpoint[] = { 0xCC };
+#define x86_64_breakpoint_len 1
+
+extern int debug_threads;
+
+static CORE_ADDR
+x86_64_get_pc ()
+{
+ unsigned long pc;
+
+ collect_register_by_name ("rip", &pc);
+
+ if (debug_threads)
+ fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
+ return pc;
+}
+
+static void
+x86_64_set_pc (CORE_ADDR newpc)
+{
+ if (debug_threads)
+ fprintf (stderr, "set pc to %08lx\n", (long) newpc);
+ supply_register_by_name ("rip", &newpc);
+}
+
+static int
+x86_64_breakpoint_at (CORE_ADDR pc)
+{
+ unsigned char c;
+
+ read_inferior_memory (pc, &c, 1);
+ if (c == 0xCC)
+ return 1;
+
+ return 0;
+}
+
+struct linux_target_ops the_low_target = {
+ init_registers_x86_64_linux,
+ -1,
+ NULL,
+ NULL,
+ NULL,
+ x86_64_get_pc,
+ x86_64_set_pc,
+ x86_64_breakpoint,
+ x86_64_breakpoint_len,
+ NULL,
+ 1,
+ x86_64_breakpoint_at,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index cd24eaf..119af7d 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -185,6 +185,10 @@ struct thread_info
/* True if this thread has been explicitly requested to stop. */
int stop_requested;
+ /* The initiating frame of a nexting operation, used for deciding
+ which exceptions to intercept. */
+ struct frame_id initiating_frame;
+
/* Private data used by the target vector implementation. */
struct private_thread_info *private;
@@ -257,6 +261,9 @@ extern struct thread_info *any_live_thread_of_process (int pid);
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
+/* Prune dead threads from the list of threads. */
+extern void prune_threads (void);
+
/* Iterator function to call a user-provided callback function
once for each known thread. */
typedef int (*thread_callback_func) (struct thread_info *, void *);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 16b34ca..b5e6110 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -39,6 +39,9 @@
#include "cp-abi.h"
#include "gdb_assert.h"
#include "hashtab.h"
+#include "observer.h"
+#include "dwarf2expr.h"
+#include "dwarf2loc.h"
/* Floatformat pairs. */
@@ -119,6 +122,24 @@ static void print_arg_types (struct field *, int, int);
static void dump_fn_fieldlists (struct type *, int);
static void print_cplus_stuff (struct type *, int);
+/* A reference count structure for the type reference count map. Each
+ type in a hierarchy of types is mapped to the same reference
+ count. */
+struct type_refc_entry
+{
+ /* One type in the hierarchy. Each type in the hierarchy gets its
+ own slot. */
+ struct type *type;
+
+ /* A pointer to the shared reference count. */
+ int *refc;
+};
+
+/* The hash table holding all discardable `struct type *' references. */
+static htab_t type_discardable_table;
+
+/* Current type_discardable_check pass used for TYPE_DISCARDABLE_AGE. */
+static int type_discardable_age_current;
/* Allocate a new OBJFILE-associated type structure and fill it
with some defaults. Space for the type structure is allocated
@@ -149,6 +170,39 @@ alloc_type (struct objfile *objfile)
return type;
}
+/* Declare TYPE as discardable on next garbage collection by free_all_types.
+ You must call type_mark_used during each free_all_types to protect TYPE from
+ being deallocated. */
+
+static void
+set_type_as_discardable (struct type *type)
+{
+ void **slot;
+
+ gdb_assert (!TYPE_DISCARDABLE (type));
+
+ TYPE_DISCARDABLE (type) = 1;
+ TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current;
+
+ slot = htab_find_slot (type_discardable_table, type, INSERT);
+ gdb_assert (!*slot);
+ *slot = type;
+}
+
+/* Allocate a new type like alloc_type but preserve for it the discardability
+ state of PARENT_TYPE. */
+
+static struct type *
+alloc_type_as_parent (struct type *parent_type)
+{
+ struct type *new_type = alloc_type_copy (parent_type);
+
+ if (TYPE_DISCARDABLE (parent_type))
+ set_type_as_discardable (new_type);
+
+ return new_type;
+}
+
/* Allocate a new GDBARCH-associated type structure and fill it
with some defaults. Space for the type structure is allocated
on the heap. */
@@ -274,7 +328,7 @@ make_pointer_type (struct type *type, struct type **typeptr)
if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
{
- ntype = alloc_type_copy (type);
+ ntype = alloc_type_as_parent (type);
if (typeptr)
*typeptr = ntype;
}
@@ -351,7 +405,7 @@ make_reference_type (struct type *type, struct type **typeptr)
if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */
{
- ntype = alloc_type_copy (type);
+ ntype = alloc_type_as_parent (type);
if (typeptr)
*typeptr = ntype;
}
@@ -726,6 +780,7 @@ create_range_type (struct type *result_type, struct type *index_type,
TYPE_ZALLOC (result_type, sizeof (struct range_bounds));
TYPE_LOW_BOUND (result_type) = low_bound;
TYPE_HIGH_BOUND (result_type) = high_bound;
+ TYPE_BYTE_STRIDE (result_type) = 0;
if (low_bound >= 0)
TYPE_UNSIGNED (result_type) = 1;
@@ -825,26 +880,45 @@ create_array_type (struct type *result_type,
TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
TYPE_TARGET_TYPE (result_type) = element_type;
- if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
- low_bound = high_bound = 0;
- CHECK_TYPEDEF (element_type);
- /* Be careful when setting the array length. Ada arrays can be
- empty arrays with the high_bound being smaller than the low_bound.
- In such cases, the array length should be zero. */
- if (high_bound < low_bound)
- TYPE_LENGTH (result_type) = 0;
- else
- TYPE_LENGTH (result_type) =
- TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
TYPE_NFIELDS (result_type) = 1;
TYPE_FIELDS (result_type) =
(struct field *) TYPE_ZALLOC (result_type, sizeof (struct field));
TYPE_INDEX_TYPE (result_type) = range_type;
TYPE_VPTR_FIELDNO (result_type) = -1;
- /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */
+ /* DWARF blocks may depend on runtime information like
+ DW_OP_PUSH_OBJECT_ADDRESS not being available during the
+ CREATE_ARRAY_TYPE time. */
+ if (TYPE_LOW_BOUND_IS_DWARF_BLOCK (range_type)
+ || TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type)
+ || TYPE_LOW_BOUND_UNDEFINED (range_type)
+ || TYPE_HIGH_BOUND_UNDEFINED (range_type)
+ || get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
+ {
+ low_bound = 0;
+ high_bound = -1;
+ }
+
+ /* Be careful when setting the array length. Ada arrays can be
+ empty arrays with the high_bound being smaller than the low_bound.
+ In such cases, the array length should be zero. TYPE_TARGET_STUB needs to
+ be checked as it may have dependencies on DWARF blocks depending on
+ runtime information not available during the CREATE_ARRAY_TYPE time. */
+ if (high_bound < low_bound || TYPE_TARGET_STUB (element_type))
+ TYPE_LENGTH (result_type) = 0;
+ else
+ {
+ CHECK_TYPEDEF (element_type);
+ TYPE_LENGTH (result_type) =
+ TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
+ }
+
if (TYPE_LENGTH (result_type) == 0)
- TYPE_TARGET_STUB (result_type) = 1;
+ {
+ /* The real size will be computed for specific instances by
+ CHECK_TYPEDEF. */
+ TYPE_TARGET_STUB (result_type) = 1;
+ }
return result_type;
}
@@ -1331,6 +1405,105 @@ stub_noname_complaint (void)
complaint (&symfile_complaints, _("stub type has NULL name"));
}
+/* Calculate the memory length of array TYPE.
+
+ TARGET_TYPE should be set to `check_typedef (TYPE_TARGET_TYPE (type))' as
+ a performance hint. Feel free to pass NULL. Set FULL_SPAN to return the
+ size incl. the possible padding of the last element - it may differ from the
+ cleared FULL_SPAN return value (the expected SIZEOF) for non-zero
+ TYPE_BYTE_STRIDE values. */
+
+static LONGEST
+type_length_get (struct type *type, struct type *target_type, int full_span)
+{
+ struct type *range_type;
+ LONGEST byte_stride = 0; /* `= 0' for a false GCC warning. */
+ LONGEST count, element_size, retval;
+
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_STRING)
+ return TYPE_LENGTH (type);
+
+ /* Avoid executing TYPE_HIGH_BOUND for invalid (unallocated/unassociated)
+ Fortran arrays. The allocated data will never be used so they can be
+ zero-length. */
+ if (object_address_data_not_valid (type))
+ return 0;
+
+ range_type = TYPE_INDEX_TYPE (type);
+ if (TYPE_LOW_BOUND_UNDEFINED (range_type)
+ || TYPE_HIGH_BOUND_UNDEFINED (range_type))
+ return 0;
+ count = TYPE_HIGH_BOUND (range_type) - TYPE_LOW_BOUND (range_type) + 1;
+ /* It may happen for wrong DWARF annotations returning garbage data. */
+ if (count < 0)
+ warning (_("Range for type %s has invalid bounds %s..%s"),
+ TYPE_NAME (type), plongest (TYPE_LOW_BOUND (range_type)),
+ plongest (TYPE_HIGH_BOUND (range_type)));
+ /* The code below does not handle count == 0 right. */
+ if (count <= 0)
+ return 0;
+ if (full_span || count > 1)
+ {
+ /* We do not use TYPE_ARRAY_BYTE_STRIDE_VALUE (type) here as we want to
+ force FULL_SPAN to 1. */
+ byte_stride = TYPE_BYTE_STRIDE (range_type);
+ if (byte_stride == 0)
+ {
+ if (target_type == NULL)
+ target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ byte_stride = type_length_get (target_type, NULL, 1);
+ }
+ }
+
+ /* For now, we conservatively take the array length to be 0 if its length
+ exceeds UINT_MAX. The code below assumes that for x < 0,
+ (ULONGEST) x == -x + ULONGEST_MAX + 1, which is technically not guaranteed
+ by C, but is usually true (because it would be true if x were unsigned
+ with its high-order bit on). It uses the fact that high_bound-low_bound is
+ always representable in ULONGEST and that if high_bound-low_bound+1
+ overflows, it overflows to 0. We must change these tests if we decide to
+ increase the representation of TYPE_LENGTH from unsigned int to ULONGEST.
+ */
+
+ if (full_span)
+ {
+ retval = count * byte_stride;
+ if (count == 0 || retval / count != byte_stride || retval > UINT_MAX)
+ retval = 0;
+ return retval;
+ }
+ if (target_type == NULL)
+ target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ element_size = type_length_get (target_type, NULL, 1);
+ retval = (count - 1) * byte_stride + element_size;
+ if (retval < element_size
+ || (byte_stride != 0
+ && (retval - element_size) / byte_stride != count - 1)
+ || retval > UINT_MAX)
+ retval = 0;
+ return retval;
+}
+
+/* Prepare TYPE after being read in by the backend. Currently this function
+ only propagates the TYPE_DYNAMIC flag. */
+
+void
+finalize_type (struct type *type)
+{
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ if (TYPE_FIELD_TYPE (type, i) && TYPE_DYNAMIC (TYPE_FIELD_TYPE (type, i)))
+ break;
+
+ /* FIXME: cplus_stuff is ignored here. */
+ if (i < TYPE_NFIELDS (type)
+ || (TYPE_VPTR_BASETYPE (type) && TYPE_DYNAMIC (TYPE_VPTR_BASETYPE (type)))
+ || (TYPE_TARGET_TYPE (type) && TYPE_DYNAMIC (TYPE_TARGET_TYPE (type))))
+ TYPE_DYNAMIC (type) = 1;
+}
+
/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989.
If this is a stubbed struct (i.e. declared as struct foo *), see if
@@ -1462,51 +1635,36 @@ check_typedef (struct type *type)
}
}
- if (TYPE_TARGET_STUB (type))
+ /* copy_type_recursive automatically makes the resulting type containing only
+ constant values expected by the callers of this function. */
+ if (TYPE_DYNAMIC (type))
+ {
+ htab_t copied_types;
+ struct type *type_old = type;
+
+ copied_types = create_copied_types_hash (NULL);
+ type = copy_type_recursive (type, copied_types);
+ htab_delete (copied_types);
+
+ gdb_assert (TYPE_DYNAMIC (type) == 0);
+ }
+
+ if (TYPE_TARGET_STUB (type) || TYPE_DYNAMIC (type))
{
- struct type *range_type;
struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
+ if (TYPE_DYNAMIC (type))
+ TYPE_TARGET_TYPE (type) = target_type;
if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type))
{
/* Empty. */
}
else if (TYPE_CODE (type) == TYPE_CODE_ARRAY
- && TYPE_NFIELDS (type) == 1
- && (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type))
- == TYPE_CODE_RANGE))
+ || TYPE_CODE (type) == TYPE_CODE_STRING)
{
/* Now recompute the length of the array type, based on its
- number of elements and the target type's length.
- Watch out for Ada null Ada arrays where the high bound
- is smaller than the low bound. */
- const LONGEST low_bound = TYPE_LOW_BOUND (range_type);
- const LONGEST high_bound = TYPE_HIGH_BOUND (range_type);
- ULONGEST len;
-
- if (high_bound < low_bound)
- len = 0;
- else {
- /* For now, we conservatively take the array length to be 0
- if its length exceeds UINT_MAX. The code below assumes
- that for x < 0, (ULONGEST) x == -x + ULONGEST_MAX + 1,
- which is technically not guaranteed by C, but is usually true
- (because it would be true if x were unsigned with its
- high-order bit on). It uses the fact that
- high_bound-low_bound is always representable in
- ULONGEST and that if high_bound-low_bound+1 overflows,
- it overflows to 0. We must change these tests if we
- decide to increase the representation of TYPE_LENGTH
- from unsigned int to ULONGEST. */
- ULONGEST ulow = low_bound, uhigh = high_bound;
- ULONGEST tlen = TYPE_LENGTH (target_type);
-
- len = tlen * (uhigh - ulow + 1);
- if (tlen == 0 || (len / tlen - 1 + ulow) != uhigh
- || len > UINT_MAX)
- len = 0;
- }
- TYPE_LENGTH (type) = len;
+ number of elements and the target type's length. */
+ TYPE_LENGTH (type) = type_length_get (type, target_type, 0);
TYPE_TARGET_STUB (type) = 0;
}
else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
@@ -1514,9 +1672,12 @@ check_typedef (struct type *type)
TYPE_LENGTH (type) = TYPE_LENGTH (target_type);
TYPE_TARGET_STUB (type) = 0;
}
+ TYPE_DYNAMIC (type) = 0;
}
+
/* Cache TYPE_LENGTH for future use. */
TYPE_LENGTH (orig_type) = TYPE_LENGTH (type);
+
return type;
}
@@ -1809,6 +1970,7 @@ init_type (enum type_code code, int length, int flags,
TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_CALLING_CONVENTION;
break;
}
+
return type;
}
@@ -2889,33 +3051,42 @@ type_pair_eq (const void *item_lhs, const void *item_rhs)
}
/* Allocate the hash table used by copy_type_recursive to walk
- types without duplicates. We use OBJFILE's obstack, because
- OBJFILE is about to be deleted. */
+ types without duplicates. */
htab_t
create_copied_types_hash (struct objfile *objfile)
{
- return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq,
- NULL, &objfile->objfile_obstack,
- hashtab_obstack_allocate,
- dummy_obstack_deallocate);
+ if (objfile == NULL)
+ {
+ /* NULL OBJFILE is for TYPE_DYNAMIC types already contained in
+ OBJFILE_MALLOC memory, such as those from VALUE_HISTORY_CHAIN. Table
+ element entries get allocated by xmalloc - so use xfree. */
+ return htab_create (1, type_pair_hash, type_pair_eq, xfree);
+ }
+ else
+ {
+ /* Use OBJFILE's obstack, because OBJFILE is about to be deleted. Table
+ element entries get allocated by xmalloc - so use xfree. */
+ return htab_create_alloc_ex (1, type_pair_hash, type_pair_eq,
+ xfree, &objfile->objfile_obstack,
+ hashtab_obstack_allocate,
+ dummy_obstack_deallocate);
+ }
}
-/* Recursively copy (deep copy) TYPE, if it is associated with
- OBJFILE. Return a new type allocated using malloc, a saved type if
- we have already visited TYPE (using COPIED_TYPES), or TYPE if it is
- not associated with OBJFILE. */
+/* A helper for copy_type_recursive. This does all the work. OBJFILE is used
+ only for an assertion checking. */
-struct type *
-copy_type_recursive (struct objfile *objfile,
- struct type *type,
- htab_t copied_types)
+static struct type *
+copy_type_recursive_1 (struct objfile *objfile,
+ struct type *type,
+ htab_t copied_types)
{
struct type_pair *stored, pair;
void **slot;
struct type *new_type;
- if (! TYPE_OBJFILE_OWNED (type))
+ if (! TYPE_OBJFILE_OWNED (type) && !TYPE_DYNAMIC (type))
return type;
/* This type shouldn't be pointing to any types in other objfiles;
@@ -2930,8 +3101,10 @@ copy_type_recursive (struct objfile *objfile,
new_type = alloc_type_arch (get_type_arch (type));
/* We must add the new type to the hash table immediately, in case
- we encounter this type again during a recursive call below. */
- stored = obstack_alloc (&objfile->objfile_obstack, sizeof (struct type_pair));
+ we encounter this type again during a recursive call below. Memory could
+ be allocated from OBJFILE in the case we will be removing OBJFILE, this
+ optimization is missed and xfree is called for it from COPIED_TYPES. */
+ stored = xmalloc (sizeof (*stored));
stored->old = type;
stored->new = new_type;
*slot = stored;
@@ -2942,6 +3115,19 @@ copy_type_recursive (struct objfile *objfile,
TYPE_OBJFILE_OWNED (new_type) = 0;
TYPE_OWNER (new_type).gdbarch = get_type_arch (type);
+ /* TYPE_MAIN_TYPE memory copy above rewrote the TYPE_DISCARDABLE flag so we
+ need to initialize it again. And even if TYPE was already discardable
+ NEW_TYPE so far is not registered in TYPE_DISCARDABLE_TABLE. */
+ TYPE_DISCARDABLE (new_type) = 0;
+ set_type_as_discardable (new_type);
+
+ /* Pre-clear the fields processed by delete_main_type. If DWARF block
+ evaluations below call error we would leave an unfreeable TYPE. */
+ TYPE_TARGET_TYPE (new_type) = NULL;
+ TYPE_VPTR_BASETYPE (new_type) = NULL;
+ TYPE_NFIELDS (new_type) = 0;
+ TYPE_FIELDS (new_type) = NULL;
+
if (TYPE_NAME (type))
TYPE_NAME (new_type) = xstrdup (TYPE_NAME (type));
if (TYPE_TAG_NAME (type))
@@ -2950,12 +3136,45 @@ copy_type_recursive (struct objfile *objfile,
TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
+ if (TYPE_ALLOCATED (new_type))
+ {
+ gdb_assert (!TYPE_NOT_ALLOCATED (new_type));
+
+ if (!dwarf_locexpr_baton_eval (TYPE_ALLOCATED (new_type)))
+ TYPE_NOT_ALLOCATED (new_type) = 1;
+ TYPE_ALLOCATED (new_type) = NULL;
+ }
+
+ if (TYPE_ASSOCIATED (new_type))
+ {
+ gdb_assert (!TYPE_NOT_ASSOCIATED (new_type));
+
+ if (!dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (new_type)))
+ TYPE_NOT_ASSOCIATED (new_type) = 1;
+ TYPE_ASSOCIATED (new_type) = NULL;
+ }
+
+ if (!TYPE_DATA_LOCATION_IS_ADDR (new_type)
+ && TYPE_DATA_LOCATION_DWARF_BLOCK (new_type))
+ {
+ if (TYPE_NOT_ALLOCATED (new_type)
+ || TYPE_NOT_ASSOCIATED (new_type))
+ TYPE_DATA_LOCATION_DWARF_BLOCK (new_type) = NULL;
+ else
+ {
+ TYPE_DATA_LOCATION_IS_ADDR (new_type) = 1;
+ TYPE_DATA_LOCATION_ADDR (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_DATA_LOCATION_DWARF_BLOCK (new_type));
+ }
+ }
+
/* Copy the fields. */
if (TYPE_NFIELDS (type))
{
int i, nfields;
nfields = TYPE_NFIELDS (type);
+ TYPE_NFIELDS (new_type) = nfields;
TYPE_FIELDS (new_type) = XCALLOC (nfields, struct field);
for (i = 0; i < nfields; i++)
{
@@ -2964,8 +3183,8 @@ copy_type_recursive (struct objfile *objfile,
TYPE_FIELD_BITSIZE (new_type, i) = TYPE_FIELD_BITSIZE (type, i);
if (TYPE_FIELD_TYPE (type, i))
TYPE_FIELD_TYPE (new_type, i)
- = copy_type_recursive (objfile, TYPE_FIELD_TYPE (type, i),
- copied_types);
+ = copy_type_recursive_1 (objfile, TYPE_FIELD_TYPE (type, i),
+ copied_types);
if (TYPE_FIELD_NAME (type, i))
TYPE_FIELD_NAME (new_type, i) =
xstrdup (TYPE_FIELD_NAME (type, i));
@@ -2992,24 +3211,75 @@ copy_type_recursive (struct objfile *objfile,
}
}
+ /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were
+ possibly converted. */
+ TYPE_DYNAMIC (new_type) = 0;
+
/* For range types, copy the bounds information. */
if (TYPE_CODE (type) == TYPE_CODE_RANGE)
{
TYPE_RANGE_DATA (new_type) = xmalloc (sizeof (struct range_bounds));
*TYPE_RANGE_DATA (new_type) = *TYPE_RANGE_DATA (type);
+
+ if (TYPE_LOW_BOUND_IS_DWARF_BLOCK (type))
+ {
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF. */
+ if (TYPE_NOT_ALLOCATED (type)
+ || TYPE_NOT_ASSOCIATED (type))
+ TYPE_RANGE_DATA (new_type)->low.u.dwarf_block = NULL;
+ else
+ TYPE_LOW_BOUND (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->low.u.dwarf_block);
+ TYPE_LOW_BOUND_IS_DWARF_BLOCK (new_type) = 0;
+ }
+
+ if (TYPE_HIGH_BOUND_IS_DWARF_BLOCK (type))
+ {
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF. */
+ if (TYPE_NOT_ALLOCATED (type)
+ || TYPE_NOT_ASSOCIATED (type))
+ TYPE_RANGE_DATA (new_type)->high.u.dwarf_block = NULL;
+ else
+ TYPE_HIGH_BOUND (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->high.u.dwarf_block);
+ TYPE_HIGH_BOUND_IS_DWARF_BLOCK (new_type) = 0;
+ }
+
+ if (TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (type))
+ {
+ /* `struct dwarf2_locexpr_baton' is too bound to its objfile so
+ it is expected to be made constant by CHECK_TYPEDEF. */
+ if (TYPE_NOT_ALLOCATED (type)
+ || TYPE_NOT_ASSOCIATED (type))
+ TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block = NULL;
+ else
+ TYPE_BYTE_STRIDE (new_type) = dwarf_locexpr_baton_eval
+ (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block);
+ TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (new_type) = 0;
+ }
+
+ /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */
+ if (TYPE_RANGE_HIGH_BOUND_IS_COUNT (type))
+ {
+ TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (type)
+ + TYPE_HIGH_BOUND (type) - 1;
+ TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0;
+ }
}
/* Copy pointers to other types. */
if (TYPE_TARGET_TYPE (type))
TYPE_TARGET_TYPE (new_type) =
- copy_type_recursive (objfile,
- TYPE_TARGET_TYPE (type),
- copied_types);
+ copy_type_recursive_1 (objfile,
+ TYPE_TARGET_TYPE (type),
+ copied_types);
if (TYPE_VPTR_BASETYPE (type))
TYPE_VPTR_BASETYPE (new_type) =
- copy_type_recursive (objfile,
- TYPE_VPTR_BASETYPE (type),
- copied_types);
+ copy_type_recursive_1 (objfile,
+ TYPE_VPTR_BASETYPE (type),
+ copied_types);
/* Maybe copy the type_specific bits.
NOTE drow/2005-12-09: We do not copy the C++-specific bits like
@@ -3027,6 +3297,17 @@ copy_type_recursive (struct objfile *objfile,
return new_type;
}
+/* Recursively copy (deep copy) TYPE. Return a new type allocated using
+ malloc, a saved type if we have already visited TYPE (using COPIED_TYPES),
+ or TYPE if it is not associated with OBJFILE. */
+
+struct type *
+copy_type_recursive (struct type *type,
+ htab_t copied_types)
+{
+ return copy_type_recursive_1 (TYPE_OBJFILE (type), type, copied_types);
+}
+
/* Make a copy of the given TYPE, except that the pointer & reference
types are not preserved.
@@ -3049,6 +3330,199 @@ copy_type (const struct type *type)
return new_type;
}
+/* Callback type for main_type_crawl. */
+typedef int (*main_type_crawl_iter) (struct type *type, void *data);
+
+/* Iterate all main_type structures reachable through any `struct type *' from
+ TYPE. ITER will be called only for one type of each main_type, use
+ TYPE_CHAIN traversal to find all the type instances. ITER is being called
+ for each main_type found. ITER returns non-zero if main_type_crawl should
+ depth-first enter the specific type. ITER must provide some detection for
+ reentering the same main_type as this function would otherwise endlessly
+ loop. */
+
+static void
+main_type_crawl (struct type *type, main_type_crawl_iter iter, void *data)
+{
+ struct type *type_iter;
+ int i;
+
+ if (!type)
+ return;
+
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ /* `struct cplus_struct_type' handling is unsupported by this function. */
+ gdb_assert ((TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ || !HAVE_CPLUS_STRUCT (type));
+
+ if (!(*iter) (type, data))
+ return;
+
+ /* Iterate all the type instances of this main_type. */
+ type_iter = type;
+ do
+ {
+ gdb_assert (TYPE_MAIN_TYPE (type_iter) == TYPE_MAIN_TYPE (type));
+
+ main_type_crawl (TYPE_POINTER_TYPE (type), iter, data);
+ main_type_crawl (TYPE_REFERENCE_TYPE (type), iter, data);
+
+ type_iter = TYPE_CHAIN (type_iter);
+ }
+ while (type_iter != type);
+
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ main_type_crawl (TYPE_FIELD_TYPE (type, i), iter, data);
+
+ main_type_crawl (TYPE_TARGET_TYPE (type), iter, data);
+ main_type_crawl (TYPE_VPTR_BASETYPE (type), iter, data);
+}
+
+/* A helper for delete_type which deletes a main_type and the things to which
+ it refers. TYPE is a type whose main_type we wish to destroy. */
+
+static void
+delete_main_type (struct type *type)
+{
+ int i;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ xfree (TYPE_NAME (type));
+ xfree (TYPE_TAG_NAME (type));
+
+ for (i = 0; i < TYPE_NFIELDS (type); ++i)
+ {
+ xfree (TYPE_FIELD_NAME (type, i));
+
+ if (TYPE_FIELD_LOC_KIND (type, i) == FIELD_LOC_KIND_PHYSNAME)
+ xfree (TYPE_FIELD_STATIC_PHYSNAME (type, i));
+ }
+ xfree (TYPE_FIELDS (type));
+
+ gdb_assert (!HAVE_CPLUS_STRUCT (type));
+
+ xfree (TYPE_MAIN_TYPE (type));
+}
+
+/* Delete all the instances on TYPE_CHAIN of TYPE, including their referenced
+ main_type. TYPE must be a reclaimable type - neither permanent nor objfile
+ associated. */
+
+static void
+delete_type_chain (struct type *type)
+{
+ struct type *type_iter, *type_iter_to_free;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+ gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+ delete_main_type (type);
+
+ type_iter = type;
+ do
+ {
+ type_iter_to_free = type_iter;
+ type_iter = TYPE_CHAIN (type_iter);
+ xfree (type_iter_to_free);
+ }
+ while (type_iter != type);
+}
+
+/* Hash function for type_discardable_table. */
+
+static hashval_t
+type_discardable_hash (const void *p)
+{
+ const struct type *type = p;
+
+ return htab_hash_pointer (TYPE_MAIN_TYPE (type));
+}
+
+/* Equality function for type_discardable_table. */
+
+static int
+type_discardable_equal (const void *a, const void *b)
+{
+ const struct type *left = a;
+ const struct type *right = b;
+
+ return TYPE_MAIN_TYPE (left) == TYPE_MAIN_TYPE (right);
+}
+
+/* A helper for type_mark_used. */
+
+static int
+type_mark_used_crawl (struct type *type, void *unused)
+{
+ if (!TYPE_DISCARDABLE (type))
+ return 0;
+
+ if (TYPE_DISCARDABLE_AGE (type) == type_discardable_age_current)
+ return 0;
+
+ TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current;
+
+ /* Continue the traversal. */
+ return 1;
+}
+
+/* Mark TYPE and its connected types as used in this free_all_types pass. */
+
+void
+type_mark_used (struct type *type)
+{
+ if (type == NULL)
+ return;
+
+ if (!TYPE_DISCARDABLE (type))
+ return;
+
+ main_type_crawl (type, type_mark_used_crawl, NULL);
+}
+
+/* A traverse callback for type_discardable_table which removes any
+ type_discardable whose reference count is now zero (unused link). */
+
+static int
+type_discardable_remove (void **slot, void *unused)
+{
+ struct type *type = *slot;
+
+ gdb_assert (TYPE_DISCARDABLE (type));
+
+ if (TYPE_DISCARDABLE_AGE (type) != type_discardable_age_current)
+ {
+ delete_type_chain (type);
+
+ htab_clear_slot (type_discardable_table, slot);
+ }
+
+ return 1;
+}
+
+/* Free all the reclaimable types that have been allocated and that have
+ currently zero reference counter.
+
+ This function is called after each command, successful or not. Use this
+ cleanup only in the GDB idle state as GDB only marks those types used by
+ globally tracked objects (with no autovariable references tracking). */
+
+void
+free_all_types (void)
+{
+ /* Mark a new pass. As GDB checks all the entries were visited after each
+ pass there cannot be any stale entries already containing the changed
+ value. */
+ type_discardable_age_current ^= 1;
+
+ observer_notify_mark_used ();
+
+ htab_traverse (type_discardable_table, type_discardable_remove, NULL);
+}
/* Helper functions to initialize architecture-specific types. */
@@ -3539,6 +4013,11 @@ void
_initialize_gdbtypes (void)
{
gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init);
+
+ type_discardable_table = htab_create_alloc (20, type_discardable_hash,
+ type_discardable_equal, NULL,
+ xcalloc, xfree);
+
objfile_type_data = register_objfile_data ();
add_setshow_zinteger_cmd ("overload", no_class, &overload_debug, _("\
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 8e73ca0..85888e1 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -138,6 +138,8 @@ enum type_code
TYPE_CODE_DECFLOAT, /* Decimal floating point. */
+ TYPE_CODE_MODULE, /* Fortran module. */
+
/* Internal function type. */
TYPE_CODE_INTERNAL_FUNCTION
};
@@ -214,6 +216,11 @@ enum type_instance_flag_value
#define TYPE_TARGET_STUB(t) (TYPE_MAIN_TYPE (t)->flag_target_stub)
+/* Type needs to be evaluated on each CHECK_TYPEDEF and its results must not be
+ sticky. */
+
+#define TYPE_DYNAMIC(t) (TYPE_MAIN_TYPE (t)->flag_dynamic)
+
/* Static type. If this is set, the corresponding type had
* a static modifier.
* Note: This may be unnecessary, since static data members
@@ -279,6 +286,48 @@ enum type_instance_flag_value
#define TYPE_OWNER(t) TYPE_MAIN_TYPE(t)->owner
#define TYPE_OBJFILE(t) (TYPE_OBJFILE_OWNED(t)? TYPE_OWNER(t).objfile : NULL)
+/* Define this type as being reclaimable during free_all_types. Type is
+ required to be have TYPE_OBJFILE set to NULL. Setting this flag requires
+ initializing TYPE_DISCARDABLE_AGE, see alloc_type_discardable. */
+
+#define TYPE_DISCARDABLE(t) (TYPE_MAIN_TYPE (t)->flag_discardable)
+
+/* Marker this type has been visited by the type_mark_used by this
+ mark-and-sweep types garbage collecting pass. Current pass is represented
+ by TYPE_DISCARDABLE_AGE_CURRENT. */
+
+#define TYPE_DISCARDABLE_AGE(t) (TYPE_MAIN_TYPE (t)->flag_discardable_age)
+
+/* Is HIGH_BOUND a low-bound relative count (1) or the high bound itself (0)? */
+
+#define TYPE_RANGE_HIGH_BOUND_IS_COUNT(range_type) \
+ (TYPE_MAIN_TYPE (range_type)->flag_range_high_bound_is_count)
+
+/* Not allocated. TYPE_ALLOCATED(t) must be NULL in such case. If this flag
+ is unset and TYPE_ALLOCATED(t) is NULL then the type is allocated. If this
+ flag is unset and TYPE_ALLOCATED(t) is not NULL then its DWARF block
+ determines the actual allocation state. */
+
+#define TYPE_NOT_ALLOCATED(t) (TYPE_MAIN_TYPE (t)->flag_not_allocated)
+
+/* Not associated. TYPE_ASSOCIATED(t) must be NULL in such case. If this flag
+ is unset and TYPE_ASSOCIATED(t) is NULL then the type is associated. If
+ this flag is unset and TYPE_ASSOCIATED(t) is not NULL then its DWARF block
+ determines the actual association state. */
+
+#define TYPE_NOT_ASSOCIATED(t) (TYPE_MAIN_TYPE (t)->flag_not_associated)
+
+/* Address of the actual data as for DW_AT_data_location. Its dwarf block must
+ not be evaluated unless both TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are
+ false. If TYPE_DATA_LOCATION_IS_ADDR set then TYPE_DATA_LOCATION_ADDR value
+ is the actual data address value. If unset and
+ TYPE_DATA_LOCATION_DWARF_BLOCK is NULL then the value is the normal
+ value_raw_address. If unset and TYPE_DATA_LOCATION_DWARF_BLOCK is not NULL
+ then its DWARF block determines the actual data address. */
+
+#define TYPE_DATA_LOCATION_IS_ADDR(t) \
+ (TYPE_MAIN_TYPE (t)->flag_data_location_is_addr)
+
/* Constant type. If this is set, the corresponding type has a
* const modifier.
*/
@@ -336,8 +385,7 @@ enum field_loc_kind
{
FIELD_LOC_KIND_BITPOS, /* bitpos */
FIELD_LOC_KIND_PHYSADDR, /* physaddr */
- FIELD_LOC_KIND_PHYSNAME, /* physname */
- FIELD_LOC_KIND_DWARF_BLOCK /* dwarf_block */
+ FIELD_LOC_KIND_PHYSNAME /* physname */
};
/* A discriminant to determine which field in the main_type.type_specific
@@ -386,6 +434,13 @@ struct main_type
unsigned int flag_nottext : 1;
unsigned int flag_fixed_instance : 1;
unsigned int flag_objfile_owned : 1;
+ unsigned int flag_discardable : 1;
+ unsigned int flag_discardable_age : 1;
+ unsigned int flag_dynamic : 1;
+ unsigned int flag_range_high_bound_is_count : 1;
+ unsigned int flag_not_allocated : 1;
+ unsigned int flag_not_associated : 1;
+ unsigned int flag_data_location_is_addr : 1;
/* A discriminant telling us which field of the type_specific union
is being used for this type, if any. */
@@ -456,6 +511,20 @@ struct main_type
struct type *target_type;
+ /* For DW_AT_data_location. */
+ union
+ {
+ struct dwarf2_locexpr_baton *dwarf_block;
+ CORE_ADDR addr;
+ }
+ data_location;
+
+ /* For DW_AT_allocated. */
+ struct dwarf2_locexpr_baton *allocated;
+
+ /* For DW_AT_associated. */
+ struct dwarf2_locexpr_baton *associated;
+
/* For structure and union types, a description of each field.
For set and pascal array types, there is one "field",
whose type is the domain type of the set or array.
@@ -492,12 +561,6 @@ struct main_type
CORE_ADDR physaddr;
char *physname;
-
- /* The field location can be computed by evaluating the following DWARF
- block. This can be used in Fortran variable-length arrays, for
- instance. */
-
- struct dwarf2_locexpr_baton *dwarf_block;
}
loc;
@@ -535,13 +598,22 @@ struct main_type
struct range_bounds
{
+ struct
+ {
+ union
+ {
+ struct dwarf2_locexpr_baton *dwarf_block;
+ LONGEST constant;
+ }
+ u;
+ unsigned is_dwarf_block : 1;
+ }
/* Low bound of range. */
-
- LONGEST low;
-
+ low,
/* High bound of range. */
-
- LONGEST high;
+ high,
+ /* Byte stride of range. */
+ byte_stride;
/* Flags indicating whether the values of low and high are
valid. When true, the respective range value is
@@ -593,6 +665,9 @@ struct main_type
supporting multiple ABIs. Right now this is only fetched from
the Dwarf-2 DW_AT_calling_convention attribute. */
unsigned calling_convention;
+
+ /* For TYPE_CODE_MODULE, the list of symbols contained in the module. */
+ struct block *module_block;
} type_specific;
};
@@ -900,9 +975,9 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
#define TYPE_CHAIN(thistype) (thistype)->chain
-/* Note that if thistype is a TYPEDEF type, you have to call check_typedef.
- But check_typedef does set the TYPE_LENGTH of the TYPEDEF type,
- so you only have to call check_typedef once. Since allocate_value
+/* Note that if thistype is a TYPEDEF, ARRAY or STRING type, you have to call
+ check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF
+ type, so you only have to call check_typedef once. Since allocate_value
calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */
#define TYPE_LENGTH(thistype) (thistype)->length
/* Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real
@@ -911,15 +986,26 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields
#define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields
#define TYPE_TEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->template_args
+#define TYPE_DATA_LOCATION_DWARF_BLOCK(thistype) TYPE_MAIN_TYPE (thistype)->data_location.dwarf_block
+#define TYPE_DATA_LOCATION_ADDR(thistype) TYPE_MAIN_TYPE (thistype)->data_location.addr
+#define TYPE_ALLOCATED(thistype) TYPE_MAIN_TYPE (thistype)->allocated
+#define TYPE_ASSOCIATED(thistype) TYPE_MAIN_TYPE (thistype)->associated
#define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0)
#define TYPE_RANGE_DATA(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.bounds
-#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low
-#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high
+#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low.u.constant
+#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high.u.constant
+#define TYPE_BYTE_STRIDE(range_type) TYPE_RANGE_DATA(range_type)->byte_stride.u.constant
#define TYPE_LOW_BOUND_UNDEFINED(range_type) \
TYPE_RANGE_DATA(range_type)->low_undefined
#define TYPE_HIGH_BOUND_UNDEFINED(range_type) \
TYPE_RANGE_DATA(range_type)->high_undefined
+#define TYPE_LOW_BOUND_IS_DWARF_BLOCK(range_type) \
+ TYPE_RANGE_DATA(range_type)->low.is_dwarf_block
+#define TYPE_HIGH_BOUND_IS_DWARF_BLOCK(range_type) \
+ TYPE_RANGE_DATA(range_type)->high.is_dwarf_block
+#define TYPE_BYTE_STRIDE_IS_DWARF_BLOCK(range_type) \
+ TYPE_RANGE_DATA(range_type)->byte_stride.is_dwarf_block
/* Moto-specific stuff for FORTRAN arrays */
@@ -928,11 +1014,23 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED(arraytype) \
TYPE_LOW_BOUND_UNDEFINED(TYPE_INDEX_TYPE(arraytype))
+#define TYPE_ARRAY_UPPER_BOUND_IS_DWARF_BLOCK(arraytype) \
+ TYPE_HIGH_BOUND_IS_DWARF_BLOCK(TYPE_INDEX_TYPE(arraytype))
+#define TYPE_ARRAY_LOWER_BOUND_IS_DWARF_BLOCK(arraytype) \
+ TYPE_LOW_BOUND_IS_DWARF_BLOCK(TYPE_INDEX_TYPE(arraytype))
+
#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \
(TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype))))
#define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \
- (TYPE_LOW_BOUND(TYPE_INDEX_TYPE((arraytype))))
+ TYPE_LOW_BOUND (TYPE_INDEX_TYPE (arraytype))
+
+/* TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) with a fallback to the
+ element size if no specific stride value is known. */
+#define TYPE_ARRAY_BYTE_STRIDE_VALUE(arraytype) \
+ (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) == 0 \
+ ? TYPE_LENGTH (TYPE_TARGET_TYPE (arraytype)) \
+ : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)))
/* C++ */
@@ -961,6 +1059,7 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_GNAT_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.gnat_stuff
#define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type
#define TYPE_CALLING_CONVENTION(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.calling_convention
+#define TYPE_MODULE_BLOCK(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.module_block
#define TYPE_BASECLASS(thistype,index) TYPE_FIELD_TYPE(thistype, index)
#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
#define TYPE_BASECLASS_NAME(thistype,index) TYPE_FIELD_NAME(thistype, index)
@@ -979,7 +1078,6 @@ extern void allocate_gnat_aux_type (struct type *);
#define FIELD_BITPOS(thisfld) ((thisfld).loc.bitpos)
#define FIELD_STATIC_PHYSNAME(thisfld) ((thisfld).loc.physname)
#define FIELD_STATIC_PHYSADDR(thisfld) ((thisfld).loc.physaddr)
-#define FIELD_DWARF_BLOCK(thisfld) ((thisfld).loc.dwarf_block)
#define SET_FIELD_BITPOS(thisfld, bitpos) \
(FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_BITPOS, \
FIELD_BITPOS (thisfld) = (bitpos))
@@ -989,9 +1087,6 @@ extern void allocate_gnat_aux_type (struct type *);
#define SET_FIELD_PHYSADDR(thisfld, addr) \
(FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_PHYSADDR, \
FIELD_STATIC_PHYSADDR (thisfld) = (addr))
-#define SET_FIELD_DWARF_BLOCK(thisfld, addr) \
- (FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_DWARF_BLOCK, \
- FIELD_DWARF_BLOCK (thisfld) = (addr))
#define FIELD_ARTIFICIAL(thisfld) ((thisfld).artificial)
#define FIELD_BITSIZE(thisfld) ((thisfld).bitsize)
@@ -1002,7 +1097,6 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_FIELD_BITPOS(thistype, n) FIELD_BITPOS (TYPE_FIELD (thistype, n))
#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) FIELD_STATIC_PHYSNAME (TYPE_FIELD (thistype, n))
#define TYPE_FIELD_STATIC_PHYSADDR(thistype, n) FIELD_STATIC_PHYSADDR (TYPE_FIELD (thistype, n))
-#define TYPE_FIELD_DWARF_BLOCK(thistype, n) FIELD_DWARF_BLOCK (TYPE_FIELD (thistype, n))
#define TYPE_FIELD_ARTIFICIAL(thistype, n) FIELD_ARTIFICIAL(TYPE_FIELD(thistype,n))
#define TYPE_FIELD_BITSIZE(thistype, n) FIELD_BITSIZE(TYPE_FIELD(thistype,n))
#define TYPE_FIELD_PACKED(thistype, n) (FIELD_BITSIZE(TYPE_FIELD(thistype,n))!=0)
@@ -1333,6 +1427,18 @@ extern struct type *create_array_type (struct type *, struct type *,
struct type *);
extern struct type *lookup_array_range_type (struct type *, int, int);
+extern CORE_ADDR type_range_any_field_internal (struct type *range_type,
+ int fieldno);
+
+extern int type_range_high_bound_internal (struct type *range_type);
+
+extern int type_range_count_bound_internal (struct type *range_type);
+
+extern CORE_ADDR type_range_byte_stride_internal (struct type *range_type,
+ struct type *element_type);
+
+extern void finalize_type (struct type *type);
+
extern struct type *create_string_type (struct type *, struct type *,
struct type *);
extern struct type *lookup_string_range_type (struct type *, int, int);
@@ -1369,6 +1475,8 @@ extern int get_discrete_bounds (struct type *, LONGEST *, LONGEST *);
extern int is_ancestor (struct type *, struct type *);
+extern void type_mark_used (struct type *type);
+
/* Overload resolution */
#define LENGTH_MATCH(bv) ((bv)->rank[0])
@@ -1431,10 +1539,11 @@ extern void maintenance_print_type (char *, int);
extern htab_t create_copied_types_hash (struct objfile *objfile);
-extern struct type *copy_type_recursive (struct objfile *objfile,
- struct type *type,
+extern struct type *copy_type_recursive (struct type *type,
htab_t copied_types);
extern struct type *copy_type (const struct type *type);
+extern void free_all_types (void);
+
#endif /* GDBTYPES_H */
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index ff837f2..1710487 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -696,6 +696,21 @@ i386_linux_dr_unset_status (unsigned long mask)
}
}
+/* See i386_dr_low_type.detach. Do not use wrappers i386_linux_dr_set_control
+ or i386_linux_dr_reset_addr as they would modify the register cache
+ (i386_linux_dr). */
+
+static void
+i386_linux_dr_detach (void)
+{
+ int regnum;
+
+ i386_linux_dr_set (inferior_ptid, DR_CONTROL, 0);
+ i386_linux_dr_unset_status (~0UL);
+ for (regnum = DR_FIRSTADDR; regnum <= DR_LASTADDR; regnum++)
+ i386_linux_dr_set (inferior_ptid, regnum, 0);
+}
+
static void
i386_linux_new_thread (ptid_t ptid)
{
@@ -868,6 +883,7 @@ _initialize_i386_linux_nat (void)
i386_dr_low.reset_addr = i386_linux_dr_reset_addr;
i386_dr_low.get_status = i386_linux_dr_get_status;
i386_dr_low.unset_status = i386_linux_dr_unset_status;
+ i386_dr_low.detach = i386_linux_dr_detach;
i386_set_debug_register_length (4);
/* Override the default ptrace resume method. */
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index fa0cce6..42dfd1c 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -527,6 +527,17 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type)
return retval;
}
+/* See target_detach_watchpoints. */
+
+static int
+i386_detach_watchpoints (void)
+{
+ if (i386_dr_low.detach)
+ i386_dr_low.detach ();
+
+ return 0;
+}
+
/* Return non-zero if we can watch a memory region that starts at
address ADDR and whose length is LEN bytes. */
@@ -679,6 +690,7 @@ i386_use_watchpoints (struct target_ops *t)
t->to_stopped_data_address = i386_stopped_data_address;
t->to_insert_watchpoint = i386_insert_watchpoint;
t->to_remove_watchpoint = i386_remove_watchpoint;
+ t->to_detach_watchpoints = i386_detach_watchpoints;
t->to_insert_hw_breakpoint = i386_insert_hw_breakpoint;
t->to_remove_hw_breakpoint = i386_remove_hw_breakpoint;
}
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 7317e7d..ea914a5 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -62,6 +62,10 @@ extern void i386_use_watchpoints (struct target_ops *);
unset_status -- unset the specified bits of the debug
status (DR6) register for all LWPs
+ detach -- clear all debug registers of only the
+ INFERIOR_PTID task without affecting any
+ register caches.
+
Additionally, the native file should set the debug_register_length
field to 4 or 8 depending on the number of bytes used for
deubg registers. */
@@ -73,6 +77,7 @@ struct i386_dr_low_type
void (*reset_addr) (int);
unsigned long (*get_status) (void);
void (*unset_status) (unsigned long);
+ void (*detach) (void);
int debug_register_length;
};
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 21a2233..34a3718 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -805,7 +805,7 @@ nexti_command (char *count_string, int from_tty)
step_1 (1, 1, count_string);
}
-static void
+void
delete_longjmp_breakpoint_cleanup (void *arg)
{
int thread = * (int *) arg;
@@ -845,10 +845,13 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
if (!single_inst || skip_subroutines) /* leave si command alone */
{
+ struct thread_info *tp = inferior_thread ();
+
if (in_thread_list (inferior_ptid))
thread = pid_to_thread_id (inferior_ptid);
set_longjmp_breakpoint (thread);
+ tp->initiating_frame = get_frame_id (get_current_frame ());
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
@@ -1197,6 +1200,15 @@ signal_command (char *signum_exp, int from_tty)
proceed ((CORE_ADDR) -1, oursig, 0);
}
+/* A continuation callback for until_next_command. */
+
+static void
+until_next_continuation (void *arg)
+{
+ struct thread_info *tp = arg;
+ delete_longjmp_breakpoint (tp->num);
+}
+
/* Proceed until we reach a different source line with pc greater than
our current one or exit the function. We skip calls in both cases.
@@ -1213,6 +1225,8 @@ until_next_command (int from_tty)
struct symbol *func;
struct symtab_and_line sal;
struct thread_info *tp = inferior_thread ();
+ int thread = tp->num;
+ struct cleanup *old_chain;
clear_proceed_status ();
set_step_frame ();
@@ -1248,7 +1262,19 @@ until_next_command (int from_tty)
tp->step_multi = 0; /* Only one call to proceed */
+ set_longjmp_breakpoint (thread);
+ tp->initiating_frame = get_frame_id (frame);
+ old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
+
+ if (target_can_async_p () && is_running (inferior_ptid))
+ {
+ discard_cleanups (old_chain);
+ add_continuation (tp, until_next_continuation, tp, NULL);
+ }
+ else
+ do_cleanups (old_chain);
}
static void
@@ -1425,6 +1451,7 @@ finish_command_continuation (void *arg)
if (bs != NULL && tp->proceed_to_finish)
observer_notify_normal_stop (bs, 1 /* print frame */);
delete_breakpoint (a->breakpoint);
+ delete_longjmp_breakpoint (inferior_thread ()->num);
}
static void
@@ -1508,6 +1535,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
struct breakpoint *breakpoint;
struct cleanup *old_chain;
struct finish_command_continuation_args *cargs;
+ int thread = tp->num;
sal = find_pc_line (get_frame_pc (frame), 0);
sal.pc = get_frame_pc (frame);
@@ -1518,6 +1546,10 @@ finish_forward (struct symbol *function, struct frame_info *frame)
old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ set_longjmp_breakpoint (thread);
+ tp->initiating_frame = get_frame_id (frame);
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+
tp->proceed_to_finish = 1; /* We want stop_registers, please... */
cargs = xmalloc (sizeof (*cargs));
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 9798ef1..e9783fb 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -279,6 +279,8 @@ extern void interrupt_target_command (char *args, int from_tty);
extern void interrupt_target_1 (int all_threads);
+extern void delete_longjmp_breakpoint_cleanup (void *arg);
+
extern void detach_command (char *, int);
extern void notice_new_inferior (ptid_t, int, int);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 426b816..bd65258 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -45,6 +45,8 @@
#include "language.h"
#include "solib.h"
#include "main.h"
+#include "dictionary.h"
+#include "block.h"
#include "gdb_assert.h"
#include "mi/mi-common.h"
#include "event-top.h"
@@ -2013,6 +2015,8 @@ static void insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
struct symtab_and_line sr_sal,
struct frame_id sr_id);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
+static void check_exception_resume (struct execution_control_state *,
+ struct frame_info *, struct symbol *);
static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
@@ -2942,6 +2946,10 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Clear WATCHPOINT_TRIGGERED values from previous stop which could
+ confuse bpstat_stop_status and bpstat_explains_signal. */
+ watchpoints_triggered (&ecs->ws);
+
ecs->event_thread->stop_bpstat
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
stop_pc, ecs->ptid);
@@ -3026,6 +3034,10 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Clear WATCHPOINT_TRIGGERED values from previous stop which could
+ confuse bpstat_stop_status and bpstat_explains_signal. */
+ watchpoints_triggered (&ecs->ws);
+
/* Do whatever is necessary to the parent branch of the vfork. */
handle_vfork_child_exec_or_exit (1);
@@ -3784,23 +3796,33 @@ process_event_stop_test:
ecs->event_thread->stepping_over_breakpoint = 1;
- if (!gdbarch_get_longjmp_target_p (gdbarch)
- || !gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc))
+ if (what.is_longjmp)
{
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "\
+ if (!gdbarch_get_longjmp_target_p (gdbarch)
+ || !gdbarch_get_longjmp_target (gdbarch,
+ frame, &jmp_buf_pc))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "\
infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
- keep_going (ecs);
- return;
- }
+ keep_going (ecs);
+ return;
+ }
- /* We're going to replace the current step-resume breakpoint
- with a longjmp-resume breakpoint. */
- delete_step_resume_breakpoint (ecs->event_thread);
+ /* We're going to replace the current step-resume breakpoint
+ with a longjmp-resume breakpoint. */
+ delete_step_resume_breakpoint (ecs->event_thread);
- /* Insert a breakpoint at resume address. */
- insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
+ /* Insert a breakpoint at resume address. */
+ insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
+ }
+ else
+ {
+ struct symbol *func = get_frame_function (frame);
+ if (func)
+ check_exception_resume (ecs, frame, func);
+ }
keep_going (ecs);
return;
@@ -3812,6 +3834,53 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL);
delete_step_resume_breakpoint (ecs->event_thread);
+ if (!what.is_longjmp)
+ {
+ /* There are several cases to consider.
+
+ 1. The initiating frame no longer exists. In this case
+ we must stop, because the exception has gone too far.
+
+ 2. The initiating frame exists, and is the same as the
+ current frame.
+
+ 2.1. If we are stepping, defer to the stepping logic.
+
+ 2.2. Otherwise, we are not stepping, so we are doing a
+ "finish" and we have reached the calling frame. So,
+ stop.
+
+ 3. The initiating frame exists and is different from
+ the current frame. This means the exception has been
+ caught beneath the initiating frame, so keep going. */
+ struct frame_info *init_frame
+ = frame_find_by_id (ecs->event_thread->initiating_frame);
+ if (init_frame)
+ {
+ struct frame_id current_id
+ = get_frame_id (get_current_frame ());
+ if (frame_id_eq (current_id,
+ ecs->event_thread->initiating_frame))
+ {
+ if (ecs->event_thread->step_range_start)
+ {
+ /* Case 2.1. */
+ break;
+ }
+ else
+ {
+ /* Case 2.2: fall through. */
+ }
+ }
+ else
+ {
+ /* Case 3. */
+ keep_going (ecs);
+ return;
+ }
+ }
+ }
+
ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -4831,6 +4900,96 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume);
}
+/* Insert an exception resume breakpoint. TP is the thread throwing
+ the exception. The block B is the block of the unwinder debug hook
+ function. FRAME is the frame corresponding to the call to this
+ function. SYM is the symbol of the function argument holding the
+ target PC of the exception. */
+
+static void
+insert_exception_resume_breakpoint (struct thread_info *tp,
+ struct block *b,
+ struct frame_info *frame,
+ struct symbol *sym)
+{
+ struct gdb_exception e;
+
+ /* We want to ignore errors here. */
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ struct symbol *vsym;
+ struct value *value;
+ CORE_ADDR handler;
+ struct breakpoint *bp;
+
+ vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+ value = read_var_value (vsym, frame);
+ handler = value_as_address (value);
+
+ /* We're going to replace the current step-resume breakpoint
+ with an exception-resume breakpoint. */
+ delete_step_resume_breakpoint (tp);
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: exception resume at %lx\n",
+ (unsigned long) handler);
+
+ bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+ handler, bp_exception_resume);
+ inferior_thread ()->step_resume_breakpoint = bp;
+ }
+}
+
+/* This is called when an exception has been intercepted. Check to
+ see whether the exception's destination is of interest, and if so,
+ set an exception resume breakpoint there. */
+
+static void
+check_exception_resume (struct execution_control_state *ecs,
+ struct frame_info *frame, struct symbol *func)
+{
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ALL)
+ {
+ struct block *b;
+ struct dict_iterator iter;
+ struct symbol *sym;
+ int argno = 0;
+
+ /* The exception breakpoint is a thread-specific breakpoint on
+ the unwinder's debug hook, declared as:
+
+ void _Unwind_DebugHook (void *cfa, void *handler);
+
+ The CFA argument indicates the frame to which control is
+ about to be transferred. HANDLER is the destination PC.
+
+ We ignore the CFA and set a temporary breakpoint at HANDLER.
+ This is not extremely efficient but it avoids issues in gdb
+ with computing the DWARF CFA, and it also works even in weird
+ cases such as throwing an exception from inside a signal
+ handler. */
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ if (!SYMBOL_IS_ARGUMENT (sym))
+ continue;
+
+ if (argno == 0)
+ ++argno;
+ else
+ {
+ insert_exception_resume_breakpoint (ecs->event_thread,
+ b, frame, sym);
+ break;
+ }
+ }
+ }
+}
+
static void
stop_stepping (struct execution_control_state *ecs)
{
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 24b6673..22ed960 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1121,6 +1121,7 @@ const struct exp_descriptor exp_descriptor_java =
{
print_subexp_standard,
operator_length_standard,
+ operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_java
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 03563cd..8145629 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -2643,6 +2643,39 @@ linux_nat_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
return lp->stopped_data_address_p;
}
+/* In `set follow-fork-mode child' with multithreaded parent we need to detach
+ watchpoints from all the LWPs. In such case INFERIOR_PTID will be the
+ non-threaded new child while LWP_LIST will still contain all the threads of
+ the parent being detached. */
+
+static int
+linux_nat_detach_watchpoints (void)
+{
+ struct lwp_info *lp;
+ int found = 0, retval = 0;
+ ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ for (lp = lwp_list; lp; lp = lp->next)
+ if (ptid_match (lp->ptid, filter))
+ {
+ inferior_ptid = lp->ptid;
+ retval |= linux_ops->to_detach_watchpoints ();
+ found = 1;
+ }
+
+ do_cleanups (old_chain);
+
+ if (!found)
+ {
+ gdb_assert (!is_lwp (inferior_ptid));
+
+ retval |= linux_ops->to_detach_watchpoints ();
+ }
+
+ return retval;
+}
+
/* Wait until LP is stopped. */
static int
@@ -5519,6 +5552,8 @@ linux_nat_add_target (struct target_ops *t)
t->to_thread_address_space = linux_nat_thread_address_space;
t->to_stopped_by_watchpoint = linux_nat_stopped_by_watchpoint;
t->to_stopped_data_address = linux_nat_stopped_data_address;
+ if (linux_ops->to_detach_watchpoints)
+ t->to_detach_watchpoints = linux_nat_detach_watchpoints;
t->to_can_async_p = linux_nat_can_async_p;
t->to_is_async_p = linux_nat_is_async_p;
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 80e9bf9..3057774 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -356,6 +356,7 @@ const struct exp_descriptor exp_descriptor_modula2 =
{
print_subexp_standard,
operator_length_standard,
+ operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_modula2
diff --git a/gdb/machoread.c b/gdb/machoread.c
index 02b61d3..13ab595 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -755,6 +755,7 @@ static struct sym_fns macho_sym_fns = {
macho_new_init, /* sym_new_init: init anything gbl to entire symtab */
macho_symfile_init, /* sym_init: read initial info, setup for sym_read() */
macho_symfile_read, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
macho_symfile_finish, /* sym_finish: finished with file, cleanup */
macho_symfile_offsets, /* sym_offsets: xlate external to internal form */
default_symfile_segments, /* sym_segments: Get segment information from
diff --git a/gdb/main.c b/gdb/main.c
index 0cc0f75..e3fc2e6 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -40,6 +40,7 @@
#include "interps.h"
#include "main.h"
+#include "python/python.h"
#include "source.h"
/* If nonzero, display time usage both at startup and for each command. */
@@ -259,6 +260,8 @@ captured_main (void *data)
char *cdarg = NULL;
char *ttyarg = NULL;
+ int python_script = 0;
+
/* These are static so that we can take their address in an initializer. */
static int print_help;
static int print_version;
@@ -434,10 +437,14 @@ captured_main (void *data)
{"args", no_argument, &set_args, 1},
{"l", required_argument, 0, 'l'},
{"return-child-result", no_argument, &return_child_result, 1},
+#if HAVE_PYTHON
+ {"python", no_argument, 0, 'P'},
+ {"P", no_argument, 0, 'P'},
+#endif
{0, no_argument, 0, 0}
};
- while (1)
+ while (!python_script)
{
int option_index;
@@ -455,6 +462,9 @@ captured_main (void *data)
case 0:
/* Long option that just sets a flag. */
break;
+ case 'P':
+ python_script = 1;
+ break;
case OPT_SE:
symarg = optarg;
execarg = optarg;
@@ -631,7 +641,31 @@ extern int gdbtk_test (char *);
use_windows = 0;
}
- if (set_args)
+ if (python_script)
+ {
+ /* The first argument is a python script to evaluate, and
+ subsequent arguments are passed to the script for
+ processing there. */
+ if (optind >= argc)
+ {
+ fprintf_unfiltered (gdb_stderr,
+ _("%s: Python script file name required\n"),
+ argv[0]);
+ exit (1);
+ }
+
+ /* FIXME: should handle inferior I/O intelligently here.
+ E.g., should be possible to run gdb in pipeline and have
+ Python (and gdb) output go to stderr or file; and if a
+ prompt is needed, open the tty. */
+ quiet = 1;
+ /* FIXME: should read .gdbinit if, and only if, a prompt is
+ requested by the script. Though... maybe this is not
+ ideal? */
+ /* FIXME: likewise, reading in history. */
+ inhibit_gdbinit = 1;
+ }
+ else if (set_args)
{
/* The remaining options are the command-line options for the
inferior. The first one is the sym/exec file, and the rest
@@ -864,7 +898,8 @@ Can't attach to process and specify a core file at the same time."));
xfree (cmdarg);
/* Read in the old history after all the command files have been read. */
- init_history ();
+ if (!python_script)
+ init_history ();
if (batch)
{
@@ -893,13 +928,25 @@ Can't attach to process and specify a core file at the same time."));
#endif
}
- /* NOTE: cagney/1999-11-07: There is probably no reason for not
- moving this loop and the code found in captured_command_loop()
- into the command_loop() proper. The main thing holding back that
- change - SET_TOP_LEVEL() - has been eliminated. */
- while (1)
+#if HAVE_PYTHON
+ if (python_script)
{
- catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
+ extern int pagination_enabled;
+ pagination_enabled = 0;
+ run_python_script (argc - optind, &argv[optind]);
+ return 1;
+ }
+ else
+#endif
+ {
+ /* NOTE: cagney/1999-11-07: There is probably no reason for not
+ moving this loop and the code found in captured_command_loop()
+ into the command_loop() proper. The main thing holding back that
+ change - SET_TOP_LEVEL() - has been eliminated. */
+ while (1)
+ {
+ catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
+ }
}
/* No exit -- exit is through quit_command. */
}
@@ -931,7 +978,12 @@ print_gdb_help (struct ui_file *stream)
fputs_unfiltered (_("\
This is the GNU debugger. Usage:\n\n\
gdb [options] [executable-file [core-file or process-id]]\n\
- gdb [options] --args executable-file [inferior-arguments ...]\n\n\
+ gdb [options] --args executable-file [inferior-arguments ...]\n"), stream);
+#if HAVE_PYTHON
+ fputs_unfiltered (_("\
+ gdb [options] [--python|-P] script-file [script-arguments ...]\n"), stream);
+#endif
+ fputs_unfiltered (_("\n\
Options:\n\n\
"), stream);
fputs_unfiltered (_("\
@@ -969,7 +1021,13 @@ Options:\n\n\
--nw Do not use a window interface.\n\
--nx Do not read "), stream);
fputs_unfiltered (gdbinit, stream);
- fputs_unfiltered (_(" file.\n\
+ fputs_unfiltered (_(" file.\n"), stream);
+#if HAVE_PYTHON
+ fputs_unfiltered (_("\
+ --python, -P Following argument is Python script file; remaining\n\
+ arguments are passed to script.\n"), stream);
+#endif
+ fputs_unfiltered (_("\
--quiet Do not print version number on startup.\n\
--readnow Fully read symbol files on first access.\n\
"), stream);
diff --git a/gdb/maint.c b/gdb/maint.c
index 4316d66..fe8a069 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -914,4 +914,12 @@ When enabled GDB is profiled."),
show_maintenance_profile_p,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+ add_setshow_filename_cmd ("gdb_datadir", class_maintenance,
+ &gdb_datadir, _("Set GDB's datadir path."),
+ _("Show GDB's datadir path."),
+ _("\
+When set, GDB uses the specified path to search for data files."),
+ NULL, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
}
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index b227411..3b932f0 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -697,7 +697,6 @@ mi_cmd_var_update (char *command, char **argv, int argc)
}
else
{
- /* Get varobj handle, if a valid var obj name was specified */
struct varobj *var = varobj_get_handle (name);
varobj_update_one (var, print_values, 1 /* explicit */);
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index dde0062..832cfcc 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -1400,7 +1400,7 @@ mi_cmd_list_features (char *command, char **argv, int argc)
ui_out_field_string (uiout, NULL, "frozen-varobjs");
ui_out_field_string (uiout, NULL, "pending-breakpoints");
ui_out_field_string (uiout, NULL, "thread-info");
-
+
#if HAVE_PYTHON
ui_out_field_string (uiout, NULL, "python");
#endif
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index 4ef817e..1c53574 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -394,6 +394,7 @@ static struct sym_fns ecoff_sym_fns =
mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */
mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */
default_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */
default_symfile_segments, /* sym_segments: Get segment information from
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 0b07e37..5de5300 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -789,6 +789,10 @@ objfile_relocate1 (struct objfile *objfile, struct section_offsets *new_offsets)
}
}
+ if (objfile->quick_addrmap)
+ addrmap_relocate (objfile->quick_addrmap,
+ ANOFFSET (delta, SECT_OFF_TEXT (objfile)));
+
{
struct partial_symbol **psym;
@@ -914,7 +918,7 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets)
int
objfile_has_partial_symbols (struct objfile *objfile)
{
- return objfile->psymtabs != NULL;
+ return objfile->psymtabs != NULL || objfile->quick_addrmap;
}
/* Return non-zero if OBJFILE has full symbols. */
@@ -954,6 +958,20 @@ have_partial_symbols (void)
if (objfile_has_partial_symbols (ofp))
return 1;
}
+
+ /* Try again, after reading partial symbols. We do this in two
+ passes because objfiles are always added to the head of the list,
+ and there might be a later objfile for which we've already read
+ partial symbols. */
+ ALL_OBJFILES (ofp)
+ {
+ require_partial_symbols (ofp);
+ if (ofp->psymtabs != NULL)
+ {
+ return 1;
+ }
+ }
+
return 0;
}
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index c689622..eb3ae10 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -213,6 +213,11 @@ struct objfile
struct partial_symtab *psymtabs;
+ /* An address map that can be used to quickly determine if an
+ address comes from this objfile. This can be NULL. */
+
+ struct addrmap *quick_addrmap;
+
/* Map addresses to the entries of PSYMTABS. It would be more efficient to
have a map per the whole process but ADDRMAP cannot selectively remove
its items during FREE_OBJFILE. This mapping is already present even for
@@ -426,6 +431,15 @@ struct objfile
#define OBJF_USERLOADED (1 << 3) /* User loaded */
+/* Set if we have tried to read partial symtabs for this objfile.
+ This is used to allow lazy reading of partial symtabs. */
+
+#define OBJF_SYMTABS_READ (1 << 6)
+
+/* This flag is set for the main objfile. */
+
+#define OBJF_MAIN (1 << 7)
+
/* The object file that contains the runtime common minimal symbols
for SunOS4. Note that this objfile has no associated BFD. */
@@ -606,6 +620,13 @@ extern void gdb_bfd_unref (struct bfd *abfd);
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
+/* Like ALL_PSYMTABS, but ensure that partial symbols have been read
+ before examining the objfile. */
+
+#define ALL_PSYMTABS_REQUIRED(objfile, p) \
+ ALL_OBJFILES (objfile) \
+ ALL_OBJFILE_PSYMTABS (require_partial_symbols (objfile), p)
+
#define ALL_PSPACE_PSYMTABS(ss, objfile, p) \
ALL_PSPACE_OBJFILES (ss, objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
diff --git a/gdb/parse.c b/gdb/parse.c
index 2885506..779b819 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -62,6 +62,7 @@ const struct exp_descriptor exp_descriptor_standard =
{
print_subexp_standard,
operator_length_standard,
+ operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_subexp_standard
@@ -1359,6 +1360,150 @@ parser_fprintf (FILE *x, const char *y, ...)
va_end (args);
}
+/* Implementation of the exp_descriptor method operator_check. */
+
+int
+operator_check_standard (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
+ int (*objfile_func) (struct objfile *objfile,
+ void *data),
+ void *data)
+{
+ const union exp_element *const elts = exp->elts;
+ struct type *type = NULL;
+ struct objfile *objfile = NULL;
+
+ /* Extended operators should have been already handled by exp_descriptor
+ iterate method of its specific language. */
+ gdb_assert (elts[pos].opcode < OP_EXTENDED0);
+
+ /* Track the callers of write_exp_elt_type for this table. */
+
+ switch (elts[pos].opcode)
+ {
+ case BINOP_VAL:
+ case OP_COMPLEX:
+ case OP_DECFLOAT:
+ case OP_DOUBLE:
+ case OP_LONG:
+ case OP_SCOPE:
+ case OP_TYPE:
+ case UNOP_CAST:
+ case UNOP_MAX:
+ case UNOP_MEMVAL:
+ case UNOP_MIN:
+ type = elts[pos + 1].type;
+ break;
+
+ case UNOP_MEMVAL_TLS:
+ objfile = elts[pos + 1].objfile;
+ type = elts[pos + 2].type;
+ break;
+
+ case OP_VAR_VALUE:
+ {
+ const struct block *const block = elts[pos + 1].block;
+ const struct symbol *const symbol = elts[pos + 2].symbol;
+ const struct obj_section *const section = SYMBOL_OBJ_SECTION (symbol);
+
+ /* Check objfile where the variable itself is placed. */
+ if (section && objfile_func && (*objfile_func) (section->objfile, data))
+ return 1;
+
+ /* Check objfile where is placed the code touching the variable. */
+ objfile = block_objfile (block);
+
+ type = SYMBOL_TYPE (symbol);
+ }
+ break;
+ }
+
+ /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */
+
+ if (type && type_func && (*type_func) (type, data))
+ return 1;
+ if (type && TYPE_OBJFILE (type) && objfile_func
+ && (*objfile_func) (TYPE_OBJFILE (type), data))
+ return 1;
+ if (objfile && objfile_func && (*objfile_func) (objfile, data))
+ return 1;
+
+ return 0;
+}
+
+/* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being
+ referenced by EXP. The functions are never called with NULL TYPE or NULL
+ OBJFILE. Functions get passed an arbitrary caller supplied DATA pointer.
+ If any of the functions returns non-zero value then (any other) non-zero
+ value is immediately returned to the caller. Otherwise zero is returned
+ after iterating through whole EXP. */
+
+static int
+exp_iterate (struct expression *exp,
+ int (*type_func) (struct type *type, void *data),
+ int (*objfile_func) (struct objfile *objfile, void *data),
+ void *data)
+{
+ int endpos;
+ const union exp_element *const elts = exp->elts;
+
+ for (endpos = exp->nelts; endpos > 0; )
+ {
+ int pos, args, oplen = 0;
+
+ exp->language_defn->la_exp_desc->operator_length (exp, endpos,
+ &oplen, &args);
+ gdb_assert (oplen > 0);
+
+ pos = endpos - oplen;
+ if (exp->language_defn->la_exp_desc->operator_check (exp, pos, type_func,
+ objfile_func, data))
+ return 1;
+
+ endpos = pos;
+ }
+
+ return 0;
+}
+
+/* Helper for exp_uses_objfile. */
+
+static int
+exp_uses_objfile_iter (struct objfile *exp_objfile, void *objfile_voidp)
+{
+ struct objfile *objfile = objfile_voidp;
+
+ return exp_objfile == objfile;
+}
+
+/* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE
+ is unloaded), otherwise return 0. */
+
+int
+exp_uses_objfile (struct expression *exp, struct objfile *objfile)
+{
+ return exp_iterate (exp, NULL, exp_uses_objfile_iter, objfile);
+}
+
+/* Helper for exp_types_mark_used. */
+
+static int
+exp_types_mark_used_iter (struct type *type, void *unused)
+{
+ type_mark_used (type);
+
+ /* Continue the traversal. */
+ return 0;
+}
+
+/* Call type_mark_used for any TYPE contained in EXP. */
+
+void
+exp_types_mark_used (struct expression *exp)
+{
+ exp_iterate (exp, exp_types_mark_used_iter, NULL, NULL);
+}
+
void
_initialize_parse (void)
{
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 6fcf7ae..3f5efe8 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -190,6 +190,13 @@ extern void operator_length (struct expression *, int, int *, int *);
extern void operator_length_standard (struct expression *, int, int *, int *);
+extern int operator_check_standard (struct expression *exp, int pos,
+ int (*type_func) (struct type *type,
+ void *data),
+ int (*objfile_func)
+ (struct objfile *objfile, void *data),
+ void *data);
+
extern char *op_name_standard (enum exp_opcode);
extern struct type *follow_types (struct type *);
@@ -268,6 +275,20 @@ struct exp_descriptor
the number of subexpressions it takes. */
void (*operator_length) (struct expression*, int, int*, int *);
+ /* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being
+ referenced by the single operator of EXP at position POS. Operator
+ parameters are located at positive (POS + number) offsets in EXP.
+ The functions should never be called with NULL TYPE or NULL OBJFILE.
+ Functions should get passed an arbitrary caller supplied DATA pointer.
+ If any of the functions returns non-zero value then (any other) non-zero
+ value should be immediately returned to the caller. Otherwise zero
+ should be returned. */
+ int (*operator_check) (struct expression *exp, int pos,
+ int (*type_func) (struct type *type, void *data),
+ int (*objfile_func) (struct objfile *objfile,
+ void *data),
+ void *data);
+
/* Name of this operator for dumping purposes. */
char *(*op_name) (enum exp_opcode);
@@ -300,4 +321,8 @@ extern void print_subexp_standard (struct expression *, int *,
extern void parser_fprintf (FILE *, const char *, ...) ATTR_FORMAT (printf, 2 ,3);
+extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
+
+extern void exp_types_mark_used (struct expression *exp);
+
#endif /* PARSER_DEFS_H */
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 10ff73d..5b68f56 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1391,6 +1391,24 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
return 0;
}
+/* See target_detach_watchpoints. Do not use wrapper
+ ppc_linux_remove_watchpoint as it would modify the register cache
+ (saved_dabr_value). */
+
+static int
+ppc_linux_detach_watchpoints (void)
+{
+ pid_t tid;
+
+ tid = TIDGET (inferior_ptid);
+ if (tid == 0)
+ tid = PIDGET (inferior_ptid);
+
+ if (ptrace (PTRACE_SET_DEBUGREG, tid, NULL, NULL) < 0)
+ return -1;
+ return 0;
+}
+
static void
ppc_linux_new_thread (ptid_t ptid)
{
@@ -1648,6 +1666,7 @@ _initialize_ppc_linux_nat (void)
t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+ t->to_detach_watchpoints = ppc_linux_detach_watchpoints;
t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
t->to_stopped_data_address = ppc_linux_stopped_data_address;
t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 88db08b..18dae9e 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -46,7 +46,6 @@
#include "exceptions.h"
#include "observer.h"
#include "solist.h"
-#include "solib.h"
#include "parser-defs.h"
#include "charset.h"
#include "arch-utils.h"
@@ -941,6 +940,11 @@ print_command_1 (char *exp, int inspect, int voidprint)
else
val = access_value_history (0);
+ /* Do not try to OBJECT_ADDRESS_SET here anything. We are interested in the
+ source variable base addresses as found by READ_VAR_VALUE. The value here
+ can be already a calculated expression address inappropriate for
+ DW_OP_push_object_address. */
+
if (voidprint || (val && value_type (val) &&
TYPE_CODE (value_type (val)) != TYPE_CODE_VOID))
{
@@ -1437,6 +1441,22 @@ x_command (char *exp, int from_tty)
set_internalvar (lookup_internalvar ("__"), last_examine_value);
}
}
+
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+print_types_mark_used (void)
+{
+ struct display *d;
+
+ if (last_examine_value)
+ type_mark_used (value_type (last_examine_value));
+
+ for (d = display_chain; d; d = d->next)
+ if (d->exp)
+ exp_types_mark_used (d->exp);
+}
+
/* Add an expression to the auto-display chain.
@@ -1859,52 +1879,6 @@ disable_display_command (char *args, int from_tty)
}
}
-/* Return 1 if D uses SOLIB (and will become dangling when SOLIB
- is unloaded), otherwise return 0. */
-
-static int
-display_uses_solib_p (const struct display *d,
- const struct so_list *solib)
-{
- int endpos;
- struct expression *const exp = d->exp;
- const union exp_element *const elts = exp->elts;
-
- if (d->block != NULL
- && d->pspace == solib->pspace
- && solib_contains_address_p (solib, d->block->startaddr))
- return 1;
-
- for (endpos = exp->nelts; endpos > 0; )
- {
- int i, args, oplen = 0;
-
- exp->language_defn->la_exp_desc->operator_length (exp, endpos,
- &oplen, &args);
- gdb_assert (oplen > 0);
-
- i = endpos - oplen;
- if (elts[i].opcode == OP_VAR_VALUE)
- {
- const struct block *const block = elts[i + 1].block;
- const struct symbol *const symbol = elts[i + 2].symbol;
- const struct obj_section *const section =
- SYMBOL_OBJ_SECTION (symbol);
-
- if (block != NULL
- && solib_contains_address_p (solib,
- block->startaddr))
- return 1;
-
- if (section && section->objfile == solib->objfile)
- return 1;
- }
- endpos -= oplen;
- }
-
- return 0;
-}
-
/* display_chain items point to blocks and expressions. Some expressions in
turn may point to symbols.
Both symbols and blocks are obstack_alloc'd on objfile_stack, and are
@@ -1916,18 +1890,20 @@ display_uses_solib_p (const struct display *d,
static void
clear_dangling_display_expressions (struct so_list *solib)
{
+ struct objfile *objfile = solib->objfile;
struct display *d;
- struct objfile *objfile = NULL;
- for (d = display_chain; d; d = d->next)
- {
- if (d->exp && display_uses_solib_p (d, solib))
- {
- xfree (d->exp);
- d->exp = NULL;
- d->block = NULL;
- }
- }
+ if (objfile == NULL)
+ return;
+
+ for (d = display_chain; d != NULL; d = d->next)
+ if (block_objfile (d->block) == objfile
+ || (d->exp && exp_uses_objfile (d->exp, objfile)))
+ {
+ xfree (d->exp);
+ d->exp = NULL;
+ d->block = NULL;
+ }
}
@@ -2812,4 +2788,6 @@ Show printing of source filename and line number with <symbol>."), NULL,
NULL,
show_print_symbol_filename,
&setprintlist, &showprintlist);
+
+ observer_attach_mark_used (print_types_mark_used);
}
diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py
new file mode 100644
index 0000000..5654546
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameIterator.py
@@ -0,0 +1,33 @@
+# Iterator over frames.
+
+# Copyright (C) 2008, 2009 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/>.
+
+class FrameIterator:
+ """An iterator that iterates over frames."""
+
+ def __init__ (self, frame):
+ "Initialize a FrameIterator. FRAME is the starting frame."
+ self.frame = frame
+
+ def __iter__ (self):
+ return self
+
+ def next (self):
+ result = self.frame
+ if result is None:
+ raise StopIteration
+ self.frame = result.older ()
+ return result
diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py
new file mode 100644
index 0000000..b790a54
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameWrapper.py
@@ -0,0 +1,112 @@
+# Wrapper API for frames.
+
+# Copyright (C) 2008, 2009 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
+
+# FIXME: arguably all this should be on Frame somehow.
+class FrameWrapper:
+ def __init__ (self, frame):
+ self.frame = frame;
+
+ def write_symbol (self, stream, sym, block):
+ if len (sym.linkage_name):
+ nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block)
+ if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER:
+ sym = nsym
+
+ stream.write (sym.print_name + "=")
+ try:
+ val = self.read_var (sym)
+ if val != None:
+ val = str (val)
+ # FIXME: would be nice to have a more precise exception here.
+ except RuntimeError, text:
+ val = text
+ if val == None:
+ stream.write ("???")
+ else:
+ stream.write (str (val))
+
+ def print_frame_locals (self, stream, func):
+ if not func:
+ return
+
+ first = True
+ block = func.value
+
+ for sym in block:
+ if sym.is_argument:
+ continue;
+
+ self.write_symbol (stream, sym, block)
+ stream.write ('\n')
+
+ def print_frame_args (self, stream, func):
+ if not func:
+ return
+
+ first = True
+ block = func.value
+
+ for sym in block:
+ if not sym.is_argument:
+ continue;
+
+ if not first:
+ stream.write (", ")
+
+ self.write_symbol (stream, sym, block)
+ first = False
+
+ # FIXME: this should probably just be a method on gdb.Frame.
+ # But then we need stream wrappers.
+ def describe (self, stream, full):
+ if self.type () == gdb.DUMMY_FRAME:
+ stream.write (" <function called from gdb>\n")
+ elif self.type () == gdb.SIGTRAMP_FRAME:
+ stream.write (" <signal handler called>\n")
+ else:
+ sal = self.find_sal ()
+ pc = self.pc ()
+ name = self.name ()
+ if not name:
+ name = "??"
+ if pc != sal.pc or not sal.symtab:
+ stream.write (" 0x%08x in" % pc)
+ stream.write (" " + name + " (")
+
+ func = self.function ()
+ self.print_frame_args (stream, func)
+
+ stream.write (")")
+
+ if sal.symtab and sal.symtab.filename:
+ stream.write (" at " + sal.symtab.filename)
+ stream.write (":" + str (sal.line))
+
+ if not self.name () or (not sal.symtab or not sal.symtab.filename):
+ lib = gdb.solib_address (pc)
+ if lib:
+ stream.write (" from " + lib)
+
+ stream.write ("\n")
+
+ if full:
+ self.print_frame_locals (stream, func)
+
+ def __getattr__ (self, name):
+ return getattr (self.frame, name)
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
new file mode 100644
index 0000000..b375c68
--- /dev/null
+++ b/gdb/python/lib/gdb/__init__.py
@@ -0,0 +1,19 @@
+# Startup code.
+
+# Copyright (C) 2008 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/>.
+
+# Load the require command by default.
+import gdb.command.require
diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py
new file mode 100644
index 0000000..2baab5f
--- /dev/null
+++ b/gdb/python/lib/gdb/backtrace.py
@@ -0,0 +1,42 @@
+# Filtering backtrace.
+
+# Copyright (C) 2008 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
+
+# Our only exports.
+__all__ = ['push_frame_filter', 'create_frame_filter']
+
+frame_filter = None
+
+def push_frame_filter (constructor):
+ """Register a new backtrace filter class with the 'backtrace' command.
+The filter will be passed an iterator as an argument. The iterator
+will return gdb.Frame-like objects. The filter should in turn act as
+an iterator returning such objects."""
+ global frame_filter
+ if frame_filter == None:
+ frame_filter = constructor
+ else:
+ frame_filter = lambda iterator: constructor (frame_filter (iterator))
+
+def create_frame_filter (iter):
+ global frame_filter
+ if frame_filter is None:
+ return iter
+ return frame_filter (iter)
+
diff --git a/gdb/python/lib/gdb/command/__init__.py b/gdb/python/lib/gdb/command/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gdb/python/lib/gdb/command/__init__.py
@@ -0,0 +1 @@
+
diff --git a/gdb/python/lib/gdb/command/alias.py b/gdb/python/lib/gdb/command/alias.py
new file mode 100644
index 0000000..96b6618
--- /dev/null
+++ b/gdb/python/lib/gdb/command/alias.py
@@ -0,0 +1,59 @@
+# Alias command.
+
+# Copyright (C) 2008 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 AliasImplementation (gdb.Command):
+ def __init__ (self, name, real, doc):
+ # Have to set __doc__ before the super init call.
+ # It would be nice if gdb's help looked up __doc__ dynamically.
+ self.__doc__ = doc
+ # Note: no good way to complete :(
+ super (AliasImplementation, self).__init__ (name, gdb.COMMAND_NONE)
+ self.real = real
+
+ def invoke(self, arg, from_tty):
+ gdb.execute (self.real + ' ' + arg, from_tty)
+
+class AliasCommand (gdb.Command):
+ """Alias one command to another.
+In the simplest form, the first word is the name of the alias, and
+the remaining words are the the expansion.
+An '=' by itself can be used to define a multi-word alias; words
+before the '=' are the name of the new command."""
+
+ def __init__ (self):
+ # Completion is not quite right here.
+ super (AliasCommand, self).__init__ ("alias", gdb.COMMAND_NONE,
+ gdb.COMPLETE_COMMAND)
+
+ def invoke (self, arg, from_tty):
+ self.dont_repeat ()
+ # Without some form of quoting we can't alias a multi-word
+ # command to another command.
+ args = arg.split()
+ try:
+ start = args.index ('=')
+ end = start + 1
+ except ValueError:
+ start = 1
+ end = 1
+ target = " ".join(args[end:])
+ AliasImplementation (" ".join (args[0:start]), target,
+ "This command is an alias for '%s'." % target)
+
+AliasCommand()
diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py
new file mode 100644
index 0000000..ec9a527
--- /dev/null
+++ b/gdb/python/lib/gdb/command/backtrace.py
@@ -0,0 +1,106 @@
+# New backtrace command.
+
+# Copyright (C) 2008, 2009 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 gdb.backtrace
+import itertools
+from gdb.FrameIterator import FrameIterator
+from gdb.FrameWrapper import FrameWrapper
+import sys
+
+class ReverseBacktraceParameter (gdb.Parameter):
+ """The new-backtrace command can show backtraces in 'reverse' order.
+This means that the innermost frame will be printed last.
+Note that reverse backtraces are more expensive to compute."""
+
+ set_doc = "Enable or disable reverse backtraces."
+ show_doc = "Show whether backtraces will be printed in reverse order."
+
+ def __init__(self):
+ gdb.Parameter.__init__ (self, "reverse-backtrace",
+ gdb.COMMAND_STACK, gdb.PARAM_BOOLEAN)
+ # Default to compatibility with gdb.
+ self.value = False
+
+class FilteringBacktrace (gdb.Command):
+ """Print backtrace of all stack frames, or innermost COUNT frames.
+With a negative argument, print outermost -COUNT frames.
+Use of the 'full' qualifier also prints the values of the local variables.
+Use of the 'raw' qualifier avoids any filtering by loadable modules.
+"""
+
+ def __init__ (self):
+ # FIXME: this is not working quite well enough to replace
+ # "backtrace" yet.
+ gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK)
+ self.reverse = ReverseBacktraceParameter()
+
+ def reverse_iter (self, iter):
+ result = []
+ for item in iter:
+ result.append (item)
+ result.reverse()
+ return result
+
+ def final_n (self, iter, x):
+ result = []
+ for item in iter:
+ result.append (item)
+ return result[x:]
+
+ def invoke (self, arg, from_tty):
+ i = 0
+ count = 0
+ filter = True
+ full = False
+
+ for word in arg.split (" "):
+ if word == '':
+ continue
+ elif word == 'raw':
+ filter = False
+ elif word == 'full':
+ full = True
+ else:
+ count = int (word)
+
+ # FIXME: provide option to start at selected frame
+ # However, should still number as if starting from newest
+ newest_frame = gdb.selected_thread ().newest_frame ()
+ iter = itertools.imap (FrameWrapper,
+ FrameIterator (newest_frame))
+ if filter:
+ iter = gdb.backtrace.create_frame_filter (iter)
+
+ # Now wrap in an iterator that numbers the frames.
+ iter = itertools.izip (itertools.count (0), iter)
+
+ # Reverse if the user wanted that.
+ if self.reverse.value:
+ iter = self.reverse_iter (iter)
+
+ # Extract sub-range user wants.
+ if count < 0:
+ iter = self.final_n (iter, count)
+ elif count > 0:
+ iter = itertools.islice (iter, 0, count)
+
+ for pair in iter:
+ sys.stdout.write ("#%-2d" % pair[0])
+ pair[1].describe (sys.stdout, full)
+
+FilteringBacktrace()
diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py
new file mode 100644
index 0000000..6fa48ff
--- /dev/null
+++ b/gdb/python/lib/gdb/command/ignore_errors.py
@@ -0,0 +1,37 @@
+# Ignore errors in user commands.
+
+# Copyright (C) 2008 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 IgnoreErrorsCommand (gdb.Command):
+ """Execute a single command, ignoring all errors.
+Only one-line commands are supported.
+This is primarily useful in scripts."""
+
+ def __init__ (self):
+ super (IgnoreErrorsCommand, self).__init__ ("ignore-errors",
+ gdb.COMMAND_OBSCURE,
+ # FIXME...
+ gdb.COMPLETE_COMMAND)
+
+ def invoke (self, arg, from_tty):
+ try:
+ gdb.execute (arg, from_tty)
+ except:
+ pass
+
+IgnoreErrorsCommand ()
diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py
new file mode 100644
index 0000000..21a0bf0
--- /dev/null
+++ b/gdb/python/lib/gdb/command/pahole.py
@@ -0,0 +1,75 @@
+# pahole command for gdb
+
+# Copyright (C) 2008, 2009 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 Pahole (gdb.Command):
+ """Show the holes in a structure.
+This command takes a single argument, a type name.
+It prints the type and displays comments showing where holes are."""
+
+ def __init__ (self):
+ super (Pahole, self).__init__ ("pahole", gdb.COMMAND_NONE,
+ gdb.COMPLETE_SYMBOL)
+
+ def pahole (self, type, level, name):
+ if name is None:
+ name = ''
+ tag = type.tag
+ if tag is None:
+ tag = ''
+ print '%sstruct %s {' % (' ' * (2 * level), tag)
+ bitpos = 0
+ for field in type.fields ():
+ # Skip static fields.
+ if not hasattr (field, ('bitpos')):
+ continue
+
+ ftype = field.type.strip_typedefs()
+
+ if bitpos != field.bitpos:
+ hole = field.bitpos - bitpos
+ print ' /* XXX %d bit hole, try to pack */' % hole
+ bitpos = field.bitpos
+ if field.bitsize > 0:
+ fieldsize = field.bitsize
+ else:
+ # TARGET_CHAR_BIT here...
+ fieldsize = 8 * ftype.sizeof
+
+ # TARGET_CHAR_BIT
+ print ' /* %3d %3d */' % (int (bitpos / 8), int (fieldsize / 8)),
+ bitpos = bitpos + fieldsize
+
+ if ftype.code == gdb.TYPE_CODE_STRUCT:
+ self.pahole (ftype, level + 1, field.name)
+ else:
+ print ' ' * (2 + 2 * level),
+ print '%s %s' % (str (ftype), field.name)
+
+ print ' ' * (14 + 2 * level),
+ print '} %s' % name
+
+ def invoke (self, arg, from_tty):
+ type = gdb.lookup_type (arg)
+ type = type.strip_typedefs ()
+ if type.code != gdb.TYPE_CODE_STRUCT:
+ raise TypeError, '%s is not a struct type' % arg
+ print ' ' * 14,
+ self.pahole (type, 0, '')
+
+Pahole()
diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py
new file mode 100644
index 0000000..1fbc1e8
--- /dev/null
+++ b/gdb/python/lib/gdb/command/require.py
@@ -0,0 +1,57 @@
+# Demand-loading commands.
+
+# Copyright (C) 2008, 2009 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 os
+
+class RequireCommand (gdb.Command):
+ """Prefix command for requiring features."""
+
+ def __init__ (self):
+ super (RequireCommand, self).__init__ ("require",
+ gdb.COMMAND_SUPPORT,
+ gdb.COMPLETE_NONE,
+ True)
+
+class RequireSubcommand (gdb.Command):
+ """Demand-load a command by name."""
+
+ def __init__ (self, name):
+ self.__doc__ = "Demand-load a %s by name." % name
+ super (RequireSubcommand, self).__init__ ("require %s" % name,
+ gdb.COMMAND_SUPPORT)
+ self.name = name
+
+ def invoke (self, arg, from_tty):
+ for cmd in arg.split():
+ exec ('import gdb.' + self.name + '.' + cmd, globals ())
+
+ def complete (self, text, word):
+ dir = gdb.pythondir + '/gdb/' + self.name
+ result = []
+ for file in os.listdir(dir):
+ if not file.startswith (word) or not file.endswith ('.py'):
+ continue
+ feature = file[0:-3]
+ if feature == 'require' or feature == '__init__':
+ continue
+ result.append (feature)
+ return result
+
+RequireCommand()
+RequireSubcommand("command")
+RequireSubcommand("function")
diff --git a/gdb/python/lib/gdb/command/save_breakpoints.py b/gdb/python/lib/gdb/command/save_breakpoints.py
new file mode 100644
index 0000000..6143187
--- /dev/null
+++ b/gdb/python/lib/gdb/command/save_breakpoints.py
@@ -0,0 +1,65 @@
+# Save breakpoints.
+
+# Copyright (C) 2008, 2009 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/>.
+
+from __future__ import with_statement
+import gdb
+
+class SavePrefixCommand (gdb.Command):
+ "Prefix command for saving things."
+
+ def __init__ (self):
+ super (SavePrefixCommand, self).__init__ ("save",
+ gdb.COMMAND_SUPPORT,
+ gdb.COMPLETE_NONE, True)
+
+class SaveBreakpointsCommand (gdb.Command):
+ """Save the current breakpoints to a file.
+This command takes a single argument, a file name.
+The breakpoints can be restored using the 'source' command."""
+
+ def __init__ (self):
+ super (SaveBreakpointsCommand, self).__init__ ("save breakpoints",
+ gdb.COMMAND_SUPPORT,
+ gdb.COMPLETE_FILENAME)
+
+ def invoke (self, arg, from_tty):
+ self.dont_repeat ()
+ bps = gdb.breakpoints ()
+ if bps is None:
+ raise RuntimeError, 'No breakpoints to save'
+ with open (arg.strip (), 'w') as f:
+ for bp in bps:
+ print >> f, "break", bp.location,
+ if bp.thread is not None:
+ print >> f, " thread", bp.thread,
+ if bp.condition is not None:
+ print >> f, " if", bp.condition,
+ print >> f
+ if not bp.enabled:
+ print >> f, "disable $bpnum"
+ # Note: we don't save the ignore count; there doesn't
+ # seem to be much point.
+ commands = bp.commands
+ if commands is not None:
+ print >> f, "commands"
+ # Note that COMMANDS has a trailing newline.
+ print >> f, commands,
+ print >> f, "end"
+ print >> f
+
+SavePrefixCommand ()
+SaveBreakpointsCommand ()
diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py
new file mode 100644
index 0000000..faf54ed
--- /dev/null
+++ b/gdb/python/lib/gdb/command/upto.py
@@ -0,0 +1,129 @@
+# upto command.
+
+# Copyright (C) 2009 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 re
+from gdb.FrameIterator import FrameIterator
+from gdb.FrameWrapper import FrameWrapper
+
+class UptoPrefix (gdb.Command):
+ def __init__ (self):
+ super (UptoPrefix, self).__init__ ("upto", gdb.COMMAND_STACK,
+ prefix = True)
+
+class UptoImplementation (gdb.Command):
+ def __init__ (self, subcommand):
+ super (UptoImplementation, self).__init__ ("upto " + subcommand,
+ gdb.COMMAND_STACK)
+
+ def search (self):
+ saved = gdb.selected_frame ()
+ iter = FrameIterator (saved)
+ found = False
+ try:
+ for frame in iter:
+ frame.select ()
+ try:
+ if self.filter (frame):
+ wrapper = FrameWrapper (frame)
+ wrapper.describe (sys.stdout, False)
+ return
+ except:
+ pass
+ except:
+ pass
+ saved.select ()
+ raise RuntimeError, 'Could not find a matching frame'
+
+ def invoke (self, arg, from_tty):
+ self.rx = re.compile (arg)
+ self.search ()
+
+class UptoSymbolCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on symbol.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose symbol matches the regular
+expression."""
+
+ def __init__ (self):
+ super (UptoSymbolCommand, self).__init__ ("symbol")
+
+ def filter (self, frame):
+ name = frame.name ()
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoSourceCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on source file.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose source file name matches the
+regular expression."""
+
+ def __init__ (self):
+ super (UptoSourceCommand, self).__init__ ("source")
+
+ def filter (self, frame):
+ name = frame.find_sal ().symtab.filename
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoObjectCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on object file.
+The argument is a regular expression. This command moves up the
+stack, stopping at the first frame whose object file name matches the
+regular expression."""
+
+ def __init__ (self):
+ super (UptoObjectCommand, self).__init__ ("object")
+
+ def filter (self, frame):
+ name = frame.find_sal ().symtab.objfile.filename
+ if name is not None:
+ if self.rx.search (name) is not None:
+ return True
+ return False
+
+class UptoWhereCommand (UptoImplementation):
+ """Select and print some calling stack frame, based on expression.
+The argument is an expression. This command moves up the stack,
+parsing and evaluating the expression in each frame. This stops when
+the expression evaluates to a non-zero (true) value."""
+
+ def __init__ (self):
+ super (UptoWhereCommand, self).__init__ ("where")
+
+ def filter (self, frame):
+ try:
+ if gdb.parse_and_eval (self.expression):
+ return True
+ except:
+ pass
+ return False
+
+ def invoke (self, arg, from_tty):
+ self.expression = arg
+ self.search ()
+
+UptoPrefix ()
+UptoSymbolCommand ()
+UptoSourceCommand ()
+UptoObjectCommand ()
+UptoWhereCommand ()
diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gdb/python/lib/gdb/function/__init__.py
@@ -0,0 +1 @@
+
diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py
new file mode 100644
index 0000000..2b9c5c7
--- /dev/null
+++ b/gdb/python/lib/gdb/function/caller_is.py
@@ -0,0 +1,58 @@
+# Caller-is functions.
+
+# Copyright (C) 2008 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 re
+
+class CallerIs (gdb.Function):
+ """Return True if the calling function's name is equal to a string.
+This function takes one or two arguments.
+The first argument is the name of a function; if the calling function's
+name is equal to this argument, this function returns True.
+The optional second argument tells this function how many stack frames
+to traverse to find the calling function. The default is 1."""
+
+ def __init__ (self):
+ super (CallerIs, self).__init__ ("caller_is")
+
+ def invoke (self, name, nframes = 1):
+ frame = gdb.selected_frame ()
+ while nframes > 0:
+ frame = frame.older ()
+ nframes = nframes - 1
+ return frame.name () == name.string ()
+
+class CallerMatches (gdb.Function):
+ """Return True if the calling function's name matches a string.
+This function takes one or two arguments.
+The first argument is a regular expression; if the calling function's
+name is matched by this argument, this function returns True.
+The optional second argument tells this function how many stack frames
+to traverse to find the calling function. The default is 1."""
+
+ def __init__ (self):
+ super (CallerMatches, self).__init__ ("caller_matches")
+
+ def invoke (self, name, nframes = 1):
+ frame = gdb.selected_frame ()
+ while nframes > 0:
+ frame = frame.older ()
+ nframes = nframes - 1
+ return re.match (name.string (), frame.name ()) is not None
+
+CallerIs()
+CallerMatches()
diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py
new file mode 100644
index 0000000..debb3bb
--- /dev/null
+++ b/gdb/python/lib/gdb/function/in_scope.py
@@ -0,0 +1,47 @@
+# In-scope function.
+
+# Copyright (C) 2008 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 InScope (gdb.Function):
+ """Return True if all the given variables or macros are in scope.
+Takes one argument for each variable name to be checked."""
+
+ def __init__ (self):
+ super (InScope, self).__init__ ("in_scope")
+
+ def invoke (self, *vars):
+ if len (vars) == 0:
+ raise TypeError, "in_scope takes at least one argument"
+
+ # gdb.Value isn't hashable so it can't be put in a map.
+ # Convert to string first.
+ wanted = set (map (lambda x: x.string (), vars))
+ found = set ()
+ block = gdb.selected_frame ().block ()
+ while block:
+ for sym in block:
+ if (sym.is_argument or sym.is_constant
+ or sym.is_function or sym.is_variable):
+ if sym.name in wanted:
+ found.add (sym.name)
+
+ block = block.superblock
+
+ return wanted == found
+
+InScope ()
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
new file mode 100644
index 0000000..8019e9d
--- /dev/null
+++ b/gdb/python/py-block.c
@@ -0,0 +1,265 @@
+/* Python interface to blocks.
+
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "block.h"
+#include "dictionary.h"
+#include "symtab.h"
+#include "python-internal.h"
+
+typedef struct {
+ PyObject_HEAD
+ struct block *block;
+} block_object;
+
+typedef struct {
+ PyObject_HEAD
+ struct dictionary *dict;
+ struct dict_iterator iter;
+ int initialized_p;
+} block_syms_iterator_object;
+
+static PyTypeObject block_syms_iterator_object_type;
+
+static PyObject *
+blpy_iter (PyObject *self)
+{
+ block_syms_iterator_object *block_iter_obj;
+
+ block_iter_obj = PyObject_New (block_syms_iterator_object,
+ &block_syms_iterator_object_type);
+ if (block_iter_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError,
+ "Could not allocate iterator object.");
+ return NULL;
+ }
+
+ block_iter_obj->dict = BLOCK_DICT (((block_object *) self)->block);
+ block_iter_obj->initialized_p = 0;
+
+ return (PyObject *) block_iter_obj;
+}
+
+static PyObject *
+blpy_get_start (PyObject *self, void *closure)
+{
+ block_object *self_block = (block_object *) self;
+
+ return PyLong_FromUnsignedLongLong (BLOCK_START (self_block->block));
+}
+
+static PyObject *
+blpy_get_end (PyObject *self, void *closure)
+{
+ block_object *self_block = (block_object *) self;
+
+ return PyLong_FromUnsignedLongLong (BLOCK_END (self_block->block));
+}
+
+static PyObject *
+blpy_get_function (PyObject *self, void *closure)
+{
+ block_object *self_block = (block_object *) self;
+ struct symbol *sym;
+
+ sym = BLOCK_FUNCTION (self_block->block);
+ if (sym)
+ return symbol_to_symbol_object (sym);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+blpy_get_superblock (PyObject *self, void *closure)
+{
+ block_object *self_block = (block_object *) self;
+ struct block *block;
+
+ block = BLOCK_SUPERBLOCK (self_block->block);
+ if (block)
+ return block_to_block_object (block);
+
+ Py_RETURN_NONE;
+}
+
+PyObject *
+block_to_block_object (struct block *block)
+{
+ block_object *block_obj;
+
+ block_obj = PyObject_New (block_object, &block_object_type);
+ if (block_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError, "Could not allocate block object.");
+ return NULL;
+ }
+
+ block_obj->block = block;
+
+ return (PyObject *) block_obj;
+}
+
+struct block *
+block_object_to_block (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &block_object_type))
+ return NULL;
+ return ((block_object *) obj)->block;
+}
+
+static PyObject *
+blpy_block_syms_iter (PyObject *self)
+{
+ return self;
+}
+
+static PyObject *
+blpy_block_syms_iternext (PyObject *self)
+{
+ block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self;
+ struct symbol *sym;
+
+ if (!iter_obj->initialized_p)
+ {
+ sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter));
+ iter_obj->initialized_p = 1;
+ }
+ else
+ sym = dict_iterator_next (&(iter_obj->iter));
+
+ return (sym == NULL)? NULL : symbol_to_symbol_object (sym);
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+ or 0 if there is none. */
+
+PyObject *
+gdbpy_block_for_pc (PyObject *self, PyObject *args)
+{
+ unsigned PY_LONG_LONG pc;
+ struct block *block;
+ PyObject *sym_obj;
+
+ if (!PyArg_ParseTuple (args, "K", &pc))
+ return NULL;
+
+ block = block_for_pc (pc);
+ if (block)
+ return block_to_block_object (block);
+
+ Py_RETURN_NONE;
+}
+
+void
+gdbpy_initialize_blocks (void)
+{
+ block_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&block_object_type) < 0)
+ return;
+
+ block_syms_iterator_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&block_syms_iterator_object_type) < 0)
+ return;
+
+ Py_INCREF (&block_object_type);
+ PyModule_AddObject (gdb_module, "Block", (PyObject *) &block_object_type);
+
+ Py_INCREF (&block_syms_iterator_object_type);
+ PyModule_AddObject (gdb_module, "BlockIterator",
+ (PyObject *) &block_syms_iterator_object_type);
+}
+
+
+
+static PyGetSetDef block_object_getset[] = {
+ { "start", blpy_get_start, NULL, "Start address of the block.", NULL },
+ { "end", blpy_get_end, NULL, "End address of the block.", NULL },
+ { "function", blpy_get_function, NULL,
+ "Symbol that names the block, or None.", NULL },
+ { "superblock", blpy_get_superblock, NULL,
+ "Block containing the block, or None.", NULL },
+ { NULL } /* Sentinel */
+};
+
+PyTypeObject block_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Block", /*tp_name*/
+ sizeof (block_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
+ "GDB block object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ blpy_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ block_object_getset /* tp_getset */
+};
+
+static PyTypeObject block_syms_iterator_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.BlockIterator", /*tp_name*/
+ sizeof (block_syms_iterator_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
+ "GDB block syms iterator object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ blpy_block_syms_iter, /* tp_iter */
+ blpy_block_syms_iternext, /* tp_iternext */
+ 0 /* tp_methods */
+};
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
new file mode 100644
index 0000000..783385e
--- /dev/null
+++ b/gdb/python/py-breakpoint.c
@@ -0,0 +1,666 @@
+/* Python interface to breakpoints
+
+ Copyright (C) 2008, 2009 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 "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "breakpoint.h"
+#include "gdbcmd.h"
+#include "gdbthread.h"
+#include "observer.h"
+#include "arch-utils.h"
+#include "language.h"
+
+/* From breakpoint.c. */
+extern struct breakpoint *breakpoint_chain;
+
+
+typedef struct breakpoint_object breakpoint_object;
+
+static PyTypeObject breakpoint_object_type;
+
+/* A dynamically allocated vector of breakpoint objects. Each
+ breakpoint has a number. A breakpoint is valid if its slot in this
+ vector is non-null. When a breakpoint is deleted, we drop our
+ reference to it and zero its slot; this is how we let the Python
+ object have a lifetime which is independent from that of the gdb
+ breakpoint. */
+static breakpoint_object **bppy_breakpoints;
+
+/* Number of slots in bppy_breakpoints. */
+static int bppy_slots;
+
+/* Number of live breakpoints. */
+static int bppy_live;
+
+/* Variables used to pass information between the Breakpoint
+ constructor and the breakpoint-created hook function. */
+static breakpoint_object *bppy_pending_object;
+
+struct breakpoint_object
+{
+ PyObject_HEAD
+
+ /* The breakpoint number according to gdb. */
+ int number;
+
+ /* The gdb breakpoint object, or NULL if the breakpoint has been
+ deleted. */
+ struct breakpoint *bp;
+};
+
+/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */
+#define BPPY_VALID_P(Num) \
+ ((Num) >= 0 \
+ && (Num) < bppy_slots \
+ && bppy_breakpoints[Num] != NULL)
+
+/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
+ exception if it is invalid. */
+#define BPPY_REQUIRE_VALID(Breakpoint) \
+ do { \
+ if (! BPPY_VALID_P ((Breakpoint)->number)) \
+ return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \
+ (Breakpoint)->number); \
+ } while (0)
+
+/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
+ exception if it is invalid. This macro is for use in setter functions. */
+#define BPPY_SET_REQUIRE_VALID(Breakpoint) \
+ do { \
+ if (! BPPY_VALID_P ((Breakpoint)->number)) \
+ { \
+ PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \
+ (Breakpoint)->number); \
+ return -1; \
+ } \
+ } while (0)
+
+/* Python function which checks the validity of a breakpoint object. */
+static PyObject *
+bppy_is_valid (PyObject *self, PyObject *args)
+{
+ if (((breakpoint_object *) self)->bp)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to test whether or not the breakpoint is enabled. */
+static PyObject *
+bppy_get_enabled (PyObject *self, void *closure)
+{
+ if (! ((breakpoint_object *) self)->bp)
+ Py_RETURN_FALSE;
+ /* Not clear what we really want here. */
+ if (((breakpoint_object *) self)->bp->enable_state == bp_enabled)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to test whether or not the breakpoint is silent. */
+static PyObject *
+bppy_get_silent (PyObject *self, void *closure)
+{
+ BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+ if (((breakpoint_object *) self)->bp->silent)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+/* Python function to set the enabled state of a breakpoint. */
+static int
+bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int cmp;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError, "cannot delete `enabled' attribute");
+ return -1;
+ }
+ else if (! PyBool_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the value of `enabled' must be a boolean");
+ return -1;
+ }
+
+ cmp = PyObject_IsTrue (newvalue);
+ if (cmp < 0)
+ return -1;
+ else if (cmp == 1)
+ enable_breakpoint (self_bp->bp);
+ else
+ disable_breakpoint (self_bp->bp);
+ return 0;
+}
+
+/* Python function to set the 'silent' state of a breakpoint. */
+static int
+bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int cmp;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError, "cannot delete `silent' attribute");
+ return -1;
+ }
+ else if (! PyBool_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the value of `silent' must be a boolean");
+ return -1;
+ }
+
+ cmp = PyObject_IsTrue (newvalue);
+ if (cmp < 0)
+ return -1;
+ else
+ self_bp->bp->silent = cmp;
+
+ return 0;
+}
+
+/* Python function to set the thread of a breakpoint. */
+static int
+bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ int id;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError, "cannot delete `thread' attribute");
+ return -1;
+ }
+ else if (PyInt_Check (newvalue))
+ {
+ id = (int) PyInt_AsLong (newvalue);
+ if (! valid_thread_id (id))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "invalid thread id");
+ return -1;
+ }
+ }
+ else if (newvalue == Py_None)
+ id = -1;
+ else
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the value of `thread' must be an integer or None");
+ return -1;
+ }
+
+ self_bp->bp->thread = id;
+
+ return 0;
+}
+
+/* Python function to set the ignore count of a breakpoint. */
+static int
+bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ long value;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot delete `ignore_count' attribute");
+ return -1;
+ }
+ else if (! PyInt_Check (newvalue))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the value of `ignore_count' must be an integer");
+ return -1;
+ }
+
+ value = PyInt_AsLong (newvalue);
+ if (value < 0)
+ value = 0;
+ set_ignore_count (self_bp->number, (int) value, 0);
+
+ return 0;
+}
+
+/* Python function to set the hit count of a breakpoint. */
+static int
+bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError, "cannot delete `hit_count' attribute");
+ return -1;
+ }
+ else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0)
+ {
+ PyErr_SetString (PyExc_AttributeError,
+ "the value of `hit_count' must be zero");
+ return -1;
+ }
+
+ self_bp->bp->hit_count = 0;
+
+ return 0;
+}
+
+/* Python function to get the location of a breakpoint. */
+static PyObject *
+bppy_get_location (PyObject *self, void *closure)
+{
+ char *str;
+
+ BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+ str = ((breakpoint_object *) self)->bp->addr_string;
+ /* FIXME: watchpoints? tracepoints? */
+ if (! str)
+ str = "";
+ return PyString_Decode (str, strlen (str), host_charset (), NULL);
+}
+
+/* Python function to get the condition expression of a breakpoint. */
+static PyObject *
+bppy_get_condition (PyObject *self, void *closure)
+{
+ char *str;
+ BPPY_REQUIRE_VALID ((breakpoint_object *) self);
+
+ str = ((breakpoint_object *) self)->bp->cond_string;
+ if (! str)
+ Py_RETURN_NONE;
+ return PyString_Decode (str, strlen (str), host_charset (), NULL);
+}
+
+static int
+bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
+{
+ char *exp;
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ volatile struct gdb_exception except;
+
+ BPPY_SET_REQUIRE_VALID (self_bp);
+
+ if (newvalue == NULL)
+ {
+ PyErr_SetString (PyExc_TypeError, "cannot delete `condition' attribute");
+ return -1;
+ }
+ else if (newvalue == Py_None)
+ exp = "";
+ else
+ {
+ exp = python_string_to_host_string (newvalue);
+ if (exp == NULL)
+ return -1;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ set_breakpoint_condition (self_bp->bp, exp, 0);
+ }
+ GDB_PY_SET_HANDLE_EXCEPTION (except);
+
+ return 0;
+}
+
+/* Python function to get the commands attached to a breakpoint. */
+static PyObject *
+bppy_get_commands (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+ long length;
+ volatile struct gdb_exception except;
+ struct ui_file *string_file;
+ struct cleanup *chain;
+ PyObject *result;
+ char *cmdstr;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (! self_bp->bp->commands)
+ Py_RETURN_NONE;
+
+ string_file = mem_fileopen ();
+ chain = make_cleanup_ui_file_delete (string_file);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ /* FIXME: this can fail. Maybe we need to be making a new
+ ui_out object here? */
+ ui_out_redirect (uiout, string_file);
+ print_command_lines (uiout, self_bp->bp->commands, 0);
+ ui_out_redirect (uiout, NULL);
+ }
+ cmdstr = ui_file_xstrdup (string_file, &length);
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL);
+ do_cleanups (chain);
+ xfree (cmdstr);
+ return result;
+}
+
+/* Python function to get the breakpoint's number. */
+static PyObject *
+bppy_get_number (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->number);
+}
+
+/* Python function to get the breakpoint's thread ID. */
+static PyObject *
+bppy_get_thread (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (self_bp->bp->thread == -1)
+ Py_RETURN_NONE;
+
+ return PyInt_FromLong (self_bp->bp->thread);
+}
+
+/* Python function to get the breakpoint's hit count. */
+static PyObject *
+bppy_get_hit_count (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->bp->hit_count);
+}
+
+/* Python function to get the breakpoint's ignore count. */
+static PyObject *
+bppy_get_ignore_count (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ return PyInt_FromLong (self_bp->bp->ignore_count);
+}
+
+/* Python function to create a new breakpoint. */
+static PyObject *
+bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+ PyObject *result;
+ char *spec;
+ volatile struct gdb_exception except;
+
+ /* FIXME: allow condition, thread, temporary, ... ? */
+ if (! PyArg_ParseTuple (args, "s", &spec))
+ return NULL;
+ result = subtype->tp_alloc (subtype, 0);
+ if (! result)
+ return NULL;
+ bppy_pending_object = (breakpoint_object *) result;
+ bppy_pending_object->number = -1;
+ bppy_pending_object->bp = NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ set_breakpoint (python_gdbarch, spec, NULL, 0, 0, -1, 0,
+ AUTO_BOOLEAN_TRUE, 1);
+ }
+ if (except.reason < 0)
+ {
+ subtype->tp_free (result);
+ return PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+ "%s", except.message);
+ }
+
+ BPPY_REQUIRE_VALID ((breakpoint_object *) result);
+ return result;
+}
+
+
+
+/* Static function to return a tuple holding all breakpoints. */
+
+PyObject *
+gdbpy_breakpoints (PyObject *self, PyObject *args)
+{
+ PyObject *result;
+
+ if (bppy_live == 0)
+ Py_RETURN_NONE;
+
+ result = PyTuple_New (bppy_live);
+ if (result)
+ {
+ int i, out = 0;
+ for (i = 0; out < bppy_live; ++i)
+ {
+ if (! bppy_breakpoints[i])
+ continue;
+ Py_INCREF (bppy_breakpoints[i]);
+ PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]);
+ ++out;
+ }
+ }
+ return result;
+}
+
+
+
+/* Event callback functions. */
+
+/* Callback that is used when a breakpoint is created. This function
+ will create a new Python breakpoint object. */
+static void
+gdbpy_breakpoint_created (int num)
+{
+ breakpoint_object *newbp;
+ struct breakpoint *bp;
+ struct cleanup *cleanup;
+
+ if (num < 0)
+ return;
+
+ for (bp = breakpoint_chain; bp; bp = bp->next)
+ if (bp->number == num)
+ break;
+ if (! bp)
+ return;
+
+ if (num >= bppy_slots)
+ {
+ int old = bppy_slots;
+ bppy_slots = bppy_slots * 2 + 10;
+ bppy_breakpoints
+ = (breakpoint_object **) xrealloc (bppy_breakpoints,
+ (bppy_slots
+ * sizeof (breakpoint_object *)));
+ memset (&bppy_breakpoints[old], 0,
+ (bppy_slots - old) * sizeof (PyObject *));
+ }
+
+ ++bppy_live;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ if (bppy_pending_object)
+ {
+ newbp = bppy_pending_object;
+ bppy_pending_object = NULL;
+ }
+ else
+ newbp = PyObject_New (breakpoint_object, &breakpoint_object_type);
+ if (newbp)
+ {
+ PyObject *hookfn;
+
+ newbp->number = num;
+ newbp->bp = bp;
+ bppy_breakpoints[num] = newbp;
+
+ hookfn = gdbpy_get_hook_function ("new_breakpoint");
+ if (hookfn)
+ {
+ PyObject *result;
+ result = PyObject_CallFunctionObjArgs (hookfn, newbp, NULL);
+ if (result)
+ {
+ Py_DECREF (result);
+ }
+ Py_DECREF (hookfn);
+ }
+ }
+
+ /* Just ignore errors here. */
+ PyErr_Clear ();
+
+ do_cleanups (cleanup);
+}
+
+/* Callback that is used when a breakpoint is deleted. This will
+ invalidate the corresponding Python object. */
+static void
+gdbpy_breakpoint_deleted (int num)
+{
+ struct cleanup *cleanup;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+ if (BPPY_VALID_P (num))
+ {
+ bppy_breakpoints[num]->bp = NULL;
+ Py_DECREF (bppy_breakpoints[num]);
+ bppy_breakpoints[num] = NULL;
+ --bppy_live;
+ }
+ do_cleanups (cleanup);
+}
+
+
+
+/* Initialize the Python breakpoint code. */
+void
+gdbpy_initialize_breakpoints (void)
+{
+ breakpoint_object_type.tp_new = bppy_new;
+ if (PyType_Ready (&breakpoint_object_type) < 0)
+ return;
+
+ Py_INCREF (&breakpoint_object_type);
+ PyModule_AddObject (gdb_module, "Breakpoint",
+ (PyObject *) &breakpoint_object_type);
+
+ observer_attach_breakpoint_created (gdbpy_breakpoint_created);
+ observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
+}
+
+
+
+static PyGetSetDef breakpoint_object_getset[] = {
+ { "enabled", bppy_get_enabled, bppy_set_enabled,
+ "Boolean telling whether the breakpoint is enabled.", NULL },
+ { "silent", bppy_get_silent, bppy_set_silent,
+ "Boolean telling whether the breakpoint is silent.", NULL },
+ { "thread", bppy_get_thread, bppy_set_thread,
+ "Thread ID for the breakpoint.\n\
+If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\
+If the value is None, then this breakpoint not thread-specific.\n\
+No other type of value can be used.", NULL },
+ { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count,
+ "Number of times this breakpoint should be automatically continued.",
+ NULL },
+ { "number", bppy_get_number, NULL,
+ "Breakpoint's number assigned by GDB.", NULL },
+ { "hit_count", bppy_get_hit_count, bppy_set_hit_count,
+ "Number of times the breakpoint has been hit.\n\
+Can be set to zero to clear the count. No other value is valid\n\
+when setting this property.", NULL },
+ { "location", bppy_get_location, NULL,
+ "Location of the breakpoint, as specified by the user.", NULL},
+ { "condition", bppy_get_condition, bppy_set_condition,
+ "Condition of the breakpoint, as specified by the user,\
+or None if no condition set."},
+ { "commands", bppy_get_commands, NULL,
+ "Commands of the breakpoint, as specified by the user."},
+ { NULL } /* Sentinel. */
+};
+
+static PyMethodDef breakpoint_object_methods[] =
+{
+ { "is_valid", bppy_is_valid, METH_NOARGS,
+ "Return true if this breakpoint is valid, false if not." },
+ { NULL } /* Sentinel. */
+};
+
+static PyTypeObject breakpoint_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Breakpoint", /*tp_name*/
+ sizeof (breakpoint_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB breakpoint object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ breakpoint_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ breakpoint_object_getset /* tp_getset */
+};
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index ae462d9..22d1405 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -49,8 +49,7 @@ static struct cmdpy_completer completers[] =
#define N_COMPLETERS (sizeof (completers) / sizeof (completers[0]))
-/* A gdb command. For the time being only ordinary commands (not
- set/show commands) are allowed. */
+/* A gdb command. */
struct cmdpy_object
{
PyObject_HEAD
@@ -70,7 +69,6 @@ typedef struct cmdpy_object cmdpy_object;
static PyTypeObject cmdpy_object_type;
-
/* Constants used by this module. */
static PyObject *invoke_cst;
static PyObject *complete_cst;
@@ -263,10 +261,13 @@ cmdpy_completer (struct cmd_list_element *command, char *text, char *word)
*BASE_LIST is set to the final prefix command's list of
*sub-commands.
+ START_LIST is the list in which the search starts.
+
This function returns the xmalloc()d name of the new command. On
error sets the Python error and returns NULL. */
-static char *
-parse_command_name (char *text, struct cmd_list_element ***base_list)
+char *
+gdbpy_parse_command_name (char *text, struct cmd_list_element ***base_list,
+ struct cmd_list_element **start_list)
{
struct cmd_list_element *elt;
int len = strlen (text);
@@ -299,7 +300,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list)
;
if (i < 0)
{
- *base_list = &cmdlist;
+ *base_list = start_list;
return result;
}
@@ -308,7 +309,7 @@ parse_command_name (char *text, struct cmd_list_element ***base_list)
prefix_text[i + 1] = '\0';
text = prefix_text;
- elt = lookup_cmd_1 (&text, cmdlist, NULL, 1);
+ elt = lookup_cmd_1 (&text, *start_list, NULL, 1);
if (!elt || elt == (struct cmd_list_element *) -1)
{
PyErr_Format (PyExc_RuntimeError, _("could not find command prefix %s"),
@@ -399,7 +400,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
return -1;
}
- cmd_name = parse_command_name (name, &cmd_list);
+ cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist);
if (! cmd_name)
return -1;
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 334bad9..524353d 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -202,10 +202,59 @@ frapy_pc (PyObject *self, PyObject *args)
return PyLong_FromUnsignedLongLong (pc);
}
+/* Implementation of gdb.Frame.block (self) -> gdb.Block.
+ Returns the frame's code block. */
+
+static PyObject *
+frapy_block (PyObject *self, PyObject *args)
+{
+ struct frame_info *frame;
+ struct block *block = NULL;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ block = block_for_pc (get_frame_address_in_block (frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (block)
+ return block_to_block_object (block);
+
+ Py_RETURN_NONE;
+}
+
+
+/* Implementation of gdb.Frame.function (self) -> gdb.Symbol.
+ Returns the symbol for the function corresponding to this frame. */
+
+static PyObject *
+frapy_function (PyObject *self, PyObject *args)
+{
+ struct symbol *sym = NULL;
+ struct frame_info *frame;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ sym = find_pc_function (get_frame_address_in_block (frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (sym)
+ return symbol_to_symbol_object (sym);
+
+ Py_RETURN_NONE;
+}
+
/* Convert a frame_info struct to a Python Frame object.
Sets a Python exception and returns NULL on error. */
-static frame_object *
+PyObject *
frame_info_to_frame_object (struct frame_info *frame)
{
frame_object *frame_obj;
@@ -235,7 +284,7 @@ frame_info_to_frame_object (struct frame_info *frame)
frame_obj->gdbarch = get_frame_arch (frame);
- return frame_obj;
+ return (PyObject *) frame_obj;
}
/* Implementation of gdb.Frame.older (self) -> gdb.Frame.
@@ -296,7 +345,30 @@ frapy_newer (PyObject *self, PyObject *args)
return next_obj;
}
-/* Implementation of gdb.Frame.read_var_value (self, variable) -> gdb.Value.
+/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line.
+ Returns the frame's symtab and line. */
+
+static PyObject *
+frapy_find_sal (PyObject *self, PyObject *args)
+{
+ struct frame_info *frame;
+ struct symtab_and_line sal;
+ volatile struct gdb_exception except;
+ PyObject *sal_obj = NULL; /* Initialize to appease gcc warning. */
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID ((frame_object *) self, frame);
+
+ find_frame_sal (frame, &sal);
+ sal_obj = symtab_and_line_to_sal_object (sal);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return sal_obj;
+}
+
+/* Implementation of gdb.Frame.read_var (self, variable) -> gdb.Value.
Returns the value of the given variable in this frame. The argument must be
a string. Returns None if GDB can't find the specified variable. */
@@ -312,7 +384,9 @@ frapy_read_var (PyObject *self, PyObject *args)
if (!PyArg_ParseTuple (args, "O", &sym_obj))
return NULL;
- if (gdbpy_is_string (sym_obj))
+ if (PyObject_TypeCheck (sym_obj, &symbol_object_type))
+ var = symbol_object_to_symbol (sym_obj);
+ else if (gdbpy_is_string (sym_obj))
{
char *var_name;
struct block *block = NULL;
@@ -365,6 +439,25 @@ frapy_read_var (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
+/* Select this frame. */
+
+static PyObject *
+frapy_select (PyObject *self, PyObject *args)
+{
+ struct frame_info *fi;
+ frame_object *frame = (frame_object *) self;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ FRAPY_REQUIRE_VALID (frame, fi);
+ select_frame (fi);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ Py_RETURN_NONE;
+}
+
/* Implementation of gdb.selected_frame () -> gdb.Frame.
Returns the selected frame object. */
@@ -372,7 +465,7 @@ PyObject *
gdbpy_selected_frame (PyObject *self, PyObject *args)
{
struct frame_info *frame;
- frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */
+ PyObject *frame_obj = NULL; /* Initialize to appease gcc warning. */
volatile struct gdb_exception except;
TRY_CATCH (except, RETURN_MASK_ALL)
@@ -382,7 +475,7 @@ gdbpy_selected_frame (PyObject *self, PyObject *args)
}
GDB_PY_HANDLE_EXCEPTION (except);
- return (PyObject *) frame_obj;
+ return frame_obj;
}
/* Implementation of gdb.stop_reason_string (Integer) -> String.
@@ -484,15 +577,26 @@ Return the reason why it's not possible to find frames older than this." },
{ "pc", frapy_pc, METH_NOARGS,
"pc () -> Long.\n\
Return the frame's resume address." },
+ { "block", frapy_block, METH_NOARGS,
+ "block () -> gdb.Block.\n\
+Return the frame's code block." },
+ { "function", frapy_function, METH_NOARGS,
+ "function () -> gdb.Symbol.\n\
+Returns the symbol for the function corresponding to this frame." },
{ "older", frapy_older, METH_NOARGS,
"older () -> gdb.Frame.\n\
Return the frame that called this frame." },
{ "newer", frapy_newer, METH_NOARGS,
"newer () -> gdb.Frame.\n\
Return the frame called by this frame." },
+ { "find_sal", frapy_find_sal, METH_NOARGS,
+ "find_sal () -> gdb.Symtab_and_line.\n\
+Return the frame's symtab and line." },
{ "read_var", frapy_read_var, METH_VARARGS,
"read_var (variable) -> gdb.Value.\n\
Return the value of the variable in this frame." },
+ { "select", frapy_select, METH_NOARGS,
+ "Select this frame as the user's current frame." },
{NULL} /* Sentinel */
};
diff --git a/gdb/python/py-hooks.c b/gdb/python/py-hooks.c
new file mode 100644
index 0000000..a3140bc
--- /dev/null
+++ b/gdb/python/py-hooks.c
@@ -0,0 +1,50 @@
+/* Notifications from gdb to Python
+
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "cli/cli-decode.h"
+#include "charset.h"
+#include "python.h"
+#include "python-internal.h"
+#include "observer.h"
+
+PyObject *
+gdbpy_get_hook_function (const char *name)
+{
+ PyObject *hooks;
+ PyObject *result;
+
+ if (! PyObject_HasAttrString (gdb_module, "hooks"))
+ return NULL;
+ hooks = PyObject_GetAttrString (gdb_module, "hooks");
+ if (! hooks)
+ return NULL;
+ /* The cast is because the Python function doesn't declare const argument.
+ This is a problem in Python version 2.4, but not in 2.5. */
+ if (! PyObject_HasAttrString (hooks, (char *) name))
+ {
+ Py_DECREF (hooks);
+ return NULL;
+ }
+ /* The cast is because the Python function doesn't declare const argument.
+ This is a problem in Python version 2.4, but not in 2.5. */
+ result = PyObject_GetAttrString (hooks, (char *) name);
+ Py_DECREF (hooks);
+ return result;
+}
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
new file mode 100644
index 0000000..b259ab5
--- /dev/null
+++ b/gdb/python/py-inferior.c
@@ -0,0 +1,934 @@
+/* Python interface to inferiors.
+
+ Copyright (C) 2009, 2010 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 "exceptions.h"
+#include "gdbcore.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "observer.h"
+#include "python-internal.h"
+#include "arch-utils.h"
+#include "language.h"
+
+struct threadlist_entry {
+ thread_object *thread_obj;
+ struct threadlist_entry *next;
+};
+
+typedef struct
+{
+ PyObject_HEAD
+
+ /* The inferior we represent. */
+ struct inferior *inferior;
+
+ /* thread_object instances under this inferior. This list owns a reference
+ to each object it contains. */
+ struct threadlist_entry *threads;
+
+ /* Number of threads in the list. */
+ int nthreads;
+} inferior_object;
+
+static PyTypeObject inferior_object_type;
+
+typedef struct {
+ PyObject_HEAD
+ void *buffer;
+
+ /* These are kept just for mbpy_str. */
+ CORE_ADDR addr;
+ CORE_ADDR length;
+} membuf_object;
+
+static PyTypeObject membuf_object_type;
+
+/* Require that INFERIOR be a valid inferior ID. */
+#define INFPY_REQUIRE_VALID(Inferior) \
+ do { \
+ if (!Inferior->inferior) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ "inferior no longer exists"); \
+ return NULL; \
+ } \
+ } while (0)
+
+struct inflist_entry {
+ inferior_object *inf_obj;
+ struct inflist_entry *next;
+};
+
+
+
+/* Inferior objects list. */
+
+/* List containing inferior_objects. This list owns a reference to each
+ object it contains. */
+static struct inflist_entry *gdbpy_inferior_list;
+
+static int ninferiors;
+
+
+/* An observer callback function that is called when an inferior has
+ been created. Creates a corresponding Python object for the inferior
+ and adds it to the list. */
+static void
+add_inferior_object (int pid)
+{
+ struct inferior *inf = find_inferior_pid (pid);
+ inferior_object *inf_obj;
+ struct inflist_entry *entry;
+ struct cleanup *cleanup;
+
+ if (!inf)
+ {
+ warning (_("Can't create Python Inferior object."));
+ return;
+ }
+
+ /* While creating new inferior no inferior thread is available. Therefore
+ get_current_arch has no valid current frame (and it would crash). */
+
+ cleanup = ensure_python_env (target_gdbarch, current_language);
+
+ inf_obj = PyObject_New (inferior_object, &inferior_object_type);
+ if (!inf_obj)
+ {
+ warning (_("Can't create Python Inferior object."));
+ gdbpy_print_stack ();
+ do_cleanups (cleanup);
+ return;
+ }
+
+ inf_obj->inferior = inf;
+ inf_obj->threads = NULL;
+ inf_obj->nthreads = 0;
+
+ entry = xmalloc (sizeof (struct inflist_entry));
+ entry->inf_obj = inf_obj;
+ entry->next = gdbpy_inferior_list;
+
+ gdbpy_inferior_list = entry;
+
+ ninferiors++;
+
+ do_cleanups (cleanup);
+}
+
+/* An observer callback function that is called when an inferior has
+ been deleted. Removes the corresponding Python object from the
+ inferior list, and removes the list's reference to the object. */
+static void
+delete_inferior_object (int pid)
+{
+ struct cleanup *cleanup;
+ struct inflist_entry **inf_entry, *inf_tmp;
+ struct threadlist_entry *th_entry, *th_tmp;
+
+ /* Find inferior_object for the given PID. */
+ for (inf_entry = &gdbpy_inferior_list; *inf_entry != NULL;
+ inf_entry = &(*inf_entry)->next)
+ if ((*inf_entry)->inf_obj->inferior->pid == pid)
+ break;
+
+ if (!*inf_entry)
+ return;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ inf_tmp = *inf_entry;
+ inf_tmp->inf_obj->inferior = NULL;
+
+ /* Deallocate threads list. */
+ for (th_entry = inf_tmp->inf_obj->threads; th_entry != NULL;)
+ {
+ Py_DECREF (th_entry->thread_obj);
+
+ th_tmp = th_entry;
+ th_entry = th_entry->next;
+ xfree (th_tmp);
+ }
+
+ inf_tmp->inf_obj->nthreads = 0;
+
+ *inf_entry = (*inf_entry)->next;
+ Py_DECREF (inf_tmp->inf_obj);
+ xfree (inf_tmp);
+
+ ninferiors--;
+
+ do_cleanups (cleanup);
+}
+
+/* Finds the Python Inferior object for the given pid. Returns a borrowed
+ reference. */
+PyObject *
+find_inferior_object (int pid)
+{
+ struct inflist_entry *p;
+
+ for (p = gdbpy_inferior_list; p != NULL; p = p->next)
+ if (p->inf_obj->inferior->pid == pid)
+ return (PyObject *) p->inf_obj;
+
+ return NULL;
+}
+
+/* Finds the Python InferiorThread object for the given ptid. Returns a
+ borrowed reference. */
+thread_object *
+find_thread_object (ptid_t ptid)
+{
+ int pid;
+ struct inflist_entry *p;
+ struct threadlist_entry *q;
+
+ pid = PIDGET (ptid);
+ for (p = gdbpy_inferior_list; p != NULL; p = p->next)
+ if (p->inf_obj->inferior->pid == pid)
+ for (q = p->inf_obj->threads; q != NULL; q = q->next)
+ if (ptid_equal (q->thread_obj->thread->ptid, ptid))
+ return q->thread_obj;
+
+ return NULL;
+}
+
+
+
+/* Inferior object. */
+
+static void
+add_thread_object (struct thread_info *tp)
+{
+ struct cleanup *cleanup;
+ thread_object *thread_obj;
+ inferior_object *inf_obj;
+ struct threadlist_entry *entry;
+
+ /* Note that the arch does not matter here, because we can't run
+ arbitrary Python code. Calling get_current_arch here will
+ crash. */
+ cleanup = ensure_python_env (target_gdbarch, current_language);
+
+ thread_obj = create_thread_object (tp);
+ if (!thread_obj)
+ {
+ warning (_("Can't create Python InferiorThread object."));
+ gdbpy_print_stack ();
+ do_cleanups (cleanup);
+ return;
+ }
+
+ inf_obj = (inferior_object *) thread_obj->inf_obj;
+
+ entry = xmalloc (sizeof (struct threadlist_entry));
+ entry->thread_obj = thread_obj;
+ entry->next = inf_obj->threads;
+
+ inf_obj->threads = entry;
+ inf_obj->nthreads++;
+
+ do_cleanups (cleanup);
+}
+
+static void
+delete_thread_object (struct thread_info *tp, int ignore)
+{
+ struct cleanup *cleanup;
+ inferior_object *inf_obj;
+ thread_object *thread_obj;
+ struct threadlist_entry **entry, *tmp;
+
+ inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
+ if (!inf_obj)
+ return;
+
+ /* Find thread entry in its inferior's thread_list. */
+ for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next)
+ if ((*entry)->thread_obj->thread == tp)
+ break;
+
+ if (!*entry)
+ return;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ tmp = *entry;
+ tmp->thread_obj->thread = NULL;
+
+ *entry = (*entry)->next;
+ inf_obj->nthreads--;
+
+ Py_DECREF (tmp->thread_obj);
+ xfree (tmp);
+
+
+ do_cleanups (cleanup);
+}
+
+static PyObject *
+infpy_threads (PyObject *self, PyObject *args)
+{
+ int i;
+ struct threadlist_entry *entry;
+ inferior_object *inf_obj = (inferior_object *) self;
+ PyObject *tuple;
+
+ INFPY_REQUIRE_VALID (inf_obj);
+
+
+ tuple = PyTuple_New (inf_obj->nthreads);
+ if (!tuple)
+ return NULL;
+
+ /* The list is in reverse order of thread age (i.e., newest comes first),
+ is this a problem? */
+ for (i = 0, entry = inf_obj->threads; i < inf_obj->nthreads;
+ i++, entry = entry->next)
+ {
+ Py_INCREF (entry->thread_obj);
+ PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->thread_obj);
+ }
+
+ return tuple;
+}
+
+static PyObject *
+infpy_get_num (PyObject *self, void *closure)
+{
+ inferior_object *inf = (inferior_object *) self;
+
+ INFPY_REQUIRE_VALID (inf);
+
+ return PyLong_FromLong (inf->inferior->num);
+}
+
+static PyObject *
+infpy_get_pid (PyObject *self, void *closure)
+{
+ inferior_object *inf = (inferior_object *) self;
+
+ INFPY_REQUIRE_VALID (inf);
+
+ return PyLong_FromLong (inf->inferior->pid);
+}
+
+static PyObject *
+infpy_get_was_attached (PyObject *self, void *closure)
+{
+ inferior_object *inf = (inferior_object *) self;
+ INFPY_REQUIRE_VALID (inf);
+ if (inf->inferior->attach_flag)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+
+
+/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
+ Returns a list of all inferiors. */
+
+PyObject *
+gdbpy_inferiors (PyObject *unused, PyObject *unused2)
+{
+ int i;
+ struct inflist_entry *entry;
+ PyObject *tuple;
+
+ tuple = PyTuple_New (ninferiors);
+ if (!tuple)
+ return NULL;
+
+ /* The list is in reverse order of inferior age (i.e., newest comes first),
+ is this a problem? */
+ for (i = 0, entry = gdbpy_inferior_list;
+ i < ninferiors;
+ i++, entry = entry->next)
+ {
+ Py_INCREF (entry->inf_obj);
+ PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->inf_obj);
+ }
+
+ return tuple;
+}
+
+
+
+/* Membuf and memory manipulation. */
+
+/* Implementation of gdb.read_memory (address, length).
+ Returns a Python buffer object with LENGTH bytes of the inferior's memory
+ at ADDRESS. Both arguments are integers. */
+
+static PyObject *
+infpy_read_memory (PyObject *self, PyObject *args)
+{
+ int error = 0;
+ CORE_ADDR addr, length;
+ void *buffer = NULL;
+ membuf_object *membuf_obj;
+ PyObject *addr_obj, *length_obj;
+ struct cleanup *cleanups;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "OO", &addr_obj, &length_obj))
+ return NULL;
+
+ cleanups = make_cleanup (null_cleanup, NULL);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (!get_addr_from_python (addr_obj, &addr)
+ || !get_addr_from_python (length_obj, &length))
+ {
+ error = 1;
+ break;
+ }
+
+ buffer = xmalloc (length);
+ make_cleanup (xfree, buffer);
+
+ read_memory (addr, buffer, length);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (error)
+ {
+ do_cleanups (cleanups);
+ return NULL;
+ }
+
+ membuf_obj = PyObject_New (membuf_object, &membuf_object_type);
+ if (membuf_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError,
+ "Could not allocate memory buffer object.");
+ do_cleanups (cleanups);
+ return NULL;
+ }
+
+ discard_cleanups (cleanups);
+
+ membuf_obj->buffer = buffer;
+ membuf_obj->addr = addr;
+ membuf_obj->length = length;
+
+ return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
+ Py_END_OF_BUFFER);
+}
+
+/* Implementation of gdb.write_memory (address, buffer [, length]).
+ Writes the contents of BUFFER (a Python object supporting the read buffer
+ protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from
+ BUFFER, or its entire contents if the argument is not provided. The
+ function returns nothing. */
+
+static PyObject *
+infpy_write_memory (PyObject *self, PyObject *args)
+{
+ int buf_len, error = 0;
+ const char *buffer;
+ CORE_ADDR addr, length;
+ PyObject *addr_obj, *length_obj = NULL;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "Os#|O", &addr_obj, &buffer, &buf_len,
+ &length_obj))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (!get_addr_from_python (addr_obj, &addr))
+ {
+ error = 1;
+ break;
+ }
+
+ if (!length_obj)
+ length = buf_len;
+ else if (!get_addr_from_python (length_obj, &length))
+ {
+ error = 1;
+ break;
+ }
+
+ write_memory (addr, buffer, length);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (error)
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+/* Destructor of Membuf objects. */
+
+static void
+mbpy_dealloc (PyObject *self)
+{
+ xfree (((membuf_object *) self)->buffer);
+ self->ob_type->tp_free (self);
+}
+
+/* Return a description of the Membuf object. */
+
+static PyObject *
+mbpy_str (PyObject *self)
+{
+ membuf_object *membuf_obj = (membuf_object *) self;
+
+ return PyString_FromFormat ("memory buffer for address %s, %s bytes long",
+ paddress (python_gdbarch, membuf_obj->addr),
+ pulongest (membuf_obj->length));
+}
+
+static Py_ssize_t
+get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+ membuf_object *membuf_obj = (membuf_object *) self;
+
+ if (segment)
+ {
+ PyErr_SetString (PyExc_SystemError,
+ "The memory buffer supports only one segment.");
+ return -1;
+ }
+
+ *ptrptr = membuf_obj->buffer;
+
+ return membuf_obj->length;
+}
+
+static Py_ssize_t
+get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+ return get_read_buffer (self, segment, ptrptr);
+}
+
+static Py_ssize_t
+get_seg_count (PyObject *self, Py_ssize_t *lenp)
+{
+ if (lenp)
+ *lenp = ((membuf_object *) self)->length;
+
+ return 1;
+}
+
+static Py_ssize_t
+get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
+{
+ void *ptr = NULL;
+ Py_ssize_t ret;
+
+ ret = get_read_buffer (self, segment, &ptr);
+ *ptrptr = (char *) ptr;
+
+ return ret;
+}
+
+/* Adds GDB value V to the pattern buffer in *PATTERN_BUF. If SIZE is not zero,
+ it specifies the number of bytes from V to copy to *PATTERN_BUF. The
+ function increases the size of *PATTERN_BUF as necessary, adjusting
+ *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. */
+
+static void
+add_value_pattern (struct value *v, int size, char **pattern_buf,
+ char **pattern_buf_end, ULONGEST *pattern_buf_size)
+{
+ int val_bytes;
+
+ if (size)
+ {
+ LONGEST x = value_as_long (v);
+
+ if (size == 1)
+ *(*pattern_buf_end)++ = x;
+ else
+ {
+ put_bits (x, *pattern_buf_end, size * 8,
+ gdbarch_byte_order (python_gdbarch) == BFD_ENDIAN_BIG);
+ *pattern_buf_end += size;
+ }
+ }
+ else
+ {
+ val_bytes = TYPE_LENGTH (value_type (v));
+
+ increase_pattern_buffer (pattern_buf, pattern_buf_end,
+ pattern_buf_size, val_bytes);
+
+ memcpy (*pattern_buf_end, value_contents_raw (v), val_bytes);
+ *pattern_buf_end += val_bytes;
+ }
+}
+
+/* This function does the actual work of constructing the pattern buffer from
+ OBJ. If OBJ is an object which implements the read buffer protocol (such
+ as a string, a byte array or gdb.Membuf), then its contents are directly
+ copied to *PATTERN_BUF. If it is a list, then this function is recursively
+ called for each of its elements. If OBJ is an object which can be converted
+ to a GDB value, then the contents of the value are copied to PATTERN_BUF.
+ If SIZE is different than zero, then it limits the number of bytes which
+ are copied to the buffer in case OBJ is converted to a GDB value. That
+ means that SIZE influences only Python scalars and gdb.Value objects.
+ The function increases the size of *PATTERN_BUF as necessary, adjusting
+ *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process.
+
+ Returns 1 on success or 0 on failure, with a Python exception set. This
+ function can also throw GDB exceptions. */
+
+static int
+add_pattern_element (PyObject *obj, int size, char **pattern_buf,
+ char **pattern_buf_end, ULONGEST *pattern_buf_size)
+{
+ if (PyObject_CheckReadBuffer (obj))
+ {
+ /* Handle string, Unicode string, byte array, gdb.Membuf and any other
+ object implementing the buffer protocol. The SIZE parameter is
+ ignored in this case. */
+
+ Py_ssize_t val_bytes;
+ const void *buffer;
+
+ if (PyObject_AsReadBuffer (obj, &buffer, &val_bytes) == -1)
+ return 0;
+
+ increase_pattern_buffer (pattern_buf, pattern_buf_end,
+ pattern_buf_size, val_bytes);
+
+ memcpy (*pattern_buf_end, buffer, val_bytes);
+ *pattern_buf_end += val_bytes;
+ }
+ else if (gdbpy_is_value_object (obj))
+ add_value_pattern (value_object_to_value (obj), size, pattern_buf,
+ pattern_buf_end, pattern_buf_size);
+ else if (PySequence_Check (obj))
+ {
+ /* Handle lists and tuples. */
+
+ Py_ssize_t i, num_objs;
+
+ num_objs = PySequence_Size (obj);
+ for (i = 0; i < num_objs; i++)
+ if (!add_pattern_element (PySequence_GetItem (obj, i), size,
+ pattern_buf, pattern_buf_end,
+ pattern_buf_size))
+ return 0;
+ }
+ else
+ {
+ /* See if we can convert from a Python object to a GDB value. */
+
+ struct value *v = convert_value_from_python (obj);
+
+ if (v)
+ add_value_pattern (v, size, pattern_buf, pattern_buf_end,
+ pattern_buf_size);
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Constructs the search pattern from OBJ, putting it in *PATTERN_BUFP, and its
+ size in *PATTERN_LENP. See the function add_pattern_element to learn how
+ the search pattern is obtained from OBJ.
+
+ Returns 1 on success or 0 on failure, with a Python exception set. This
+ function can also throw GDB exceptions. */
+
+static int
+get_search_pattern (PyObject *obj, int size, char **pattern_bufp,
+ ULONGEST *pattern_lenp)
+{
+ /* Buffer to hold the search pattern. */
+ char *pattern_buf;
+ /* Current size of search pattern buffer.
+ We realloc space as needed. */
+ ULONGEST pattern_buf_size;
+ /* Pointer to one past the last in-use part of pattern_buf. */
+ char *pattern_buf_end;
+ struct cleanup *old_cleanups;
+
+ allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size);
+ old_cleanups = make_cleanup (free_current_contents, &pattern_buf);
+
+ if (!add_pattern_element (obj, size, &pattern_buf, &pattern_buf_end,
+ &pattern_buf_size))
+ {
+ do_cleanups (old_cleanups);
+
+ return 0;
+ }
+
+ *pattern_bufp = pattern_buf;
+ *pattern_lenp = pattern_buf_end - pattern_buf;
+
+ discard_cleanups (old_cleanups);
+
+ return 1;
+}
+
+/* Implementation of
+ gdb.search_memory (address, length, pattern [, size] [, max_count]).
+ The third argument may be either a pattern, or a list or tupple of patterns
+ to be searched. Size is the size in bytes of each search query value, either
+ 1, 2, 4 or 8. Returns a list of the addresses where matches were found. */
+
+static PyObject *
+infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
+{
+ int size = 0;
+ unsigned int found_count = 0;
+ long max_count = 0;
+ CORE_ADDR start_addr, length;
+ char *pattern_buf;
+ static char *keywords[] = { "address", "length", "pattern", "size",
+ "max_count", NULL };
+ ULONGEST pattern_len, search_space_len;
+ PyObject *pattern, *list = NULL, *start_addr_obj, *length_obj;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO|il", keywords,
+ &start_addr_obj, &length_obj, &pattern,
+ &size, &max_count))
+ return NULL;
+
+ if (!max_count)
+ max_count = LONG_MAX;
+
+ if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8)
+ {
+ PyErr_SetString (PyExc_ValueError, "invalid pattern size");
+ return NULL;
+ }
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (get_addr_from_python (start_addr_obj, &start_addr)
+ && get_addr_from_python (length_obj, &length))
+ {
+ if (!length)
+ {
+ PyErr_SetString (PyExc_ValueError, "empty search range");
+ break;
+ }
+ /* Watch for overflows. */
+ else if (length > CORE_ADDR_MAX
+ || (start_addr + length - 1) < start_addr)
+ {
+ PyErr_SetString (PyExc_ValueError, "search range too large");
+ break;
+ }
+
+ search_space_len = length;
+
+ if (get_search_pattern (pattern, size, &pattern_buf, &pattern_len))
+ {
+ /* Any cleanups get automatically executed on an exception. */
+ struct cleanup *cleanups = make_cleanup (xfree, pattern_buf);
+
+ list = PyList_New (0);
+
+ while (search_space_len >= pattern_len && found_count < max_count)
+ {
+ CORE_ADDR found_addr;
+ int found;
+
+ found = search_memory (&start_addr, &search_space_len,
+ pattern_buf, pattern_len, &found_addr);
+ if (found <= 0)
+ break;
+
+ PyList_Append (list, PyLong_FromUnsignedLong (found_addr));
+ ++found_count;
+ }
+
+ do_cleanups (cleanups);
+ }
+ }
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ return list;
+}
+
+
+
+void
+gdbpy_initialize_inferior (void)
+{
+ if (PyType_Ready (&inferior_object_type) < 0)
+ return;
+
+ Py_INCREF (&inferior_object_type);
+ PyModule_AddObject (gdb_module, "Inferior",
+ (PyObject *) &inferior_object_type);
+
+ gdbpy_inferior_list = NULL;
+ ninferiors = 0;
+
+ observer_attach_inferior_appeared (add_inferior_object);
+ observer_attach_inferior_exit (delete_inferior_object);
+ observer_attach_new_thread (add_thread_object);
+ observer_attach_thread_exit (delete_thread_object);
+
+ if (PyType_Ready (&membuf_object_type) < 0)
+ return;
+
+ Py_INCREF (&membuf_object_type);
+ PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type);
+}
+
+
+
+static PyGetSetDef inferior_object_getset[] =
+{
+ { "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL },
+ { "pid", infpy_get_pid, NULL, "PID of inferior, as assigned by the OS.",
+ NULL },
+ { "was_attached", infpy_get_was_attached, NULL,
+ "True if the inferior was created using 'attach'.", NULL },
+
+ { NULL }
+};
+
+static PyMethodDef inferior_object_methods[] =
+{
+ { "threads", infpy_threads, METH_NOARGS,
+ "Return all the threads of this inferior." },
+
+ { "read_memory", infpy_read_memory, METH_VARARGS,
+ "read_memory (address, length) -> buffer\n\
+Return a buffer object for reading from the inferior's memory." },
+ { "write_memory", infpy_write_memory, METH_VARARGS,
+ "write_memory (address, buffer [, length])\n\
+Write the given buffer object to the inferior's memory." },
+ { "search_memory", (PyCFunction) infpy_search_memory, METH_VARARGS | METH_KEYWORDS,
+ "search_memory (address, length, pattern [, size] [, max_count]) -> list\n\
+Return a list with the addresses where matches were found." },
+
+ { NULL }
+};
+
+static PyTypeObject inferior_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /* ob_size */
+ "gdb.Inferior", /* tp_name */
+ sizeof (inferior_object), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */
+ "GDB inferior object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ inferior_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ inferior_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
+
+
+
+/* Python doesn't provide a decent way to get compatibility here. */
+#if HAVE_LIBPYTHON2_4
+#define CHARBUFFERPROC_NAME getcharbufferproc
+#else
+#define CHARBUFFERPROC_NAME charbufferproc
+#endif
+
+static PyBufferProcs buffer_procs = {
+ get_read_buffer,
+ get_write_buffer,
+ get_seg_count,
+ /* The cast here works around a difference between Python 2.4 and
+ Python 2.5. */
+ (CHARBUFFERPROC_NAME) get_char_buffer
+};
+
+static PyTypeObject membuf_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Membuf", /*tp_name*/
+ sizeof (membuf_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ mbpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ mbpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &buffer_procs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB memory buffer object", /*tp_doc*/
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c
new file mode 100644
index 0000000..21e4eab
--- /dev/null
+++ b/gdb/python/py-infthread.c
@@ -0,0 +1,285 @@
+/* Python interface to inferior threads.
+
+ Copyright (C) 2009 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 "exceptions.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "python-internal.h"
+
+static PyTypeObject thread_object_type;
+
+/* Require that INFERIOR be a valid inferior ID. */
+#define THPY_REQUIRE_VALID(Thread) \
+ do { \
+ if (!Thread->thread) \
+ { \
+ PyErr_SetString (PyExc_RuntimeError, \
+ "thread no longer exists"); \
+ return NULL; \
+ } \
+ } while (0)
+
+
+
+thread_object *
+create_thread_object (struct thread_info *tp)
+{
+ thread_object *thread_obj;
+
+ thread_obj = PyObject_New (thread_object, &thread_object_type);
+ if (!thread_obj)
+ return NULL;
+
+ thread_obj->thread = tp;
+ thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
+ Py_INCREF (thread_obj->inf_obj);
+
+ return thread_obj;
+}
+
+
+
+static void
+thpy_dealloc (PyObject *self)
+{
+ Py_DECREF (((thread_object *) self)->inf_obj);
+ self->ob_type->tp_free (self);
+}
+
+static PyObject *
+thpy_get_num (PyObject *self, void *closure)
+{
+ thread_object *thread_obj = (thread_object *) self;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ return PyLong_FromLong (thread_obj->thread->num);
+}
+
+
+
+/* Implementation of Inferior.frames () -> (gdb.Frame, ...).
+ Returns a tuple of all frame objects. */
+PyObject *
+thpy_frames (PyObject *self, PyObject *args)
+{
+ int result = 0;
+ struct frame_info *frame;
+ PyObject *frame_obj;
+ PyObject *list, *tuple;
+ thread_object *thread_obj = (thread_object *) self;
+ struct cleanup *cleanup;
+ volatile struct gdb_exception except;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ list = PyList_New (0);
+ if (list == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError, "Could not allocate frames list.");
+ return NULL;
+ }
+
+ cleanup = make_cleanup_restore_current_thread ();
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch_to_thread (thread_obj->thread->ptid);
+
+ for (frame = get_current_frame (); frame; frame = get_prev_frame (frame))
+ {
+ frame_obj = frame_info_to_frame_object (frame);
+ if (frame_obj == NULL)
+ {
+ Py_DECREF (list);
+ list = NULL;
+ break;
+ }
+
+ PyList_Append (list, frame_obj);
+ }
+ }
+ if (except.reason < 0)
+ {
+ Py_DECREF (list);
+ return PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+ "%s", except.message);
+ }
+
+ do_cleanups (cleanup);
+
+ if (list)
+ {
+ tuple = PyList_AsTuple (list);
+ Py_DECREF (list);
+ }
+ else
+ tuple = NULL;
+
+ return tuple;
+}
+
+/* Implementation of InferiorThread.newest_frame () -> gdb.Frame.
+ Returns the newest frame object. */
+PyObject *
+thpy_newest_frame (PyObject *self, PyObject *args)
+{
+ struct frame_info *frame;
+ PyObject *frame_obj = NULL; /* Initialize to appease gcc warning. */
+ thread_object *thread_obj = (thread_object *) self;
+ struct cleanup *cleanup;
+ volatile struct gdb_exception except;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ cleanup = make_cleanup_restore_current_thread ();
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch_to_thread (thread_obj->thread->ptid);
+
+ frame = get_current_frame ();
+ frame_obj = frame_info_to_frame_object (frame);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ do_cleanups (cleanup);
+
+ return frame_obj;
+}
+
+/* Implementation of InferiorThread.switch ().
+ Makes this the GDB selected thread. */
+static PyObject *
+thpy_switch (PyObject *self, PyObject *args)
+{
+ thread_object *thread_obj = (thread_object *) self;
+ struct cleanup *cleanup;
+ volatile struct gdb_exception except;
+
+ THPY_REQUIRE_VALID (thread_obj);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ switch_to_thread (thread_obj->thread->ptid);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ Py_RETURN_NONE;
+}
+
+
+
+/* Implementation of gdb.selected_thread () -> gdb.InferiorThread.
+ Returns the selected thread object. */
+PyObject *
+gdbpy_selected_thread (PyObject *self, PyObject *args)
+{
+ PyObject *thread_obj;
+
+ thread_obj = (PyObject *) find_thread_object (inferior_ptid);
+ if (thread_obj)
+ {
+ Py_INCREF (thread_obj);
+ return thread_obj;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+
+void
+gdbpy_initialize_thread (void)
+{
+ if (PyType_Ready (&thread_object_type) < 0)
+ return;
+
+ Py_INCREF (&thread_object_type);
+ PyModule_AddObject (gdb_module, "InferiorThread",
+ (PyObject *) &thread_object_type);
+}
+
+
+
+static PyGetSetDef thread_object_getset[] =
+{
+ { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
+
+ { NULL }
+};
+
+static PyMethodDef thread_object_methods[] =
+{
+ { "frames", thpy_frames, METH_NOARGS,
+ "frames () -> (gdb.Frame, ...)\n\
+Return a tuple containing all frames in the thread." },
+ { "newest_frame", thpy_newest_frame, METH_NOARGS,
+ "newest_frame () -> gdb.Frame\n\
+Return the newest frame in the thread." },
+ { "switch", thpy_switch, METH_NOARGS,
+ "switch ()\n\
+Makes this the GDB selected thread." },
+
+ { NULL }
+};
+
+static PyTypeObject thread_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.InferiorThread", /*tp_name*/
+ sizeof (thread_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ thpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
+ "GDB thread object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ thread_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ thread_object_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0 /* tp_alloc */
+};
diff --git a/gdb/python/py-membuf.c b/gdb/python/py-membuf.c
new file mode 100644
index 0000000..7bc294c
--- /dev/null
+++ b/gdb/python/py-membuf.c
@@ -0,0 +1,268 @@
+/* Python interface to the inferior memory.
+
+ Copyright (C) 2008, 2009 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 "exceptions.h"
+#include "gdbcore.h"
+#include "python-internal.h"
+
+typedef struct {
+ PyObject_HEAD
+ void *buffer;
+
+ /* These are kept just for mbpy_str. */
+ CORE_ADDR addr;
+ CORE_ADDR length;
+} membuf_object;
+
+static PyTypeObject membuf_object_type;
+
+/* Implementation of gdb.read_memory (address, length).
+ Returns a Python buffer object with LENGTH bytes of the inferior's memory
+ at ADDRESS. Both arguments are integers. */
+
+PyObject *
+gdbpy_read_memory (PyObject *self, PyObject *args)
+{
+ int error = 0;
+ CORE_ADDR addr, length;
+ void *buffer = NULL;
+ membuf_object *membuf_obj;
+ PyObject *addr_obj, *length_obj;
+ struct cleanup *cleanups = NULL;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "OO", &addr_obj, &length_obj))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (!get_addr_from_python (addr_obj, &addr)
+ || !get_addr_from_python (length_obj, &length))
+ {
+ error = 1;
+ break;
+ }
+
+ buffer = xmalloc (length);
+ cleanups = make_cleanup (xfree, buffer);
+
+ read_memory (addr, buffer, length);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (error)
+ return NULL;
+
+ discard_cleanups (cleanups);
+
+ membuf_obj = PyObject_New (membuf_object, &membuf_object_type);
+ if (membuf_obj == NULL)
+ {
+ xfree (buffer);
+ PyErr_SetString (PyExc_MemoryError,
+ "Could not allocate memory buffer object.");
+ return NULL;
+ }
+
+ membuf_obj->buffer = buffer;
+ membuf_obj->addr = addr;
+ membuf_obj->length = length;
+
+ return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
+ Py_END_OF_BUFFER);
+}
+
+/* Implementation of gdb.write_memory (address, buffer [, length]).
+ Writes the contents of BUFFER (a Python object supporting the read buffer
+ protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from
+ BUFFER, or its entire contents if the argument is not provided. The
+ function returns nothing. */
+
+PyObject *
+gdbpy_write_memory (PyObject *self, PyObject *args)
+{
+ int buf_len, error = 0;
+ const char *buffer;
+ CORE_ADDR addr, length;
+ PyObject *addr_obj, *length_obj = NULL;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "Os#|O", &addr_obj, &buffer, &buf_len,
+ &length_obj))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (!get_addr_from_python (addr_obj, &addr))
+ {
+ error = 1;
+ break;
+ }
+
+ if (!length_obj)
+ length = buf_len;
+ else if (!get_addr_from_python (length_obj, &length))
+ {
+ error = 1;
+ break;
+ }
+
+ write_memory (addr, buffer, length);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ if (error)
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+
+/* Destructor of Membuf objects. */
+
+static void
+mbpy_dealloc (PyObject *self)
+{
+ xfree (((membuf_object *) self)->buffer);
+ self->ob_type->tp_free (self);
+}
+
+/* Return a description of the Membuf object. */
+
+static PyObject *
+mbpy_str (PyObject *self)
+{
+ membuf_object *membuf_obj = (membuf_object *) self;
+
+ return PyString_FromFormat ("memory buffer for address %s, %s bytes long",
+ paddress (membuf_obj->addr),
+ pulongest (membuf_obj->length));
+}
+
+static Py_ssize_t
+get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+ membuf_object *membuf_obj = (membuf_object *) self;
+
+ if (segment)
+ {
+ PyErr_SetString (PyExc_SystemError,
+ "The memory buffer supports only one segment.");
+ return -1;
+ }
+
+ *ptrptr = membuf_obj->buffer;
+
+ return membuf_obj->length;
+}
+
+static Py_ssize_t
+get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
+{
+ return get_read_buffer (self, segment, ptrptr);
+}
+
+static Py_ssize_t
+get_seg_count (PyObject *self, Py_ssize_t *lenp)
+{
+ if (lenp)
+ *lenp = ((membuf_object *) self)->length;
+
+ return 1;
+}
+
+static Py_ssize_t
+get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
+{
+ void *ptr = NULL;
+ Py_ssize_t ret;
+
+ ret = get_read_buffer (self, segment, &ptr);
+ *ptrptr = (char *) ptr;
+
+ return ret;
+}
+
+/* Python doesn't provide a decent way to get compatibility here. */
+#if HAVE_LIBPYTHON2_4
+#define CHARBUFFERPROC_NAME getcharbufferproc
+#else
+#define CHARBUFFERPROC_NAME charbufferproc
+#endif
+
+static PyBufferProcs buffer_procs = {
+ get_read_buffer,
+ get_write_buffer,
+ get_seg_count,
+ /* The cast here works around a difference between Python 2.4 and
+ Python 2.5. */
+ (CHARBUFFERPROC_NAME) get_char_buffer
+};
+
+static PyTypeObject membuf_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Membuf", /*tp_name*/
+ sizeof (membuf_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ mbpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ mbpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ &buffer_procs, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB memory buffer object", /*tp_doc*/
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
+
+void
+gdbpy_initialize_membuf (void)
+{
+ if (PyType_Ready (&membuf_object_type) < 0)
+ return;
+
+ Py_INCREF (&membuf_object_type);
+ PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type);
+}
diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c
new file mode 100644
index 0000000..1f591a8
--- /dev/null
+++ b/gdb/python/py-param.c
@@ -0,0 +1,606 @@
+/* gdb parameters implemented in Python
+
+ Copyright (C) 2008, 2009 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 "value.h"
+#include "exceptions.h"
+#include "python-internal.h"
+#include "charset.h"
+#include "gdbcmd.h"
+#include "cli/cli-decode.h"
+#include "completer.h"
+
+/* Parameter constants and their values. */
+struct parm_constant
+{
+ char *name;
+ int value;
+};
+
+struct parm_constant parm_constants[] =
+{
+ { "PARAM_BOOLEAN", var_boolean },
+ { "PARAM_AUTO_BOOLEAN", var_auto_boolean },
+ { "PARAM_UINTEGER", var_uinteger },
+ { "PARAM_INTEGER", var_integer },
+ { "PARAM_STRING", var_string },
+ { "PARAM_STRING_NOESCAPE", var_string_noescape },
+ { "PARAM_OPTIONAL_FILENAME", var_optional_filename },
+ { "PARAM_FILENAME", var_filename },
+ { "PARAM_ZINTEGER", var_zinteger },
+ { "PARAM_ENUM", var_enum },
+ { NULL, 0 }
+};
+
+/* A union that can hold anything described by enum var_types. */
+union parmpy_variable
+{
+ /* Hold an integer value, for boolean and integer types. */
+ int intval;
+
+ /* Hold an auto_boolean. */
+ enum auto_boolean autoboolval;
+
+ /* Hold an unsigned integer value, for uinteger. */
+ unsigned int uintval;
+
+ /* Hold a string, for the various string types. */
+ char *stringval;
+
+ /* Hold a string, for enums. */
+ const char *cstringval;
+};
+
+/* A gdb parameter. */
+struct parmpy_object
+{
+ PyObject_HEAD
+
+ /* The type of the parameter. */
+ enum var_types type;
+
+ /* The value of the parameter. */
+ union parmpy_variable value;
+
+ /* For an enum command, the possible values. The vector is
+ allocated with xmalloc, as is each element. It is
+ NULL-terminated. */
+ const char **enumeration;
+};
+
+typedef struct parmpy_object parmpy_object;
+
+static PyTypeObject parmpy_object_type;
+
+/* Some handy string constants. */
+static PyObject *set_doc_cst;
+static PyObject *show_doc_cst;
+
+
+
+/* Get an attribute. */
+static PyObject *
+get_attr (PyObject *obj, PyObject *attr_name)
+{
+ if (PyString_Check (attr_name)
+ && ! strcmp (PyString_AsString (attr_name), "value"))
+ {
+ parmpy_object *self = (parmpy_object *) obj;
+ return gdbpy_parameter_value (self->type, &self->value);
+ }
+
+ return PyObject_GenericGetAttr (obj, attr_name);
+}
+
+/* Set a parameter value from a Python value. Return 0 on success, -1
+ on failure. */
+static int
+set_parameter_value (parmpy_object *self, PyObject *value)
+{
+ int cmp;
+
+ switch (self->type)
+ {
+ case var_string:
+ case var_string_noescape:
+ case var_optional_filename:
+ case var_filename:
+ if (! gdbpy_is_string (value)
+ && (self->type == var_filename
+ || value != Py_None))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "string required");
+ return -1;
+ }
+ if (self->value.stringval)
+ xfree (self->value.stringval);
+ if (value == Py_None)
+ {
+ if (self->type == var_optional_filename)
+ self->value.stringval = xstrdup ("");
+ else
+ self->value.stringval = NULL;
+ }
+ else
+ self->value.stringval = python_string_to_host_string (value);
+ break;
+
+ case var_enum:
+ {
+ int i;
+ char *str;
+
+ if (! gdbpy_is_string (value))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "string required");
+ return -1;
+ }
+
+ str = python_string_to_host_string (value);
+ for (i = 0; self->enumeration[i]; ++i)
+ if (! strcmp (self->enumeration[i], str))
+ break;
+ xfree (str);
+ if (! self->enumeration[i])
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "value must be member of enumeration");
+ return -1;
+ }
+ self->value.cstringval = self->enumeration[i];
+ break;
+ }
+
+ case var_boolean:
+ if (! PyBool_Check (value))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "boolean required");
+ return -1;
+ }
+ cmp = PyObject_IsTrue (value);
+ if (cmp < 0)
+ return -1;
+ self->value.intval = cmp;
+ break;
+
+ case var_auto_boolean:
+ if (! PyBool_Check (value) && value != Py_None)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "boolean or None required");
+ return -1;
+ }
+
+ if (value == Py_None)
+ self->value.autoboolval = AUTO_BOOLEAN_AUTO;
+ else
+ {
+ cmp = PyObject_IsTrue (value);
+ if (cmp < 0 )
+ return -1;
+ if (cmp == 1)
+ self->value.autoboolval = AUTO_BOOLEAN_TRUE;
+ else
+ self->value.autoboolval = AUTO_BOOLEAN_FALSE;
+
+ break;
+ }
+
+ case var_integer:
+ case var_zinteger:
+ case var_uinteger:
+ {
+ long l;
+ int ok;
+
+ if (! PyInt_Check (value))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "value must be integer");
+ return -1;
+ }
+
+ l = PyInt_AsLong (value);
+ if (self->type == var_uinteger)
+ {
+ ok = (l >= 0 && l <= UINT_MAX);
+ if (l == 0)
+ l = UINT_MAX;
+ }
+ else if (self->type == var_integer)
+ {
+ ok = (l >= INT_MIN && l <= INT_MAX);
+ if (l == 0)
+ l = INT_MAX;
+ }
+ else
+ ok = (l >= INT_MIN && l <= INT_MAX);
+
+ if (! ok)
+ {
+ PyErr_SetString (PyExc_RuntimeError, "range exceeded");
+ return -1;
+ }
+
+ self->value.intval = (int) l;
+ break;
+ }
+
+ default:
+ PyErr_SetString (PyExc_RuntimeError, "programmer error: unhandled type");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Set an attribute. */
+static int
+set_attr (PyObject *obj, PyObject *attr_name, PyObject *val)
+{
+ if (PyString_Check (attr_name)
+ && ! strcmp (PyString_AsString (attr_name), "value"))
+ {
+ if (!val)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "cannot delete a parameter's value");
+ return -1;
+ }
+ return set_parameter_value ((parmpy_object *) obj, val);
+ }
+
+ return PyObject_GenericSetAttr (obj, attr_name, val);
+}
+
+
+
+/* A helper function that dispatches to the appropriate add_setshow
+ function. */
+static void
+add_setshow_generic (int parmclass, enum command_class cmdclass,
+ char *cmd_name, parmpy_object *self,
+ char *set_doc, char *show_doc, char *help_doc,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ switch (parmclass)
+ {
+ case var_boolean:
+ add_setshow_boolean_cmd (cmd_name, cmdclass, &self->value.intval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_auto_boolean:
+ add_setshow_auto_boolean_cmd (cmd_name, cmdclass,
+ &self->value.autoboolval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_uinteger:
+ add_setshow_uinteger_cmd (cmd_name, cmdclass, &self->value.uintval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_integer:
+ add_setshow_integer_cmd (cmd_name, cmdclass, &self->value.intval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_string:
+ add_setshow_string_cmd (cmd_name, cmdclass, &self->value.stringval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_string_noescape:
+ add_setshow_string_noescape_cmd (cmd_name, cmdclass,
+ &self->value.stringval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_optional_filename:
+ add_setshow_optional_filename_cmd (cmd_name, cmdclass,
+ &self->value.stringval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_filename:
+ add_setshow_filename_cmd (cmd_name, cmdclass, &self->value.stringval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_zinteger:
+ add_setshow_zinteger_cmd (cmd_name, cmdclass, &self->value.intval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ break;
+
+ case var_enum:
+ add_setshow_enum_cmd (cmd_name, cmdclass, self->enumeration,
+ &self->value.cstringval,
+ set_doc, show_doc, help_doc,
+ NULL, NULL, set_list, show_list);
+ /* Initialize the value, just in case. */
+ self->value.cstringval = self->enumeration[0];
+ break;
+ }
+}
+
+/* A helper which computes enum values. Returns 1 on success, 0 on
+ error. */
+static int
+compute_enum_values (parmpy_object *self, PyObject *enum_values)
+{
+ Py_ssize_t size, i;
+
+ if (! enum_values)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "enumeration required for PARAM_ENUM");
+ return 0;
+ }
+
+ if (! PySequence_Check (enum_values))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "enumeration is not a sequence");
+ return 0;
+ }
+
+ size = PySequence_Size (enum_values);
+ if (size < 0)
+ return 0;
+ if (size == 0)
+ {
+ PyErr_SetString (PyExc_RuntimeError, "empty enumeration");
+ return 0;
+ }
+
+ self->enumeration = xmalloc ((size + 1) * sizeof (char *));
+ memset (self->enumeration, 0, (size + 1) * sizeof (char *));
+
+ for (i = 0; i < size; ++i)
+ {
+ PyObject *item = PySequence_GetItem (enum_values, i);
+ if (! item)
+ return 0;
+ if (! gdbpy_is_string (item))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "enumeration item not a string");
+ return 0;
+ }
+ self->enumeration[i] = python_string_to_host_string (item);
+ }
+
+ return 1;
+}
+
+/* A helper function which returns a documentation string for an
+ object. */
+static char *
+get_doc_string (PyObject *object, PyObject *attr)
+{
+ char *result = NULL;
+ if (PyObject_HasAttr (object, attr))
+ {
+ PyObject *ds_obj = PyObject_GetAttr (object, attr);
+ if (ds_obj && gdbpy_is_string (ds_obj))
+ result = python_string_to_host_string (ds_obj);
+ }
+ if (! result)
+ result = xstrdup ("This command is not documented.");
+ return result;
+}
+
+/* Object initializer; sets up gdb-side structures for command.
+
+ Use: __init__(NAME, CMDCLASS, PARMCLASS, [ENUM])
+
+ NAME is the name of the parameter. It may consist of multiple
+ words, in which case the final word is the name of the new command,
+ and earlier words must be prefix commands.
+
+ CMDCLASS is the kind of command. It should be one of the COMMAND_*
+ constants defined in the gdb module.
+
+ PARMCLASS is the type of the parameter. It should be one of the
+ PARAM_* constants defined in the gdb module.
+
+ If PARMCLASS is PARAM_ENUM, then the final argument should be a
+ collection of strings. These strings are the valid values for this
+ parameter.
+
+ The documentation for the parameter is taken from the doc string
+ for the python class.
+
+*/
+static int
+parmpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+{
+ parmpy_object *obj = (parmpy_object *) self;
+ char *name;
+ char *set_doc, *show_doc, *doc;
+ char *cmd_name;
+ int parmclass, cmdtype;
+ PyObject *enum_values = NULL;
+ struct cmd_list_element *cmd_list;
+ struct cmd_list_element **set_list, **show_list;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass,
+ &enum_values))
+ return -1;
+
+ if (cmdtype != no_class && cmdtype != class_run
+ && cmdtype != class_vars && cmdtype != class_stack
+ && cmdtype != class_files && cmdtype != class_support
+ && cmdtype != class_info && cmdtype != class_breakpoint
+ && cmdtype != class_trace && cmdtype != class_obscure
+ && cmdtype != class_maintenance)
+ {
+ PyErr_Format (PyExc_RuntimeError, "invalid command class argument");
+ return -1;
+ }
+
+ if (parmclass != var_boolean && parmclass != var_auto_boolean
+ && parmclass != var_uinteger && parmclass != var_integer
+ && parmclass != var_string && parmclass != var_string_noescape
+ && parmclass != var_optional_filename && parmclass != var_filename
+ && parmclass != var_zinteger && parmclass != var_enum)
+ {
+ PyErr_SetString (PyExc_RuntimeError, "invalid parameter class argument");
+ return -1;
+ }
+
+ if (enum_values && parmclass != var_enum)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "only PARAM_ENUM accepts a fourth argument");
+ return -1;
+ }
+ if (parmclass == var_enum)
+ {
+ if (! compute_enum_values (obj, enum_values))
+ return -1;
+ }
+
+ obj->type = (enum var_types) parmclass;
+ memset (&obj->value, 0, sizeof (obj->value));
+ obj->enumeration = NULL;
+
+ cmd_name = gdbpy_parse_command_name (name, &set_list, &setlist);
+ if (! cmd_name)
+ return -1;
+ xfree (cmd_name);
+ cmd_name = gdbpy_parse_command_name (name, &show_list, &showlist);
+ if (! cmd_name)
+ return -1;
+
+ /* FIXME: there is no way to register a destructor function for
+ set/show commands. So, these are leaked. */
+ set_doc = get_doc_string (self, set_doc_cst);
+ show_doc = get_doc_string (self, show_doc_cst);
+ doc = get_doc_string (self, gdbpy_doc_cst);
+
+ Py_INCREF (self);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ add_setshow_generic (parmclass, (enum command_class) cmdtype,
+ cmd_name, obj,
+ set_doc, show_doc,
+ doc, set_list, show_list);
+ }
+ if (except.reason < 0)
+ {
+ xfree (cmd_name);
+ xfree (set_doc);
+ xfree (show_doc);
+ xfree (doc);
+ Py_DECREF (self);
+ PyErr_Format (except.reason == RETURN_QUIT
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
+ "%s", except.message);
+ return -1;
+ }
+ return 0;
+}
+
+
+
+/* Initialize the 'parameters' module. */
+void
+gdbpy_initialize_parameters (void)
+{
+ int i;
+
+ if (PyType_Ready (&parmpy_object_type) < 0)
+ return;
+
+ set_doc_cst = PyString_FromString ("set_doc");
+ if (! set_doc_cst)
+ return;
+ show_doc_cst = PyString_FromString ("show_doc");
+ if (! show_doc_cst)
+ return;
+
+ for (i = 0; parm_constants[i].name; ++i)
+ {
+ if (PyModule_AddIntConstant (gdb_module,
+ parm_constants[i].name,
+ parm_constants[i].value) < 0)
+ return;
+ }
+
+ Py_INCREF (&parmpy_object_type);
+ PyModule_AddObject (gdb_module, "Parameter",
+ (PyObject *) &parmpy_object_type);
+}
+
+
+
+static PyTypeObject parmpy_object_type =
+{
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Parameter", /*tp_name*/
+ sizeof (parmpy_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ get_attr, /*tp_getattro*/
+ set_attr, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "GDB parameter object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ parmpy_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew /* tp_new */
+};
diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
index 193f97c..2f2b365 100644
--- a/gdb/python/py-prettyprint.c
+++ b/gdb/python/py-prettyprint.c
@@ -143,10 +143,15 @@ pretty_print_one_value (PyObject *printer, struct value **out_value)
if (! gdbpy_is_string (result) && ! gdbpy_is_lazy_string (result))
{
*out_value = convert_value_from_python (result);
- if (PyErr_Occurred ())
- *out_value = NULL;
- Py_DECREF (result);
- result = NULL;
+ if (PyErr_Occurred ())
+ *out_value = NULL;
+ else
+ /* We must increment the value's refcount, because we
+ are about to decref RESULT, and this may result in
+ the value being destroyed. */
+ value_incref (*out_value);
+ Py_DECREF (result);
+ result = NULL;
}
}
}
@@ -604,14 +609,7 @@ gdbpy_get_varobj_pretty_printer (struct value *value)
{
PyObject *val_obj;
PyObject *pretty_printer = NULL;
- volatile struct gdb_exception except;
- TRY_CATCH (except, RETURN_MASK_ALL)
- {
- value = value_copy (value);
- }
- GDB_PY_HANDLE_EXCEPTION (except);
-
val_obj = value_to_value_object (value);
if (! val_obj)
return NULL;
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
new file mode 100644
index 0000000..03d43c1
--- /dev/null
+++ b/gdb/python/py-symbol.c
@@ -0,0 +1,336 @@
+/* Python interface to symbols.
+
+ Copyright (C) 2008, 2009 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 "block.h"
+#include "exceptions.h"
+#include "frame.h"
+#include "symtab.h"
+#include "python-internal.h"
+
+typedef struct {
+ PyObject_HEAD
+ struct symbol *symbol;
+} symbol_object;
+
+
+static PyObject *
+sympy_str (PyObject *self)
+{
+ int ret;
+ char *s;
+ PyObject *result;
+
+ ret = asprintf (&s, "symbol for %s",
+ SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol));
+ if (ret < 0)
+ Py_RETURN_NONE;
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static PyObject *
+sympy_get_value (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ switch (SYMBOL_CLASS (self_sym->symbol))
+ {
+ case LOC_BLOCK:
+ return block_to_block_object (SYMBOL_BLOCK_VALUE (self_sym->symbol));
+ }
+
+ PyErr_SetString (PyExc_NotImplementedError,
+ "Symbol type not yet supported in Python scripts.");
+ return NULL;
+}
+
+static PyObject *
+sympy_get_symtab (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return symtab_to_symtab_object (SYMBOL_SYMTAB (self_sym->symbol));
+}
+
+static PyObject *
+sympy_get_name (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return PyString_FromString (SYMBOL_NATURAL_NAME (self_sym->symbol));
+}
+
+static PyObject *
+sympy_get_linkage_name (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return PyString_FromString (SYMBOL_LINKAGE_NAME (self_sym->symbol));
+}
+
+static PyObject *
+sympy_get_print_name (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return PyString_FromString (SYMBOL_PRINT_NAME (self_sym->symbol));
+}
+
+static PyObject *
+sympy_get_addr_class (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return PyInt_FromLong (SYMBOL_CLASS (self_sym->symbol));
+}
+
+static PyObject *
+sympy_is_argument (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+
+ return PyBool_FromLong (SYMBOL_IS_ARGUMENT (self_sym->symbol));
+}
+
+static PyObject *
+sympy_is_constant (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+ enum address_class class = SYMBOL_CLASS (self_sym->symbol);
+
+ return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES);
+}
+
+static PyObject *
+sympy_is_function (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+ enum address_class class = SYMBOL_CLASS (self_sym->symbol);
+
+ return PyBool_FromLong (class == LOC_BLOCK);
+}
+
+static PyObject *
+sympy_is_variable (PyObject *self, void *closure)
+{
+ symbol_object *self_sym = (symbol_object *) self;
+ enum address_class class = SYMBOL_CLASS (self_sym->symbol);
+
+ return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol)
+ && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC
+ || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT));
+}
+
+PyObject *
+symbol_to_symbol_object (struct symbol *sym)
+{
+ symbol_object *sym_obj;
+
+ sym_obj = PyObject_New (symbol_object, &symbol_object_type);
+ if (sym_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError, "Could not allocate symbol object.");
+ return NULL;
+ }
+
+ sym_obj->symbol = sym;
+
+ return (PyObject *) sym_obj;
+}
+
+struct symbol *
+symbol_object_to_symbol (PyObject *obj)
+{
+ if (! PyObject_TypeCheck (obj, &symbol_object_type))
+ return NULL;
+ return ((symbol_object *) obj)->symbol;
+}
+
+/* Implementation of
+ gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)
+ A tuple with 2 elements is always returned. The first is the symbol
+ object or None, the second is a boolean with the value of
+ is_a_field_of_this (see comment in lookup_symbol_in_language). */
+
+PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw)
+{
+ int domain = VAR_DOMAIN, is_a_field_of_this = 0;
+ const char *name;
+ static char *keywords[] = { "name", "block", "domain", NULL };
+ struct symbol *symbol;
+ PyObject *block_obj = NULL, *ret_tuple, *sym_obj, *bool_obj;
+ struct block *block = NULL;
+
+ if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!i", keywords, &name,
+ &block_object_type, &block_obj, &domain))
+ return NULL;
+
+ if (block_obj)
+ block = block_object_to_block (block_obj);
+ else
+ {
+ struct frame_info *selected_frame;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ selected_frame = get_selected_frame (_("No frame selected."));
+ block = block_for_pc (get_frame_address_in_block (selected_frame));
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+
+ symbol = lookup_symbol (name, block, domain, &is_a_field_of_this);
+
+ ret_tuple = PyTuple_New (2);
+ if (!ret_tuple)
+ {
+ PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object.");
+ return NULL;
+ }
+
+ if (symbol)
+ {
+ sym_obj = symbol_to_symbol_object (symbol);
+ if (!sym_obj)
+ {
+ Py_DECREF (ret_tuple);
+ return NULL;
+ }
+ }
+ else
+ {
+ sym_obj = Py_None;
+ Py_INCREF (Py_None);
+ }
+ PyTuple_SET_ITEM (ret_tuple, 0, sym_obj);
+
+ bool_obj = is_a_field_of_this? Py_True : Py_False;
+ Py_INCREF (bool_obj);
+ PyTuple_SET_ITEM (ret_tuple, 1, bool_obj);
+
+ return ret_tuple;
+}
+
+void
+gdbpy_initialize_symbols (void)
+{
+ if (PyType_Ready (&symbol_object_type) < 0)
+ return;
+
+ /* FIXME: These would probably be best exposed as class attributes of Symbol,
+ but I don't know how to do it except by messing with the type's dictionary.
+ That seems too messy. */
+ /* FIXME 2: Some of these were removed from GDB since I first wrote this code,
+ so it's probably a good idea not to expose them to Python. */
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNDEF", LOC_UNDEF);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST", LOC_CONST);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_STATIC", LOC_STATIC);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGISTER", LOC_REGISTER);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_ARG", LOC_ARG);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REF_ARG", LOC_REF_ARG);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LOCAL", LOC_LOCAL);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_TYPEDEF", LOC_TYPEDEF);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LABEL", LOC_LABEL);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_BLOCK", LOC_BLOCK);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST_BYTES",
+ LOC_CONST_BYTES);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNRESOLVED", LOC_UNRESOLVED);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_OPTIMIZED_OUT",
+ LOC_OPTIMIZED_OUT);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_COMPUTED", LOC_COMPUTED);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGPARM_ADDR",
+ LOC_REGPARM_ADDR);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_UNDEF_DOMAIN", UNDEF_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_VAR_DOMAIN", VAR_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_STRUCT_DOMAIN", STRUCT_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_LABEL_DOMAIN", LABEL_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_VARIABLES_DOMAIN",
+ VARIABLES_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_FUNCTIONS_DOMAIN",
+ FUNCTIONS_DOMAIN);
+ PyModule_AddIntConstant (gdb_module, "SYMBOL_TYPES_DOMAIN", TYPES_DOMAIN);
+
+ Py_INCREF (&symbol_object_type);
+ PyModule_AddObject (gdb_module, "Symbol", (PyObject *) &symbol_object_type);
+}
+
+
+
+static PyGetSetDef symbol_object_getset[] = {
+ { "value", sympy_get_value, NULL, "Value of the symbol.", NULL },
+ { "symtab", sympy_get_symtab, NULL,
+ "Symbol table in which the symbol appears.", NULL },
+ { "name", sympy_get_name, NULL,
+ "Name of the symbol, as it appears in the source code.", NULL },
+ { "linkage_name", sympy_get_linkage_name, NULL,
+ "Name of the symbol, as used by the linker (i.e., may be mangled).", NULL },
+ { "print_name", sympy_get_print_name, NULL,
+ "Name of the symbol in a form suitable for output.\n\
+This is either name or linkage_name, depending on whether the user asked GDB\n\
+to display demangled or mangled names.", NULL },
+ { "addr_class", sympy_get_addr_class, NULL, "Address class of the symbol." },
+ { "is_argument", sympy_is_argument, NULL,
+ "True if the symbol is an argument of a function." },
+ { "is_constant", sympy_is_constant, NULL,
+ "True if the symbol is a constant." },
+ { "is_function", sympy_is_function, NULL,
+ "True if the symbol is a function or method." },
+ { "is_variable", sympy_is_variable, NULL,
+ "True if the symbol is a variable." },
+ { NULL } /* Sentinel */
+};
+
+PyTypeObject symbol_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symbol", /*tp_name*/
+ sizeof (symbol_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ sympy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symbol object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ symbol_object_getset /* tp_getset */
+};
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
new file mode 100644
index 0000000..830e586
--- /dev/null
+++ b/gdb/python/py-symtab.c
@@ -0,0 +1,322 @@
+/* Python interface to symbol tables.
+
+ Copyright (C) 2008, 2009 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 "charset.h"
+#include "symtab.h"
+#include "source.h"
+#include "python-internal.h"
+
+typedef struct {
+ PyObject_HEAD
+ struct symtab *symtab;
+} symtab_object;
+
+static PyTypeObject symtab_object_type;
+
+typedef struct {
+ PyObject_HEAD
+ symtab_object *symtab;
+ struct symtab_and_line *sal;
+} sal_object;
+
+static PyTypeObject sal_object_type;
+
+
+static PyObject *
+stpy_str (PyObject *self)
+{
+ int ret;
+ char *s;
+ PyObject *result;
+
+ ret = asprintf (&s, "symbol table for %s",
+ ((symtab_object *) self)->symtab->filename);
+ if (ret < 0)
+ Py_RETURN_NONE;
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static PyObject *
+stpy_get_filename (PyObject *self, void *closure)
+{
+ symtab_object *self_symtab = (symtab_object *) self;
+ PyObject *str_obj;
+
+ /* FIXME: Can symtab->filename really be NULL? */
+ if (self_symtab->symtab->filename)
+ str_obj = PyString_Decode (self_symtab->symtab->filename,
+ strlen (self_symtab->symtab->filename),
+ host_charset (), NULL);
+ else
+ {
+ str_obj = Py_None;
+ Py_INCREF (Py_None);
+ }
+
+ return str_obj;
+}
+
+static PyObject *
+stpy_get_objfile (PyObject *self, void *closure)
+{
+ symtab_object *self_symtab = (symtab_object *) self;
+ PyObject *result = objfile_to_objfile_object (self_symtab->symtab->objfile);
+ Py_INCREF (result);
+ return result;
+}
+
+static PyObject *
+stpy_fullname (PyObject *self, PyObject *args)
+{
+ char *fullname;
+
+ fullname = symtab_to_fullname (((symtab_object *) self)->symtab);
+ if (fullname)
+ return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+salpy_str (PyObject *self)
+{
+ int ret;
+ char *s, *filename;
+ sal_object *sal_obj;
+ PyObject *result;
+
+ sal_obj = (sal_object *) self;
+ filename = (sal_obj->symtab == (symtab_object *) Py_None)? "<unknown>" :
+ sal_obj->symtab->symtab->filename;
+ ret = asprintf (&s, "symbol and line for %s, line %d", filename,
+ sal_obj->sal->line);
+ if (ret < 0)
+ Py_RETURN_NONE;
+
+ result = PyString_FromString (s);
+ xfree (s);
+
+ return result;
+}
+
+static PyObject *
+salpy_get_pc (PyObject *self, void *closure)
+{
+ return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->pc);
+}
+
+static PyObject *
+salpy_get_line (PyObject *self, void *closure)
+{
+ return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->line);
+}
+
+static PyObject *
+salpy_get_symtab (PyObject *self, void *closure)
+{
+ sal_object *self_sal = (sal_object *) self;
+
+ Py_INCREF (self_sal->symtab);
+
+ return (PyObject *) self_sal->symtab;
+}
+
+static void
+salpy_dealloc (PyObject *self)
+{
+ sal_object *self_sal = (sal_object *) self;
+
+ Py_DECREF (self_sal->symtab);
+ xfree (self_sal->sal);
+ self_sal->ob_type->tp_free (self);
+}
+
+PyObject *
+symtab_and_line_to_sal_object (struct symtab_and_line sal)
+{
+ sal_object *sal_obj;
+ symtab_object *symtab_obj;
+
+ sal_obj = PyObject_New (sal_object, &sal_object_type);
+ if (sal_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError,
+ "Could not allocate Symtab_and_line object.");
+ return NULL;
+ }
+
+ if (sal.symtab)
+ {
+ symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab);
+ if (symtab_obj == NULL)
+ {
+ Py_DECREF (sal_obj);
+ return NULL;
+ }
+
+ symtab_obj->symtab = sal.symtab;
+ }
+ else
+ {
+ symtab_obj = (symtab_object *) Py_None;
+ Py_INCREF (Py_None);
+ }
+
+ sal_obj->sal = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ *(sal_obj->sal) = sal;
+ sal_obj->symtab = symtab_obj;
+
+ return (PyObject *) sal_obj;
+}
+
+PyObject *
+symtab_to_symtab_object (struct symtab *symtab)
+{
+ symtab_object *symtab_obj;
+
+ symtab_obj = PyObject_New (symtab_object, &symtab_object_type);
+ if (symtab_obj == NULL)
+ {
+ PyErr_SetString (PyExc_MemoryError,
+ "Could not allocate Symtab object.");
+
+ return NULL;
+ }
+
+ symtab_obj->symtab = symtab;
+
+ return (PyObject *) symtab_obj;
+}
+
+void
+gdbpy_initialize_symtabs (void)
+{
+ symtab_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&symtab_object_type) < 0)
+ return;
+
+ sal_object_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&sal_object_type) < 0)
+ return;
+
+ Py_INCREF (&symtab_object_type);
+ PyModule_AddObject (gdb_module, "Symtab", (PyObject *) &symtab_object_type);
+
+ Py_INCREF (&sal_object_type);
+ PyModule_AddObject (gdb_module, "Symtab_and_line",
+ (PyObject *) &sal_object_type);
+}
+
+
+
+static PyGetSetDef symtab_object_getset[] = {
+ { "filename", stpy_get_filename, NULL,
+ "The symbol table's source filename.", NULL },
+ { "objfile", stpy_get_objfile, NULL, "The symtab's objfile.",
+ NULL },
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef symtab_object_methods[] = {
+ { "fullname", stpy_fullname, METH_NOARGS,
+ "Return the symtab's full source filename." },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject symtab_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symtab", /*tp_name*/
+ sizeof (symtab_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ stpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symtab object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ symtab_object_methods, /* tp_methods */
+ 0, /* tp_members */
+ symtab_object_getset /* tp_getset */
+};
+
+static PyGetSetDef sal_object_getset[] = {
+ { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL },
+ { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL },
+ { "line", salpy_get_line, NULL,
+ "Return the symtab_and_line's line.", NULL },
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject sal_object_type = {
+ PyObject_HEAD_INIT (NULL)
+ 0, /*ob_size*/
+ "gdb.Symtab_and_line", /*tp_name*/
+ sizeof (sal_object), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ salpy_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ salpy_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "GDB symtab_and_line object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ sal_object_getset /* tp_getset */
+};
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index a97c125..ac366bb 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -27,6 +27,8 @@
#include "demangle.h"
#include "objfiles.h"
#include "language.h"
+#include "observer.h"
+#include "gdb_assert.h"
typedef struct pyty_type_object
{
@@ -35,11 +37,17 @@ typedef struct pyty_type_object
/* If a Type object is associated with an objfile, it is kept on a
doubly-linked list, rooted in the objfile. This lets us copy the
- underlying struct type when the objfile is deleted. */
+ underlying struct type when the objfile is deleted.
+
+ With NULL objfile Type still can be doubly-linked in the list
+ PYTY_OBJECTS_DISCARDABLE. */
struct pyty_type_object *prev;
struct pyty_type_object *next;
} type_object;
+/* First element of a doubly-linked list of TYPE_DISCARDABLE Types. */
+static type_object *pyty_objects_discardable;
+
static PyTypeObject type_object_type;
/* A Field object. */
@@ -434,7 +442,7 @@ typy_get_sizeof (PyObject *self, void *closure)
}
static struct type *
-typy_lookup_typename (char *type_name)
+typy_lookup_typename (char *type_name, struct block *block)
{
struct type *type = NULL;
volatile struct gdb_exception except;
@@ -448,7 +456,7 @@ typy_lookup_typename (char *type_name)
type = lookup_enum (type_name + 5, NULL);
else
type = lookup_typename (python_language, python_gdbarch,
- type_name, NULL, 0);
+ type_name, block, 0);
}
if (except.reason < 0)
{
@@ -462,7 +470,8 @@ typy_lookup_typename (char *type_name)
}
static struct type *
-typy_lookup_type (struct demangle_component *demangled)
+typy_lookup_type (struct demangle_component *demangled,
+ struct block *block)
{
struct type *type;
char *type_name;
@@ -477,7 +486,7 @@ typy_lookup_type (struct demangle_component *demangled)
|| demangled_type == DEMANGLE_COMPONENT_CONST
|| demangled_type == DEMANGLE_COMPONENT_VOLATILE)
{
- type = typy_lookup_type (demangled->u.s_binary.left);
+ type = typy_lookup_type (demangled->u.s_binary.left, block);
if (! type)
return NULL;
@@ -495,7 +504,7 @@ typy_lookup_type (struct demangle_component *demangled)
}
type_name = cp_comp_to_string (demangled, 10);
- type = typy_lookup_typename (type_name);
+ type = typy_lookup_typename (type_name, block);
xfree (type_name);
return type;
@@ -509,10 +518,23 @@ typy_template_argument (PyObject *self, PyObject *args)
struct demangle_component *demangled;
const char *err;
struct type *argtype;
+ struct block *block = NULL;
+ PyObject *block_obj = NULL;
- if (! PyArg_ParseTuple (args, "i", &argno))
+ if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj))
return NULL;
+ if (block_obj)
+ {
+ block = block_object_to_block (block_obj);
+ if (! block)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "second argument must be block");
+ return NULL;
+ }
+ }
+
type = check_typedef (type);
if (TYPE_CODE (type) == TYPE_CODE_REF)
type = check_typedef (TYPE_TARGET_TYPE (type));
@@ -555,7 +577,7 @@ typy_template_argument (PyObject *self, PyObject *args)
return NULL;
}
- argtype = typy_lookup_type (demangled->u.s_binary.left);
+ argtype = typy_lookup_type (demangled->u.s_binary.left, block);
if (! argtype)
return NULL;
@@ -597,8 +619,59 @@ typy_str (PyObject *self)
+/* Key associated with each objfile pointing to the first element of
+ a doubly-linked list of Types associated with this objfile. */
static const struct objfile_data *typy_objfile_data_key;
+/* Link TYPE_OBJ to its appropriate list. Either to its objfile associated one
+ or at least to the global list for TYPE_DISCARDABLE Types. Permanent types
+ do not get linked anywhere. */
+static void
+typy_link (type_object *type_obj)
+{
+ type_obj->prev = NULL;
+
+ if (type_obj->type && TYPE_OBJFILE (type_obj->type))
+ {
+ struct objfile *objfile = TYPE_OBJFILE (type_obj->type);
+
+ type_obj->next = objfile_data (objfile, typy_objfile_data_key);
+ if (type_obj->next)
+ type_obj->next->prev = type_obj;
+ set_objfile_data (objfile, typy_objfile_data_key, type_obj);
+ }
+ else if (type_obj->type && TYPE_DISCARDABLE (type_obj->type))
+ {
+ type_obj->next = pyty_objects_discardable;
+ if (type_obj->next)
+ type_obj->next->prev = type_obj;
+ pyty_objects_discardable = type_obj;
+ }
+ else
+ type_obj->next = NULL;
+}
+
+/* Unlink TYPE_OBJ from its current list. Permanent types are not linked
+ anywhere and this function has no effect on them. */
+static void
+typy_unlink (type_object *type_obj)
+{
+ if (type_obj->prev)
+ type_obj->prev->next = type_obj->next;
+ else if (type_obj->type && TYPE_OBJFILE (type_obj->type))
+ {
+ /* Must reset head of list. */
+ struct objfile *objfile = TYPE_OBJFILE (type_obj->type);
+
+ set_objfile_data (objfile, typy_objfile_data_key, type_obj->next);
+ }
+ else if (pyty_objects_discardable == type_obj)
+ pyty_objects_discardable = type_obj->next;
+
+ if (type_obj->next)
+ type_obj->next->prev = type_obj->prev;
+}
+
static void
save_objfile_types (struct objfile *objfile, void *datum)
{
@@ -616,12 +689,13 @@ save_objfile_types (struct objfile *objfile, void *datum)
{
type_object *next = obj->next;
- htab_empty (copied_types);
+ gdb_assert (TYPE_OBJFILE (obj->type) == objfile);
+ typy_unlink (obj);
- obj->type = copy_type_recursive (objfile, obj->type, copied_types);
+ obj->type = copy_type_recursive (obj->type, copied_types);
- obj->next = NULL;
- obj->prev = NULL;
+ gdb_assert (TYPE_OBJFILE (obj->type) == NULL);
+ typy_link (obj);
obj = next;
}
@@ -632,41 +706,25 @@ save_objfile_types (struct objfile *objfile, void *datum)
}
static void
-set_type (type_object *obj, struct type *type)
+typy_dealloc (PyObject *obj)
{
- obj->type = type;
- obj->prev = NULL;
- if (type && TYPE_OBJFILE (type))
- {
- struct objfile *objfile = TYPE_OBJFILE (type);
+ type_object *type_obj = (type_object *) obj;
- obj->next = objfile_data (objfile, typy_objfile_data_key);
- if (obj->next)
- obj->next->prev = obj;
- set_objfile_data (objfile, typy_objfile_data_key, obj);
- }
- else
- obj->next = NULL;
+ typy_unlink (type_obj);
+
+ type_obj->ob_type->tp_free (obj);
}
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
static void
-typy_dealloc (PyObject *obj)
+typy_types_mark_used (void)
{
- type_object *type = (type_object *) obj;
-
- if (type->prev)
- type->prev->next = type->next;
- else if (type->type && TYPE_OBJFILE (type->type))
- {
- /* Must reset head of list. */
- struct objfile *objfile = TYPE_OBJFILE (type->type);
- if (objfile)
- set_objfile_data (objfile, typy_objfile_data_key, type->next);
- }
- if (type->next)
- type->next->prev = type->prev;
+ type_object *type_obj;
- type->ob_type->tp_free (type);
+ for (type_obj = pyty_objects_discardable;
+ type_obj != NULL;
+ type_obj = type_obj->next)
+ type_mark_used (type_obj->type);
}
/* Create a new Type referring to TYPE. */
@@ -677,7 +735,10 @@ type_to_type_object (struct type *type)
type_obj = PyObject_New (type_object, &type_object_type);
if (type_obj)
- set_type (type_obj, type);
+ {
+ type_obj->type = type;
+ typy_link (type_obj);
+ }
return (PyObject *) type_obj;
}
@@ -696,14 +757,28 @@ type_object_to_type (PyObject *obj)
PyObject *
gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
{
- static char *keywords[] = { "name", NULL };
+ static char *keywords[] = { "name", "block", NULL };
char *type_name = NULL;
struct type *type = NULL;
+ PyObject *block_obj = NULL;
+ struct block *block = NULL;
- if (! PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &type_name))
+ if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O", keywords,
+ &type_name, &block_obj))
return NULL;
- type = typy_lookup_typename (type_name);
+ if (block_obj)
+ {
+ block = block_object_to_block (block_obj);
+ if (! block)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ "'block' argument must be a Block");
+ return NULL;
+ }
+ }
+
+ type = typy_lookup_typename (type_name, block);
if (! type)
return NULL;
@@ -737,6 +812,8 @@ gdbpy_initialize_types (void)
Py_INCREF (&field_object_type);
PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type);
+
+ observer_attach_mark_used (typy_types_mark_used);
}
diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
index 4ccf97f..87cde73 100644
--- a/gdb/python/py-utils.c
+++ b/gdb/python/py-utils.c
@@ -19,6 +19,7 @@
#include "defs.h"
#include "charset.h"
+#include "value.h"
#include "python-internal.h"
@@ -219,3 +220,48 @@ gdbpy_is_string (PyObject *obj)
{
return PyString_Check (obj) || PyUnicode_Check (obj);
}
+
+/* Converts OBJ to a CORE_ADDR value.
+
+ Returns 1 on success or 0 on failure, with a Python exception set. This
+ function can also throw GDB exceptions. */
+
+int
+get_addr_from_python (PyObject *obj, CORE_ADDR *addr)
+{
+ if (gdbpy_is_value_object (obj))
+ *addr = value_as_address (value_object_to_value (obj));
+ else if (PyLong_Check (obj))
+ {
+ /* Assume CORE_ADDR corresponds to unsigned long. */
+ *addr = PyLong_AsUnsignedLong (obj);
+ if (PyErr_Occurred () != NULL)
+ return 0;
+ }
+ else if (PyInt_Check (obj))
+ {
+ long val;
+
+ /* Assume CORE_ADDR corresponds to unsigned long. */
+ val = PyInt_AsLong (obj);
+
+ if (val >= 0)
+ *addr = val;
+ else
+ {
+ /* If no error ocurred, VAL is indeed negative. */
+ if (PyErr_Occurred () != NULL)
+ return 0;
+
+ PyErr_SetString (PyExc_ValueError, "negative address");
+ return 0;
+ }
+ }
+ else
+ {
+ PyErr_SetString (PyExc_TypeError, "invalid type for address");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index a792819..bdac80e 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -25,6 +25,7 @@
#include "language.h"
#include "dfp.h"
#include "valprint.h"
+#include "observer.h"
#ifdef HAVE_PYTHON
@@ -43,6 +44,10 @@
/* Python's long type corresponds to C's long long type. */
#define builtin_type_pylong builtin_type (python_gdbarch)->builtin_long_long
+/* Python's long type corresponds to C's long long type. Unsigned version. */
+#define builtin_type_upylong builtin_type \
+ (python_gdbarch)->builtin_unsigned_long_long
+
#define builtin_type_pybool \
language_bool_type (python_language, python_gdbarch)
@@ -945,7 +950,34 @@ convert_value_from_python (PyObject *obj)
{
LONGEST l = PyLong_AsLongLong (obj);
- if (! PyErr_Occurred ())
+ if (PyErr_Occurred ())
+ {
+ /* If the error was an overflow, we can try converting to
+ ULONGEST instead. */
+ if (PyErr_ExceptionMatches (PyExc_OverflowError))
+ {
+ PyObject *etype, *evalue, *etraceback, *zero;
+
+ PyErr_Fetch (&etype, &evalue, &etraceback);
+ zero = PyInt_FromLong (0);
+
+ /* Check whether obj is positive. */
+ if (PyObject_RichCompareBool (obj, zero, Py_GT) > 0)
+ {
+ ULONGEST ul;
+
+ ul = PyLong_AsUnsignedLongLong (obj);
+ if (! PyErr_Occurred ())
+ value = value_from_ulongest (builtin_type_upylong, ul);
+ }
+ else
+ /* There's nothing we can do. */
+ PyErr_Restore (etype, evalue, etraceback);
+
+ Py_DECREF (zero);
+ }
+ }
+ else
value = value_from_longest (builtin_type_pylong, l);
}
else if (PyFloat_Check (obj))
@@ -1011,6 +1043,25 @@ gdbpy_history (PyObject *self, PyObject *args)
return value_to_value_object (res_val);
}
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+python_types_mark_used (void)
+{
+ value_object *iter;
+
+ for (iter = values_in_python; iter; iter = iter->next)
+ type_mark_used (value_type (iter->value));
+}
+
+/* Returns 1 in OBJ is a gdb.Value object, 0 otherwise. */
+
+int
+gdbpy_is_value_object (PyObject *obj)
+{
+ return PyObject_TypeCheck (obj, &value_object_type);
+}
+
void
gdbpy_initialize_values (void)
{
@@ -1021,6 +1072,8 @@ gdbpy_initialize_values (void)
PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type);
values_in_python = NULL;
+
+ observer_attach_mark_used (python_types_mark_used);
}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 9196f08..5230a8c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -61,36 +61,79 @@ typedef int Py_ssize_t;
#define PyEval_ReleaseLock() 0
#endif
+#include "command.h"
+
+struct block;
+struct symbol;
+struct symtab_and_line;
struct value;
struct language_defn;
extern PyObject *gdb_module;
+extern PyTypeObject block_object_type;
extern PyTypeObject value_object_type;
+extern PyTypeObject symbol_object_type;
+
+/* Used in python-inferior.c. */
+typedef struct
+{
+ PyObject_HEAD
+
+ /* The thread we represent. */
+ struct thread_info *thread;
+
+ /* The Inferior object to which this thread belongs. */
+ PyObject *inf_obj;
+} thread_object;
PyObject *gdbpy_history (PyObject *self, PyObject *args);
+PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
+PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw);
PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
+PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args);
PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
const char *encoding, struct type *type);
+PyObject *gdbpy_inferiors (PyObject *unused, PyObject *unused2);
+PyObject *gdbpy_selected_thread (PyObject *self, PyObject *args);
+PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
+PyObject *symtab_to_symtab_object (struct symtab *symtab);
+PyObject *symbol_to_symbol_object (struct symbol *sym);
+PyObject *block_to_block_object (struct block *block);
PyObject *value_to_value_object (struct value *v);
PyObject *type_to_type_object (struct type *);
PyObject *objfile_to_objfile_object (struct objfile *);
+PyObject *frame_info_to_frame_object (struct frame_info *frame);
+thread_object *create_thread_object (struct thread_info *tp);
+thread_object *find_thread_object (ptid_t ptid);
+PyObject *find_inferior_object (int pid);
PyObject *objfpy_get_printers (PyObject *, void *);
+struct block *block_object_to_block (PyObject *obj);
+struct symbol *symbol_object_to_symbol (PyObject *obj);
struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (PyObject *obj);
struct type *type_object_to_type (PyObject *obj);
+PyObject *gdbpy_get_hook_function (const char *);
+
void gdbpy_initialize_values (void);
+void gdbpy_initialize_breakpoints (void);
void gdbpy_initialize_frames (void);
+void gdbpy_initialize_symtabs (void);
void gdbpy_initialize_commands (void);
+void gdbpy_initialize_symbols (void);
void gdbpy_initialize_types (void);
+void gdbpy_initialize_blocks (void);
void gdbpy_initialize_functions (void);
void gdbpy_initialize_objfile (void);
void gdbpy_initialize_lazy_string (void);
+void gdbpy_initialize_parameters (void);
+void gdbpy_initialize_thread (void);
+void gdbpy_initialize_inferior (void);
struct cleanup *make_cleanup_py_decref (PyObject *py);
@@ -100,6 +143,12 @@ struct cleanup *ensure_python_env (struct gdbarch *gdbarch,
extern struct gdbarch *python_gdbarch;
extern const struct language_defn *python_language;
+char *gdbpy_parse_command_name (char *text,
+ struct cmd_list_element ***base_list,
+ struct cmd_list_element **start_list);
+
+PyObject *gdbpy_parameter_value (enum var_types, void *);
+
/* Use this after a TRY_EXCEPT to throw the appropriate Python
exception. */
#define GDB_PY_HANDLE_EXCEPTION(Exception) \
@@ -110,6 +159,19 @@ extern const struct language_defn *python_language;
"%s", Exception.message); \
} while (0)
+/* Use this after a TRY_EXCEPT to throw the appropriate Python
+ exception. This macro is for use inside setter functions. */
+#define GDB_PY_SET_HANDLE_EXCEPTION(Exception) \
+ do { \
+ if (Exception.reason < 0) \
+ { \
+ PyErr_Format (Exception.reason == RETURN_QUIT \
+ ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \
+ "%s", Exception.message); \
+ return -1; \
+ } \
+ } while (0)
+
void gdbpy_print_stack (void);
@@ -125,17 +187,22 @@ gdb_byte *gdbpy_extract_lazy_string (PyObject *string,
struct type **str_type,
long *length, char **encoding);
+int gdbpy_is_value_object (PyObject *obj);
+
/* Note that these are declared here, and not in python.h with the
other pretty-printer functions, because they refer to PyObject. */
PyObject *apply_varobj_pretty_printer (PyObject *print_obj,
struct value **replacement);
PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
+PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value);
char *gdbpy_get_display_hint (PyObject *printer);
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
-extern PyObject *gdbpy_doc_cst;
extern PyObject *gdbpy_children_cst;
extern PyObject *gdbpy_to_string_cst;
extern PyObject *gdbpy_display_hint_cst;
+extern PyObject *gdbpy_doc_cst;
+
+int get_addr_from_python (PyObject *obj, CORE_ADDR *addr);
#endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 827372c..171cd5b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -27,6 +27,7 @@
#include "observer.h"
#include "value.h"
#include "language.h"
+#include "event-loop.h"
#include <ctype.h>
@@ -45,11 +46,18 @@ static int gdbpy_auto_load = 1;
#include "cli/cli-decode.h"
#include "charset.h"
#include "top.h"
+#include "solib.h"
#include "exceptions.h"
#include "python-internal.h"
+#include "linespec.h"
+#include "symtab.h"
+#include "source.h"
#include "version.h"
+#include "inferior.h"
+#include "gdbthread.h"
#include "target.h"
#include "gdbthread.h"
+#include "event-top.h"
static PyMethodDef GdbMethods[];
@@ -197,10 +205,10 @@ python_command (char *arg, int from_tty)
NULL (and set a Python exception) on error. Helper function for
get_parameter. */
-static PyObject *
-parameter_to_python (struct cmd_list_element *cmd)
+PyObject *
+gdbpy_parameter_value (enum var_types type, void *var)
{
- switch (cmd->var_type)
+ switch (type)
{
case var_string:
case var_string_noescape:
@@ -208,7 +216,7 @@ parameter_to_python (struct cmd_list_element *cmd)
case var_filename:
case var_enum:
{
- char *str = * (char **) cmd->var;
+ char *str = * (char **) var;
if (! str)
str = "";
return PyString_Decode (str, strlen (str), host_charset (), NULL);
@@ -216,7 +224,7 @@ parameter_to_python (struct cmd_list_element *cmd)
case var_boolean:
{
- if (* (int *) cmd->var)
+ if (* (int *) var)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
@@ -224,7 +232,7 @@ parameter_to_python (struct cmd_list_element *cmd)
case var_auto_boolean:
{
- enum auto_boolean ab = * (enum auto_boolean *) cmd->var;
+ enum auto_boolean ab = * (enum auto_boolean *) var;
if (ab == AUTO_BOOLEAN_TRUE)
Py_RETURN_TRUE;
else if (ab == AUTO_BOOLEAN_FALSE)
@@ -234,15 +242,15 @@ parameter_to_python (struct cmd_list_element *cmd)
}
case var_integer:
- if ((* (int *) cmd->var) == INT_MAX)
+ if ((* (int *) var) == INT_MAX)
Py_RETURN_NONE;
/* Fall through. */
case var_zinteger:
- return PyLong_FromLong (* (int *) cmd->var);
+ return PyLong_FromLong (* (int *) var);
case var_uinteger:
{
- unsigned int val = * (unsigned int *) cmd->var;
+ unsigned int val = * (unsigned int *) var;
if (val == UINT_MAX)
Py_RETURN_NONE;
return PyLong_FromUnsignedLong (val);
@@ -280,7 +288,7 @@ gdbpy_parameter (PyObject *self, PyObject *args)
if (! cmd->var)
return PyErr_Format (PyExc_RuntimeError, "`%s' is not a parameter", arg);
- return parameter_to_python (cmd);
+ return gdbpy_parameter_value (cmd->var_type, cmd->var);
}
/* A Python function which evaluates a string using the gdb CLI. */
@@ -323,6 +331,105 @@ execute_gdb_command (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
+/* Implementation of gdb.solib_address (Long) -> String.
+ Returns the name of the shared library holding a given address, or None. */
+
+static PyObject *
+gdbpy_solib_address (PyObject *self, PyObject *args)
+{
+ unsigned long long pc;
+ char *soname;
+ PyObject *str_obj;
+
+ if (!PyArg_ParseTuple (args, "K", &pc))
+ return NULL;
+
+ soname = solib_name_from_address (current_program_space, pc);
+ if (soname)
+ str_obj = PyString_Decode (soname, strlen (soname), host_charset (), NULL);
+ else
+ {
+ str_obj = Py_None;
+ Py_INCREF (Py_None);
+ }
+
+ return str_obj;
+}
+
+/* A Python function which is a wrapper for decode_line_1. */
+
+static PyObject *
+gdbpy_decode_line (PyObject *self, PyObject *args)
+{
+ struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to appease gcc. */
+ struct symtab_and_line sal;
+ char *arg = NULL;
+ int free_sals = 0, i;
+ PyObject *result = NULL;
+ volatile struct gdb_exception except;
+
+ if (! PyArg_ParseTuple (args, "|s", &arg))
+ return NULL;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ if (arg)
+ {
+ char *copy;
+
+ arg = strdup (arg);
+ copy = arg;
+
+ sals = decode_line_1 (&copy, 0, 0, 0, 0, 0);
+ free_sals = 1;
+ }
+ else
+ {
+ set_default_source_symtab_and_line ();
+ sal = get_current_source_symtab_and_line ();
+ sals.sals = &sal;
+ sals.nelts = 1;
+ }
+ }
+ if (arg)
+ xfree (arg);
+
+ if (except.reason < 0)
+ {
+ if (free_sals)
+ xfree (sals.sals);
+ /* We know this will always throw. */
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+
+ if (sals.nelts)
+ {
+ result = PyTuple_New (sals.nelts);
+ for (i = 0; i < sals.nelts; ++i)
+ {
+ PyObject *obj;
+ char *str;
+
+ obj = symtab_and_line_to_sal_object (sals.sals[i]);
+ if (! obj)
+ {
+ Py_DECREF (result);
+ result = NULL;
+ break;
+ }
+
+ PyTuple_SetItem (result, i, obj);
+ }
+ }
+
+ if (free_sals)
+ xfree (sals.sals);
+
+ if (result)
+ return result;
+ Py_RETURN_NONE;
+}
+
/* Parse a string and evaluate it as an expression. */
static PyObject *
gdbpy_parse_and_eval (PyObject *self, PyObject *args)
@@ -345,6 +452,114 @@ gdbpy_parse_and_eval (PyObject *self, PyObject *args)
+/* Posting and handling events. */
+
+/* A single event. */
+struct gdbpy_event
+{
+ /* The Python event. This is just a callable object. */
+ PyObject *event;
+ /* The next event. */
+ struct gdbpy_event *next;
+};
+
+/* All pending events. */
+static struct gdbpy_event *gdbpy_event_list;
+/* The final link of the event list. */
+static struct gdbpy_event **gdbpy_event_list_end;
+
+/* We use a file handler, and not an async handler, so that we can
+ wake up the main thread even when it is blocked in poll(). */
+static int gdbpy_event_fds[2];
+
+/* The file handler callback. This reads from the internal pipe, and
+ then processes the Python event queue. This will always be run in
+ the main gdb thread. */
+static void
+gdbpy_run_events (int err, gdb_client_data ignore)
+{
+ struct cleanup *cleanup;
+ char buffer[100];
+ int r;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+
+ /* Just read whatever is available on the fd. It is relatively
+ harmless if there are any bytes left over. */
+ r = read (gdbpy_event_fds[0], buffer, sizeof (buffer));
+
+ while (gdbpy_event_list)
+ {
+ /* Dispatching the event might push a new element onto the event
+ loop, so we update here "atomically enough". */
+ struct gdbpy_event *item = gdbpy_event_list;
+ gdbpy_event_list = gdbpy_event_list->next;
+ if (gdbpy_event_list == NULL)
+ gdbpy_event_list_end = &gdbpy_event_list;
+
+ /* Ignore errors. */
+ PyObject_CallObject (item->event, NULL);
+
+ Py_DECREF (item->event);
+ xfree (item);
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* Submit an event to the gdb thread. */
+static PyObject *
+gdbpy_post_event (PyObject *self, PyObject *args)
+{
+ struct gdbpy_event *event;
+ PyObject *func;
+ int wakeup;
+
+ if (!PyArg_ParseTuple (args, "O", &func))
+ return NULL;
+
+ if (!PyCallable_Check (func))
+ {
+ PyErr_SetString (PyExc_RuntimeError, "Posted event is not callable");
+ return NULL;
+ }
+
+ Py_INCREF (func);
+
+ /* From here until the end of the function, we have the GIL, so we
+ can operate on our global data structures without worrying. */
+ wakeup = gdbpy_event_list == NULL;
+
+ event = XNEW (struct gdbpy_event);
+ event->event = func;
+ event->next = NULL;
+ *gdbpy_event_list_end = event;
+ gdbpy_event_list_end = &event->next;
+
+ /* Wake up gdb when needed. */
+ if (wakeup)
+ {
+ char c = 'q'; /* Anything. */
+ if (write (gdbpy_event_fds[1], &c, 1) != 1)
+ return PyErr_SetFromErrno (PyExc_IOError);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* Initialize the Python event handler. */
+static void
+gdbpy_initialize_events (void)
+{
+ if (!pipe (gdbpy_event_fds))
+ {
+ gdbpy_event_list_end = &gdbpy_event_list;
+ add_file_handler (gdbpy_event_fds[0], gdbpy_run_events, NULL);
+ }
+}
+
+
+
/* Printing. */
/* A python function to write a single string using gdb's filtered
@@ -381,6 +596,67 @@ gdbpy_print_stack (void)
+/* Script interface. */
+
+/* True if 'gdb -P' was used, false otherwise. */
+static int running_python_script;
+
+/* True if we are currently in a call to 'gdb.cli', false otherwise. */
+static int in_cli;
+
+/* Enter the command loop. */
+
+static PyObject *
+gdbpy_cli (PyObject *unused1, PyObject *unused2)
+{
+ if (! running_python_script || in_cli)
+ return PyErr_Format (PyExc_RuntimeError, "cannot invoke CLI recursively");
+
+ in_cli = 1;
+ cli_command_loop ();
+ in_cli = 0;
+
+ Py_RETURN_NONE;
+}
+
+/* Set up the Python argument vector and evaluate a script. This is
+ used to implement 'gdb -P'. */
+
+void
+run_python_script (int argc, char **argv)
+{
+ FILE *input;
+
+ /* We never free this, since we plan to exit at the end. */
+ ensure_python_env (get_current_arch (), current_language);
+
+ running_python_script = 1;
+ PySys_SetArgv (argc - 1, argv + 1);
+ input = fopen (argv[0], "r");
+ if (! input)
+ {
+ fprintf (stderr, "could not open %s: %s\n", argv[0], strerror (errno));
+ exit (1);
+ }
+ PyRun_SimpleFile (input, argv[0]);
+ fclose (input);
+ exit (0);
+}
+
+void
+source_python_script (FILE *stream, char *file)
+{
+ struct cleanup *cleanup;
+
+ cleanup = ensure_python_env (get_current_arch (), current_language);
+ PyRun_SimpleFile (stream, file);
+
+ fclose (stream);
+ do_cleanups (cleanup);
+}
+
+
+
/* The "current" objfile. This is set when gdb detects that a new
objfile has been loaded. It is only set for the duration of a call
to gdbpy_new_objfile; it is NULL at other times. */
@@ -525,6 +801,13 @@ eval_python_from_control_command (struct command_line *cmd)
error (_("Python scripting is not supported in this copy of GDB."));
}
+void
+source_python_script (FILE *stream)
+{
+ fclose (stream);
+ error (_("Python scripting is not supported in this copy of GDB."));
+}
+
#endif /* HAVE_PYTHON */
@@ -616,14 +899,28 @@ Enables or disables auto-loading of Python code when an object is opened."),
PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version);
PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name);
PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
+#ifdef PYTHONDIR
+ PyModule_AddStringConstant (gdb_module, "pythondir", PYTHONDIR);
+#else
+ if (gdb_datadir)
+ PyModule_AddStringConstant (gdb_module, "datadir", gdb_datadir);
+#endif
gdbpy_initialize_values ();
+ gdbpy_initialize_breakpoints ();
gdbpy_initialize_frames ();
+ gdbpy_initialize_symtabs ();
gdbpy_initialize_commands ();
+ gdbpy_initialize_symbols ();
+ gdbpy_initialize_blocks ();
gdbpy_initialize_functions ();
gdbpy_initialize_types ();
+ gdbpy_initialize_parameters ();
gdbpy_initialize_objfile ();
gdbpy_initialize_lazy_string ();
+ gdbpy_initialize_thread ();
+ gdbpy_initialize_inferior ();
+ gdbpy_initialize_events ();
PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
@@ -659,6 +956,15 @@ class GdbOutputFile:\n\
\n\
sys.stderr = GdbOutputFile()\n\
sys.stdout = GdbOutputFile()\n\
+if hasattr (gdb, 'datadir'):\n\
+ gdb.pythondir = gdb.datadir + '/python'\n\
+if hasattr (gdb, 'pythondir'):\n\
+ sys.path.insert(0, gdb.pythondir)\n\
+ gdb.__path__ = [gdb.pythondir + '/gdb']\n\
+ from os.path import exists\n\
+ ipy = gdb.pythondir + '/gdb/__init__.py'\n\
+ if exists (ipy):\n\
+ execfile (ipy)\n\
");
/* Release the GIL while gdb runs. */
@@ -678,9 +984,14 @@ static PyMethodDef GdbMethods[] =
"Get a value from history" },
{ "execute", execute_gdb_command, METH_VARARGS,
"Execute a gdb command" },
+ { "cli", gdbpy_cli, METH_NOARGS,
+ "Enter the gdb CLI" },
{ "parameter", gdbpy_parameter, METH_VARARGS,
"Return a gdb parameter's value" },
+ { "breakpoints", gdbpy_breakpoints, METH_NOARGS,
+ "Return a tuple of all breakpoint objects" },
+
{ "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
"Find the default visualizer for a Value." },
@@ -701,11 +1012,39 @@ Return a string explaining unwind stop reason." },
"lookup_type (name [, block]) -> type\n\
Return a Type corresponding to the given name." },
+ { "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol,
+ METH_VARARGS | METH_KEYWORDS,
+ "lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\
+Return a tuple with the symbol corresponding to the given name (or None) and\n\
+a boolean indicating if name is a field of the current implied argument\n\
+`this' (when the current language is object-oriented)." },
+ { "solib_address", gdbpy_solib_address, METH_VARARGS,
+ "solib_address (Long) -> String.\n\
+Return the name of the shared library holding a given address, or None." },
+
+ { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS,
+ "Return the block containing the given pc value, or None." },
+
+ { "decode_line", gdbpy_decode_line, METH_VARARGS,
+ "Decode a string argument the way that 'break' or 'edit' does.\n\
+Return a tuple holding the file name (or None) and line number (or None).\n\
+Note: may later change to return an object." },
+
+ { "selected_thread", gdbpy_selected_thread, METH_NOARGS,
+ "selected_thread () -> gdb.InferiorThread.\n\
+Return the selected thread object." },
+ { "inferiors", gdbpy_inferiors, METH_NOARGS,
+ "inferiors () -> (gdb.Inferior, ...).\n\
+Return a tuple containing all inferiors." },
+
{ "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS,
"parse_and_eval (String) -> Value.\n\
Parse String as an expression, evaluate it, and return the result as a Value."
},
+ { "post_event", gdbpy_post_event, METH_VARARGS,
+ "Post an event into gdb's event loop." },
+
{ "write", gdbpy_write, METH_VARARGS,
"Write a string using gdb's filtered stream." },
{ "flush", gdbpy_flush, METH_NOARGS,
diff --git a/gdb/python/python.h b/gdb/python/python.h
index f35827b..1a5b9a8 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -24,6 +24,10 @@
void eval_python_from_control_command (struct command_line *);
+void source_python_script (FILE *stream, char *file);
+
+void run_python_script (int argc, char **argv);
+
int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c
index 1d05f8a..e2015c4 100644
--- a/gdb/scm-lang.c
+++ b/gdb/scm-lang.c
@@ -233,6 +233,7 @@ const struct exp_descriptor exp_descriptor_scm =
{
print_subexp_standard,
operator_length_standard,
+ operator_check_standard,
op_name_standard,
dump_subexp_body_standard,
evaluate_exp
diff --git a/gdb/somread.c b/gdb/somread.c
index c7beaba..e31164c 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -432,6 +432,7 @@ static struct sym_fns som_sym_fns =
som_new_init, /* sym_new_init: init anything gbl to entire symtab */
som_symfile_init, /* sym_init: read initial info, setup for sym_read() */
som_symfile_read, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
som_symfile_finish, /* sym_finish: finished with file, cleanup */
som_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */
default_symfile_segments, /* sym_segments: Get segment information from
diff --git a/gdb/stack.c b/gdb/stack.c
index 6e198e0..94a3ef9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1309,24 +1309,24 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
else
count = -1;
- if (info_verbose)
- {
- struct partial_symtab *ps;
-
- /* Read in symbols for all of the frames. Need to do this in a
- separate pass so that "Reading in symbols for xxx" messages
- don't screw up the appearance of the backtrace. Also if
- people have strong opinions against reading symbols for
- backtrace this may have to be an option. */
- i = count;
- for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi))
- {
- QUIT;
- ps = find_pc_psymtab (get_frame_address_in_block (fi));
- if (ps)
- PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */
- }
- }
+ {
+ struct partial_symtab *ps;
+
+ /* Read in symbols for all of the frames. Need to do this
+ unconditionally to ensure that psymbols are read. Also need to
+ do this in a separate pass so that "Reading in symbols for xxx"
+ messages don't screw up the appearance of the backtrace. Also
+ if people have strong opinions against reading symbols for
+ backtrace this may have to be an option. */
+ i = count;
+ for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi))
+ {
+ QUIT;
+ ps = find_pc_psymtab (get_frame_address_in_block (fi));
+ if (info_verbose && ps)
+ PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */
+ }
+ }
for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi))
{
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 89cc07c..b759f10 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -968,13 +968,16 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
/* Give user a chance to burp if we'd be
interactively wiping out any existing symbols. */
- if ((have_full_symbols () || have_partial_symbols ())
- && (add_flags & SYMFILE_MAINLINE)
+ if ((add_flags & SYMFILE_MAINLINE)
+ && (have_full_symbols () || have_partial_symbols ())
&& from_tty
+ && (have_full_symbols () || have_partial_symbols ())
&& !query (_("Load new symbol table from \"%s\"? "), name))
error (_("Not confirmed."));
objfile = allocate_objfile (abfd, flags);
+ if (add_flags & SYMFILE_MAINLINE)
+ objfile->flags |= OBJF_MAIN;
discard_cleanups (my_cleanups);
/* We either created a new mapped symbol table, mapped an existing
@@ -1001,6 +1004,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
if ((flags & OBJF_READNOW) || readnow_symbol_files)
{
+ require_partial_symbols (objfile);
+
if (from_tty || info_verbose)
{
printf_unfiltered (_("expanding to full symbols..."));
@@ -2323,6 +2328,7 @@ reread_symbols (void)
objfile->symtabs = NULL;
objfile->psymtabs = NULL;
objfile->psymtabs_addrmap = NULL;
+ objfile->quick_addrmap = NULL;
objfile->free_psymtabs = NULL;
objfile->cp_namespace_symtab = NULL;
objfile->msymbols = NULL;
@@ -2333,6 +2339,8 @@ reread_symbols (void)
memset (&objfile->msymbol_demangled_hash, 0,
sizeof (objfile->msymbol_demangled_hash));
+ objfile->flags &= ~OBJF_SYMTABS_READ;
+
objfile->psymbol_cache = bcache_xmalloc ();
objfile->macro_cache = bcache_xmalloc ();
objfile->filename_cache = bcache_xmalloc ();
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 7ae819c..f3f6eb3 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -139,6 +139,12 @@ struct sym_fns
void (*sym_read) (struct objfile *, int);
+ /* Read the partial symbols for an objfile. This may be NULL, in
+ which case gdb assumes that sym_read already read the partial
+ symbols. */
+
+ void (*sym_read_psymbols) (struct objfile *);
+
/* Called when we are finished with an objfile. Should do all
cleanup that is specific to the object file format for the
particular objfile. */
@@ -389,7 +395,7 @@ void free_symfile_segment_data (struct symfile_segment_data *data);
/* From dwarf2read.c */
extern int dwarf2_has_info (struct objfile *);
-
+extern void dwarf2_create_quick_addrmap (struct objfile *);
extern void dwarf2_build_psymtabs (struct objfile *);
extern void dwarf2_build_frame_info (struct objfile *);
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 426326d..bac4ca3 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -271,7 +271,7 @@ lookup_partial_symtab (const char *name)
make_cleanup (xfree, real_path);
}
- ALL_PSYMTABS (objfile, pst)
+ ALL_PSYMTABS_REQUIRED (objfile, pst)
{
if (FILENAME_CMP (name, pst->filename) == 0)
{
@@ -414,7 +414,8 @@ symbol_init_language_specific (struct general_symbol_info *gsymbol,
gsymbol->language = language;
if (gsymbol->language == language_cplus
|| gsymbol->language == language_java
- || gsymbol->language == language_objc)
+ || gsymbol->language == language_objc
+ || gsymbol->language == language_fortran)
{
gsymbol->language_specific.cplus_specific.demangled_name = NULL;
}
@@ -695,6 +696,7 @@ symbol_natural_name (const struct general_symbol_info *gsymbol)
case language_cplus:
case language_java:
case language_objc:
+ case language_fortran:
if (gsymbol->language_specific.cplus_specific.demangled_name != NULL)
return gsymbol->language_specific.cplus_specific.demangled_name;
break;
@@ -720,6 +722,7 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol)
case language_cplus:
case language_java:
case language_objc:
+ case language_fortran:
if (gsymbol->language_specific.cplus_specific.demangled_name != NULL)
return gsymbol->language_specific.cplus_specific.demangled_name;
break;
@@ -931,7 +934,13 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
than the later used TEXTLOW/TEXTHIGH one. */
ALL_OBJFILES (objfile)
- if (objfile->psymtabs_addrmap != NULL)
+ {
+ if (objfile->quick_addrmap)
+ {
+ if (!addrmap_find (objfile->quick_addrmap, pc))
+ continue;
+ }
+ if (require_partial_symbols (objfile)->psymtabs_addrmap != NULL)
{
struct partial_symtab *pst;
@@ -964,6 +973,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
return pst;
}
}
+ }
/* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs
which still have no corresponding full SYMTABs read. But it is not
@@ -1231,6 +1241,22 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile)
return psym;
}
+/* Ensure that the partial symbols for OBJFILE have been loaded. This
+ function always returns its argument, as a convenience. */
+
+struct objfile *
+require_partial_symbols (struct objfile *objfile)
+{
+ if ((objfile->flags & OBJF_SYMTABS_READ) == 0)
+ {
+ objfile->flags |= OBJF_SYMTABS_READ;
+
+ if (objfile->sf->sym_read_psymbols)
+ (*objfile->sf->sym_read_psymbols) (objfile);
+ }
+ return objfile;
+}
+
/* Find the definition for a specified symbol name NAME
in domain DOMAIN, visible from lexical block BLOCK.
Returns the struct symbol pointer, or zero if no symbol is found.
@@ -1534,6 +1560,7 @@ lookup_global_symbol_from_objfile (const struct objfile *main_objfile,
}
/* Now go through psymtabs. */
+ require_partial_symbols ((struct objfile *) objfile);
ALL_OBJFILE_PSYMTABS (objfile, ps)
{
if (!ps->readin
@@ -1601,7 +1628,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name,
struct symtab *s;
const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0);
- ALL_PSYMTABS (objfile, ps)
+ ALL_PSYMTABS_REQUIRED (objfile, ps)
{
if (!ps->readin
&& lookup_partial_symbol (ps, name, linkage_name,
@@ -1886,7 +1913,11 @@ basic_lookup_transparent_type (const char *name)
}
}
- ALL_PSYMTABS (objfile, ps)
+ /* FIXME: .debug_pubnames should be read in.
+
+ One may also try to the first pass without the require_partial_symbols
+ call but that would behave nondeterministically. */
+ ALL_PSYMTABS_REQUIRED (objfile, ps)
{
if (!ps->readin && lookup_partial_symbol (ps, name, NULL,
1, STRUCT_DOMAIN))
@@ -1934,7 +1965,12 @@ basic_lookup_transparent_type (const char *name)
}
}
- ALL_PSYMTABS (objfile, ps)
+ /* FIXME: Something like .debug_pubnames containing also static symbols
+ should be read in. Compiler needs to be taught to generate it first.
+
+ One may also try to the first pass without the require_partial_symbols
+ call but that would behave nondeterministically. */
+ ALL_PSYMTABS_REQUIRED (objfile, ps)
{
if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 0, STRUCT_DOMAIN))
{
@@ -1975,7 +2011,21 @@ find_main_psymtab (void)
struct partial_symtab *pst;
struct objfile *objfile;
- ALL_PSYMTABS (objfile, pst)
+ ALL_OBJFILES (objfile)
+ {
+ if ((objfile->flags & OBJF_MAIN) == 0)
+ continue;
+ require_partial_symbols (objfile);
+ ALL_OBJFILE_PSYMTABS (objfile, pst)
+ {
+ if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN))
+ {
+ return pst;
+ }
+ }
+ }
+
+ ALL_PSYMTABS_REQUIRED (objfile, pst)
{
if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN))
{
@@ -3261,7 +3311,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[],
matching the regexp. That way we don't have to reproduce all of
the machinery below. */
- ALL_PSYMTABS (objfile, ps)
+ ALL_PSYMTABS_REQUIRED (objfile, ps)
{
struct partial_symbol **bound, **gbound, **sbound;
int keep_going = 1;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 800ffd8..3ed6947 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -396,7 +396,10 @@ typedef enum domain_enum_tag
FUNCTIONS_DOMAIN,
/* All defined types */
- TYPES_DOMAIN
+ TYPES_DOMAIN,
+
+ /* Fortran module. Their naming must be separate. */
+ MODULE_DOMAIN
}
domain_enum;
@@ -1065,6 +1068,8 @@ extern void clear_pc_function_cache (void);
/* from symtab.c: */
+struct objfile *require_partial_symbols (struct objfile *);
+
/* lookup partial symbol table by filename */
extern struct partial_symtab *lookup_partial_symtab (const char *);
diff --git a/gdb/target.c b/gdb/target.c
index edf8697..a7ed206 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -124,6 +124,8 @@ static int debug_to_insert_watchpoint (CORE_ADDR, int, int);
static int debug_to_remove_watchpoint (CORE_ADDR, int, int);
+static int debug_to_detach_watchpoints (void);
+
static int debug_to_stopped_by_watchpoint (void);
static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
@@ -624,6 +626,7 @@ update_current_target (void)
INHERIT (to_remove_hw_breakpoint, t);
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ INHERIT (to_detach_watchpoints, t);
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
@@ -747,6 +750,9 @@ update_current_target (void)
de_fault (to_remove_watchpoint,
(int (*) (CORE_ADDR, int, int))
return_minus_one);
+ de_fault (to_detach_watchpoints,
+ (int (*) (void))
+ return_zero);
de_fault (to_stopped_by_watchpoint,
(int (*) (void))
return_zero);
@@ -3302,6 +3308,19 @@ debug_to_remove_watchpoint (CORE_ADDR addr, int len, int type)
return retval;
}
+static int
+debug_to_detach_watchpoints (void)
+{
+ int retval;
+
+ retval = debug_target.to_detach_watchpoints ();
+
+ fprintf_unfiltered (gdb_stdlog,
+ "target_detach_watchpoints () = %ld\n",
+ (unsigned long) retval);
+ return retval;
+}
+
static void
debug_to_terminal_init (void)
{
@@ -3549,6 +3568,7 @@ setup_target_debug (void)
current_target.to_remove_hw_breakpoint = debug_to_remove_hw_breakpoint;
current_target.to_insert_watchpoint = debug_to_insert_watchpoint;
current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
+ current_target.to_detach_watchpoints = debug_to_detach_watchpoints;
current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
current_target.to_stopped_data_address = debug_to_stopped_data_address;
current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range;
diff --git a/gdb/target.h b/gdb/target.h
index a020bf7..2c5e58e 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -419,6 +419,7 @@ struct target_ops
int (*to_remove_hw_breakpoint) (struct gdbarch *, struct bp_target_info *);
int (*to_remove_watchpoint) (CORE_ADDR, int, int);
int (*to_insert_watchpoint) (CORE_ADDR, int, int);
+ int (*to_detach_watchpoints) (void);
int (*to_stopped_by_watchpoint) (void);
int to_have_steppable_watchpoint;
int to_have_continuable_watchpoint;
@@ -1262,6 +1263,15 @@ extern char *normal_pid_to_str (ptid_t ptid);
#define target_remove_watchpoint(addr, len, type) \
(*current_target.to_remove_watchpoint) (addr, len, type)
+/* Clear all debug registers without affecting any register caches. Function
+ acts on INFERIOR_PTID which should be the forked-off process, either the
+ non-threaded child one or the threaded parent one, depending on `set
+ follow-fork-mode'. Both watchpoints and hardware breakpoints get removed.
+ Return 0 on success, -1 on failure. */
+
+#define target_detach_watchpoints() \
+ (*current_target.to_detach_watchpoints) ()
+
#define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
(*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
@@ -1302,6 +1312,20 @@ extern int target_search_memory (CORE_ADDR start_addr,
ULONGEST pattern_len,
CORE_ADDR *found_addrp);
+/* Utility functions which can be used by search_memory implementations. */
+
+void allocate_pattern_buffer (char **pattern_bufp, char **pattern_buf_end,
+ ULONGEST *pattern_buf_size);
+
+void increase_pattern_buffer (char **pattern_bufp, char **pattern_buf_end,
+ ULONGEST *pattern_buf_size, int val_bytes);
+
+int search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len,
+ const char *pattern_buf, ULONGEST pattern_len,
+ CORE_ADDR *found_addr);
+
+void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p);
+
/* Tracepoint-related operations. */
#define target_trace_init() \
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S
new file mode 100644
index 0000000..83faaf6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S
@@ -0,0 +1,457 @@
+ .file "x86_64-vla-pointer.c"
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .text
+.Ltext0:
+.globl foo
+ .type foo, @function
+foo:
+.LFB2:
+ .file 1 "x86_64-vla-pointer.c"
+ .loc 1 22 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ subq $64, %rsp
+.LCFI2:
+ movl %edi, -36(%rbp)
+ .loc 1 22 0
+ movq %rsp, %rax
+ movq %rax, -48(%rbp)
+ .loc 1 23 0
+ movl -36(%rbp), %edx
+ movslq %edx,%rax
+ subq $1, %rax
+ movq %rax, -24(%rbp)
+ .loc 1 24 0
+ movslq %edx,%rax
+ addq $15, %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ subq %rax, %rsp
+ movq %rsp, -56(%rbp)
+ movq -56(%rbp), %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ movq %rax, -56(%rbp)
+ movq -56(%rbp), %rax
+ movq %rax, -16(%rbp)
+ .loc 1 27 0
+ movl $0, -4(%rbp)
+ jmp .L2
+.L3:
+ .loc 1 28 0
+ movl -4(%rbp), %esi
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ movq -16(%rbp), %rdx
+ movslq %esi,%rax
+ movb %cl, (%rdx,%rax)
+ .loc 1 27 0
+ addl $1, -4(%rbp)
+.L2:
+ movl -4(%rbp), %eax
+ cmpl -36(%rbp), %eax
+ jl .L3
+ .loc 1 30 0
+ .globl break_here
+break_here:
+ movq -16(%rbp), %rax
+ movb $0, (%rax)
+ movq -48(%rbp), %rsp
+ .loc 1 31 0
+ leave
+ ret
+.LFE2:
+ .size foo, .-foo
+ .section .debug_frame,"",@progbits
+.Lframe0:
+ .long .LECIE0-.LSCIE0
+.LSCIE0:
+ .long 0xffffffff
+ .byte 0x1
+ .string ""
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE0:
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0
+.LASFDE0:
+ .long .Lframe0
+ .quad .LFB2
+ .quad .LFE2-.LFB2
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE0:
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0x0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x3
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1
+.LASFDE1:
+ .long .LASFDE1-.Lframe1
+ .long .LFB2
+ .long .LFE2-.LFB2
+ .uleb128 0x0
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+ .text
+.Letext0:
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .quad .LFB2-.Ltext0
+ .quad .LCFI0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI0-.Ltext0
+ .quad .LCFI1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI1-.Ltext0
+ .quad .LFE2-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad 0x0
+ .quad 0x0
+ .section .debug_info
+.Ldebug_relative:
+ .long .Ldebug_end - .Ldebug_start
+.Ldebug_start:
+ .value 0x2
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF2
+ .byte 0x1
+ .long .LASF3
+ .long .LASF4
+ .quad .Ltext0
+ .quad .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .string "foo"
+ .byte 0x1
+ .byte 0x16
+ .byte 0x1
+ .quad .LFB2
+ .quad .LFE2
+ .long .LLST0
+ .long .Ltype_int - .Ldebug_relative
+ .uleb128 0x3
+ .long .LASF5
+ .byte 0x1
+ .byte 0x15
+ .long .Ltype_int - .Ldebug_relative
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -52
+.Ltag_pointer:
+ .uleb128 0x4
+ .byte 0x8 /* DW_AT_byte_size */
+ .long .Ltag_array_type - .debug_info /* DW_AT_type */
+ .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */
+ .long .LASF0
+ .byte 0x1
+ .byte 0x18
+#if 1
+ .long .Ltag_pointer - .debug_info
+#else
+ /* Debugging only: Skip the typedef indirection. */
+ .long .Ltag_array_type - .debug_info
+#endif
+ /* DW_AT_location: DW_FORM_block1: start */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -32
+#if 0
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+ /* DW_AT_location: DW_FORM_block1: end */
+ .uleb128 0x6
+ .string "i"
+ .byte 0x1
+ .byte 0x19
+ .long .Ltype_int - .Ldebug_relative
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0x0
+.Ltype_int:
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+.Ltag_array_type:
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .long .Ltype_char - .Ldebug_relative
+ .long .Ltype_ulong - .Ldebug_relative /* DW_AT_sibling: DW_FORM_ref4 */
+1: /* DW_AT_data_location: DW_FORM_block1: start */
+ .byte 2f - 3f /* length */
+3:
+ .byte 0x97 /* DW_OP_push_object_address */
+#if 1
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+2: /* DW_AT_data_location: DW_FORM_block1: end */
+ .uleb128 0x9
+ .long .Ltype_char - .Ldebug_relative /* DW_AT_type: DW_FORM_ref4 */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -40
+ .byte 0x6
+ .byte 0x0
+.Ltype_ulong:
+ .uleb128 0xa
+ .byte 0x8
+ .byte 0x7
+.Ltype_char:
+ .uleb128 0xb
+ .byte 0x1
+ .byte 0x6
+ .long .LASF1
+ .byte 0x0
+.Ldebug_end:
+ .section .debug_abbrev
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x27
+ .uleb128 0xc
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x4 /* .Ltag_pointer abbrev */
+ .uleb128 0x0f /* DW_TAG_pointer_type */
+ .byte 0x0
+ .uleb128 0x0b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x5
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x6
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x50 /* DW_AT_data_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x9
+ .uleb128 0x21
+ .byte 0x0
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2f
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xa
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .byte 0x0
+ .byte 0x0
+ .byte 0x0
+ .section .debug_pubnames,"",@progbits
+ .long 0x16
+ .value 0x2
+ .long .Ldebug_info0
+ .long 0xa8
+ .long 0x2d
+ .string "foo"
+ .long 0x0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0x0
+ .value 0x0
+ .value 0x0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0x0
+ .quad 0x0
+ .section .debug_str,"MS",@progbits,1
+.LASF0:
+ .string "array"
+.LASF5:
+ .string "size"
+.LASF3:
+ .string "x86_64-vla-pointer.c"
+.LASF6:
+ .string "array_t"
+.LASF1:
+ .string "char"
+.LASF4:
+ .string "gdb.arch"
+.LASF2:
+ .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c
new file mode 100644
index 0000000..fe2c8f7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c
@@ -0,0 +1,43 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>. */
+
+#if 0
+
+void
+foo (int size)
+{
+ typedef char array_t[size];
+ array_t array;
+ int i;
+
+ for (i = 0; i < size; i++)
+ array[i] = i;
+
+ array[0] = 0; /* break-here */
+}
+
+#else
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
+
+#endif
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp
new file mode 100644
index 0000000..d243cf1
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp
@@ -0,0 +1,66 @@
+# Copyright 2009 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/>.
+
+if ![istarget "x86_64-*-*"] then {
+ verbose "Skipping over gdb.arch/x86_64-vla-pointer.exp test made only for x86_64."
+ return
+}
+
+set testfile x86_64-vla-pointer
+set srcasmfile ${testfile}-foo.S
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set binobjfile ${objdir}/${subdir}/${testfile}-foo.o
+if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested x86_64-vla-pointer
+ return -1
+}
+
+gdb_breakpoint "break_here"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "first: whatis array"
+gdb_test "ptype array" "type = char \\(\\*\\)\\\[26\\\]" "first: ptype array"
+
+gdb_test "whatis *array" "type = char \\\[26\\\]" "first: whatis *array"
+gdb_test "ptype *array" "type = char \\\[26\\\]" "first: ptype *array"
+
+gdb_test "p (*array)\[1\]" "\\$\[0-9\] = 1 '\\\\001'"
+gdb_test "p (*array)\[2\]" "\\$\[0-9\] = 2 '\\\\002'"
+gdb_test "p (*array)\[3\]" "\\$\[0-9\] = 3 '\\\\003'"
+gdb_test "p (*array)\[4\]" "\\$\[0-9\] = 4 '\\\\004'"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "second: whatis array"
+gdb_test "ptype array" "type = char \\(\\*\\)\\\[78\\\]" "second: ptype array"
+
+gdb_test "whatis *array" "type = char \\\[78\\\]" "second: whatis *array"
+gdb_test "ptype *array" "type = char \\\[78\\\]" "second: ptype *array"
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S
new file mode 100644
index 0000000..66f7a39
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S
@@ -0,0 +1,455 @@
+ .file "x86_64-vla-typedef.c"
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .text
+.Ltext0:
+.globl foo
+ .type foo, @function
+foo:
+.LFB2:
+ .file 1 "x86_64-vla-typedef.c"
+ .loc 1 22 0
+ pushq %rbp
+.LCFI0:
+ movq %rsp, %rbp
+.LCFI1:
+ subq $64, %rsp
+.LCFI2:
+ movl %edi, -36(%rbp)
+ .loc 1 22 0
+ movq %rsp, %rax
+ movq %rax, -48(%rbp)
+ .loc 1 23 0
+ movl -36(%rbp), %edx
+ movslq %edx,%rax
+ subq $1, %rax
+ movq %rax, -24(%rbp)
+ .loc 1 24 0
+ movslq %edx,%rax
+ addq $15, %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ subq %rax, %rsp
+ movq %rsp, -56(%rbp)
+ movq -56(%rbp), %rax
+ addq $15, %rax
+ shrq $4, %rax
+ salq $4, %rax
+ movq %rax, -56(%rbp)
+ movq -56(%rbp), %rax
+ movq %rax, -16(%rbp)
+ .loc 1 27 0
+ movl $0, -4(%rbp)
+ jmp .L2
+.L3:
+ .loc 1 28 0
+ movl -4(%rbp), %esi
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ movq -16(%rbp), %rdx
+ movslq %esi,%rax
+ movb %cl, (%rdx,%rax)
+ .loc 1 27 0
+ addl $1, -4(%rbp)
+.L2:
+ movl -4(%rbp), %eax
+ cmpl -36(%rbp), %eax
+ jl .L3
+ .loc 1 30 0
+ .globl break_here
+break_here:
+ movq -16(%rbp), %rax
+ movb $0, (%rax)
+ movq -48(%rbp), %rsp
+ .loc 1 31 0
+ leave
+ ret
+.LFE2:
+ .size foo, .-foo
+ .section .debug_frame,"",@progbits
+.Lframe0:
+ .long .LECIE0-.LSCIE0
+.LSCIE0:
+ .long 0xffffffff
+ .byte 0x1
+ .string ""
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE0:
+.LSFDE0:
+ .long .LEFDE0-.LASFDE0
+.LASFDE0:
+ .long .Lframe0
+ .quad .LFB2
+ .quad .LFE2-.LFB2
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE0:
+ .section .eh_frame,"a",@progbits
+.Lframe1:
+ .long .LECIE1-.LSCIE1
+.LSCIE1:
+ .long 0x0
+ .byte 0x1
+ .string "zR"
+ .uleb128 0x1
+ .sleb128 -8
+ .byte 0x10
+ .uleb128 0x1
+ .byte 0x3
+ .byte 0xc
+ .uleb128 0x7
+ .uleb128 0x8
+ .byte 0x90
+ .uleb128 0x1
+ .align 8
+.LECIE1:
+.LSFDE1:
+ .long .LEFDE1-.LASFDE1
+.LASFDE1:
+ .long .LASFDE1-.Lframe1
+ .long .LFB2
+ .long .LFE2-.LFB2
+ .uleb128 0x0
+ .byte 0x4
+ .long .LCFI0-.LFB2
+ .byte 0xe
+ .uleb128 0x10
+ .byte 0x86
+ .uleb128 0x2
+ .byte 0x4
+ .long .LCFI1-.LCFI0
+ .byte 0xd
+ .uleb128 0x6
+ .align 8
+.LEFDE1:
+ .text
+.Letext0:
+ .section .debug_loc,"",@progbits
+.Ldebug_loc0:
+.LLST0:
+ .quad .LFB2-.Ltext0
+ .quad .LCFI0-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 8
+ .quad .LCFI0-.Ltext0
+ .quad .LCFI1-.Ltext0
+ .value 0x2
+ .byte 0x77
+ .sleb128 16
+ .quad .LCFI1-.Ltext0
+ .quad .LFE2-.Ltext0
+ .value 0x2
+ .byte 0x76
+ .sleb128 16
+ .quad 0x0
+ .quad 0x0
+ .section .debug_info
+ .long .Ldebug_end - .Ldebug_start
+.Ldebug_start:
+ .value 0x2
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF2
+ .byte 0x1
+ .long .LASF3
+ .long .LASF4
+ .quad .Ltext0
+ .quad .Letext0
+ .long .Ldebug_line0
+ .uleb128 0x2
+ .byte 0x1
+ .string "foo"
+ .byte 0x1
+ .byte 0x16
+ .byte 0x1
+ .quad .LFB2
+ .quad .LFE2
+ .long .LLST0
+ .long 0x83
+ .uleb128 0x3
+ .long .LASF5
+ .byte 0x1
+ .byte 0x15
+ .long 0x83
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -52
+.Ltag_typedef:
+ .uleb128 0x4
+ .long .LASF6
+ .byte 0x1
+ .byte 0x17
+ .long .Ltag_array_type - .debug_info
+ .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */
+ .long .LASF0
+ .byte 0x1
+ .byte 0x18
+#if 1
+ .long .Ltag_typedef - .debug_info
+#else
+ /* Debugging only: Skip the typedef indirection. */
+ .long .Ltag_array_type - .debug_info
+#endif
+ /* DW_AT_location: DW_FORM_block1: start */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -32
+#if 0
+ .byte 0x6 /* DW_OP_deref */
+#else
+ .byte 0x96 /* DW_OP_nop */
+#endif
+ /* DW_AT_location: DW_FORM_block1: end */
+ .uleb128 0x6
+ .string "i"
+ .byte 0x1
+ .byte 0x19
+ .long 0x83
+ .byte 0x2
+ .byte 0x91
+ .sleb128 -20
+ .byte 0x0
+ .uleb128 0x7
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+.Ltag_array_type:
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */
+ .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */
+1: /* DW_AT_data_location: DW_FORM_block1: start */
+ .byte 2f - 3f /* length */
+3:
+ .byte 0x97 /* DW_OP_push_object_address */
+ .byte 0x6 /* DW_OP_deref */
+2: /* DW_AT_data_location: DW_FORM_block1: end */
+ .uleb128 0x9
+ .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */
+ .byte 0x3
+ .byte 0x91
+ .sleb128 -40
+ .byte 0x6
+ .byte 0x0
+ .uleb128 0xa
+ .byte 0x8
+ .byte 0x7
+ .uleb128 0xb
+ .byte 0x1
+ .byte 0x6
+ .long .LASF1
+ .byte 0x0
+.Ldebug_end:
+ .section .debug_abbrev
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x10
+ .uleb128 0x6
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0x1
+ .uleb128 0x3f
+ .uleb128 0xc
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x27
+ .uleb128 0xc
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x1
+ .uleb128 0x40
+ .uleb128 0x6
+ .uleb128 0x1
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x5
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x4
+ .uleb128 0x16
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x5
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x6
+ .uleb128 0x34
+ .byte 0x0
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x2
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x7
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */
+ .uleb128 0x1
+ .byte 0x1
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x1 /* DW_AT_sibling */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x50 /* DW_AT_data_location */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0x9
+ .uleb128 0x21
+ .byte 0x0
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x2f
+ .uleb128 0xa
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xa
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .byte 0x0
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0x24
+ .byte 0x0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0xe
+ .byte 0x0
+ .byte 0x0
+ .byte 0x0
+ .section .debug_pubnames,"",@progbits
+ .long 0x16
+ .value 0x2
+ .long .Ldebug_info0
+ .long 0xa8
+ .long 0x2d
+ .string "foo"
+ .long 0x0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0x0
+ .value 0x0
+ .value 0x0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0x0
+ .quad 0x0
+ .section .debug_str,"MS",@progbits,1
+.LASF0:
+ .string "array"
+.LASF5:
+ .string "size"
+.LASF3:
+ .string "x86_64-vla-typedef.c"
+.LASF6:
+ .string "array_t"
+.LASF1:
+ .string "char"
+.LASF4:
+ .string "gdb.arch"
+.LASF2:
+ .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c
new file mode 100644
index 0000000..b809c4e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c
@@ -0,0 +1,43 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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/>. */
+
+#if 0
+
+void
+foo (int size)
+{
+ typedef char array_t[size];
+ array_t array;
+ int i;
+
+ for (i = 0; i < size; i++)
+ array[i] = i;
+
+ array[0] = 0; /* break-here */
+}
+
+#else
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
+
+#endif
diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp
new file mode 100644
index 0000000..b05411e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp
@@ -0,0 +1,64 @@
+# Copyright 2009 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/>.
+
+# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate.
+
+if ![istarget "x86_64-*-*"] then {
+ verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64."
+ return
+}
+
+set testfile x86_64-vla-typedef
+set srcasmfile ${testfile}-foo.S
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set binobjfile ${objdir}/${subdir}/${testfile}-foo.o
+if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested x86_64-vla-typedef
+ return -1
+}
+
+gdb_breakpoint "break_here"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = array_t" "first: whatis array"
+
+gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array"
+
+gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\001'"
+gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\002'"
+gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\003'"
+gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\004'"
+
+gdb_continue_to_breakpoint "break_here"
+
+gdb_test "whatis array" "type = array_t" "second: whatis array"
+
+gdb_test "ptype array" "type = char \\\[78\\\]" "second: ptype array"
diff --git a/gdb/testsuite/gdb.base/arrayidx.c b/gdb/testsuite/gdb.base/arrayidx.c
index ecc3289..f79ad40 100644
--- a/gdb/testsuite/gdb.base/arrayidx.c
+++ b/gdb/testsuite/gdb.base/arrayidx.c
@@ -17,6 +17,13 @@
int array[] = {1, 2, 3, 4};
+#ifdef __GNUC__
+struct
+ {
+ int a[0];
+ } unbound;
+#endif
+
int
main (void)
{
diff --git a/gdb/testsuite/gdb.base/arrayidx.exp b/gdb/testsuite/gdb.base/arrayidx.exp
index 0ef6c4b..330ed87 100644
--- a/gdb/testsuite/gdb.base/arrayidx.exp
+++ b/gdb/testsuite/gdb.base/arrayidx.exp
@@ -59,4 +59,12 @@ gdb_test "print array" \
"\\{\\\[0\\\] = 1, \\\[1\\\] = 2, \\\[2\\\] = 3, \\\[3\\\] = 4\\}" \
"Print array with array-indexes on"
-
+set test "p unbound.a == &unbound.a\[0\]"
+gdb_test_multiple $test $test {
+ -re " = 1\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "No symbol \"unbound\" in current context.\r\n$gdb_prompt $" {
+ unsupported "$test (no GCC)"
+ }
+}
diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp
index d71641b..dbe86eb 100644
--- a/gdb/testsuite/gdb.base/help.exp
+++ b/gdb/testsuite/gdb.base/help.exp
@@ -606,7 +606,7 @@ gdb_test "help stepi" "Step one instruction exactly\.\[\r\n\]+Argument N means d
gdb_test "help signal" "Continue program giving it signal.*" "help signal"
# test help source
# vxgdb reads .vxgdbinit
-gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\." "help source"
+gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\.\[\r\n\]+Optional -p switch \\(before the filename\\) causes FILE to be evaluated\[\r\n\]+as Python code\." "help source"
# test help stack
test_class_help "stack" {
"Examining the stack\..*\[\r\n\]+"
diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.c b/gdb/testsuite/gdb.base/internal-var-field-address.c
new file mode 100644
index 0000000..eeb7b85
--- /dev/null
+++ b/gdb/testsuite/gdb.base/internal-var-field-address.c
@@ -0,0 +1,20 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>. */
+
+struct {
+ int field;
+} staticstruct = { 1 };
diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.exp b/gdb/testsuite/gdb.base/internal-var-field-address.exp
new file mode 100644
index 0000000..6d82e73
--- /dev/null
+++ b/gdb/testsuite/gdb.base/internal-var-field-address.exp
@@ -0,0 +1,26 @@
+# Copyright 2009 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/>.
+
+set test internal-var-field-address
+set binfile ${test}.x
+if { [gdb_compile "${srcdir}/${subdir}/${test}.c" "${objdir}/${subdir}/${binfile}" object {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+clean_restart $binfile
+
+gdb_test {set $varstruct = staticstruct}
+gdb_test {p $varstruct.field} " = 1"
diff --git a/gdb/testsuite/gdb.base/radix.exp b/gdb/testsuite/gdb.base/radix.exp
index 9fd6cb5..93aa142 100644
--- a/gdb/testsuite/gdb.base/radix.exp
+++ b/gdb/testsuite/gdb.base/radix.exp
@@ -163,13 +163,6 @@ gdb_test "set radix" \
"Input and output radices now set to decimal 10, hex a, octal 12\." \
"Reset radices"
-gdb_test "set input-radix 0" \
- "Nonsense input radix ``decimal 0''; input radix unchanged\\." \
- "Reject input-radix 0"
-gdb_test "show input-radix" \
- "Default input radix for entering numbers is 10\\." \
- "Input radix unchanged after rejecting 0"
-
gdb_test "set input-radix 1" \
"Nonsense input radix ``decimal 1''; input radix unchanged\\." \
"Reject input-radix 1"
diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c
new file mode 100644
index 0000000..c5d5ee0
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla-overflow.c
@@ -0,0 +1,30 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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>
+
+int
+main (int argc, char **argv)
+{
+ int array[argc];
+
+ array[0] = array[0];
+
+ abort ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp
new file mode 100644
index 0000000..7203a48
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla-overflow.exp
@@ -0,0 +1,108 @@
+# Copyright 2008 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/>.
+
+# We could crash in:
+# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69
+# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97
+# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL));
+# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496
+# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156
+# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206
+# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430
+# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840
+# ...
+# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292
+# ...
+# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273
+
+set testfile vla-overflow
+set shfile ${objdir}/${subdir}/${testfile}-gdb.sh
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+set f [open "|getconf PAGESIZE" "r"]
+gets $f pagesize
+close $f
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set pid_of_gdb [exp_pid -i [board_info host fileid]]
+
+if { [runto_main] < 0 } {
+ untested vla-overflow
+ return -1
+}
+
+# Get the GDB memory size when we stay at main.
+
+proc memory_v_pages_get {} {
+ global pid_of_gdb pagesize
+ set fd [open "/proc/$pid_of_gdb/statm"]
+ gets $fd line
+ close $fd
+ # number of pages of virtual memory
+ scan $line "%d" drs
+ return $drs
+}
+
+set pages_found [memory_v_pages_get]
+
+set mb_reserve 10
+verbose -log "pages_found = $pages_found, mb_reserve = $mb_reserve"
+set kb_found [expr $pages_found * $pagesize / 1024]
+set kb_permit [expr $kb_found + 1 * 1024 + $mb_reserve * 1024]
+verbose -log "kb_found = $kb_found, kb_permit = $kb_permit"
+
+# Create the ulimit wrapper.
+set f [open $shfile "w"]
+puts $f "#! /bin/sh"
+puts $f "ulimit -v $kb_permit"
+puts $f "exec $GDB \"\$@\""
+close $f
+remote_exec host "chmod +x $shfile"
+
+gdb_exit
+set GDBold $GDB
+set GDB "$shfile"
+gdb_start
+set GDB $GDBold
+
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set pid_of_gdb [exp_pid -i [board_info host fileid]]
+
+# Check the size again after the second run.
+# We must not stop in main as it would cache `array' and never crash later.
+
+gdb_run_cmd
+
+verbose -log "kb_found before abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
+
+gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()"
+
+verbose -log "kb_found in abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
+
+# `abort' can get expressed as `*__GI_abort'.
+gdb_test "bt" "in \[^ \]*abort \\(.* in main \\(.*" "Backtrace after abort()"
+
+verbose -log "kb_found in bt after abort() = [expr [memory_v_pages_get] * $pagesize / 1024]"
diff --git a/gdb/testsuite/gdb.base/vla.c b/gdb/testsuite/gdb.base/vla.c
new file mode 100644
index 0000000..e1f3ed1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla.c
@@ -0,0 +1,55 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008 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 <string.h>
+
+void
+marker (void)
+{
+}
+
+void
+bar (char *a, char *b, char *c, int size)
+{
+ memset (a, '1', size);
+ memset (b, '2', size);
+ memset (c, '3', 48);
+}
+
+void
+foo (int size)
+{
+ char temp1[size];
+ char temp3[48];
+
+ temp1[size - 1] = '\0';
+ {
+ char temp2[size];
+
+ bar (temp1, temp2, temp3, size);
+
+ marker (); /* break-here */
+ }
+}
+
+int
+main (void)
+{
+ foo (26);
+ foo (78);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp
new file mode 100644
index 0000000..5da7378
--- /dev/null
+++ b/gdb/testsuite/gdb.base/vla.exp
@@ -0,0 +1,62 @@
+# Copyright 2008 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/>.
+
+set testfile vla
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile test program"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+ untested vla
+ return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1"
+gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2"
+gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3"
+
+gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1"
+gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2"
+gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3"
+
+gdb_test "p temp1" " = '1' <repeats 26 times>" "first: print temp1"
+gdb_test "p temp2" " = '2' <repeats 26 times>" "first: print temp2"
+gdb_test "p temp3" " = '3' <repeats 48 times>" "first: print temp3"
+
+gdb_continue_to_breakpoint "break-here"
+
+gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1"
+gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2"
+gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3"
+
+gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1"
+gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2"
+gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3"
+
+gdb_test "p temp1" " = '1' <repeats 78 times>" "second: print temp1"
+gdb_test "p temp2" " = '2' <repeats 78 times>" "second: print temp2"
+gdb_test "p temp3" " = '3' <repeats 48 times>" "second: print temp3"
diff --git a/gdb/testsuite/gdb.cp/Makefile.in b/gdb/testsuite/gdb.cp/Makefile.in
index c990a64..c964db9 100644
--- a/gdb/testsuite/gdb.cp/Makefile.in
+++ b/gdb/testsuite/gdb.cp/Makefile.in
@@ -4,7 +4,7 @@ srcdir = @srcdir@
EXECUTABLES = ambiguous annota2 anon-union cplusfuncs cttiadd \
derivation inherit local member-ptr method misc \
overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \
- ref-types ref-params method2 pr9594 gdb2495 virtfunc2
+ ref-types ref-params method2 pr9594 gdb2495 gdb9593 virtfunc2
all info install-info dvi install uninstall installcheck check:
@echo "Nothing to be done for $@..."
diff --git a/gdb/testsuite/gdb.cp/gdb9593.cc b/gdb/testsuite/gdb.cp/gdb9593.cc
new file mode 100644
index 0000000..783c962
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/gdb9593.cc
@@ -0,0 +1,180 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008, 2009 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 <iostream>
+
+using namespace std;
+
+class NextOverThrowDerivates
+{
+
+public:
+
+
+ // Single throw an exception in this function.
+ void function1()
+ {
+ throw 20;
+ }
+
+ // Throw an exception in another function.
+ void function2()
+ {
+ function1();
+ }
+
+ // Throw an exception in another function, but handle it
+ // locally.
+ void function3 ()
+ {
+ {
+ try
+ {
+ function1 ();
+ }
+ catch (...)
+ {
+ cout << "Caught and handled function1 exception" << endl;
+ }
+ }
+ }
+
+ void rethrow ()
+ {
+ try
+ {
+ function1 ();
+ }
+ catch (...)
+ {
+ throw;
+ }
+ }
+
+ void finish ()
+ {
+ // We use this to test that a "finish" here does not end up in
+ // this frame, but in the one above.
+ try
+ {
+ function1 ();
+ }
+ catch (int x)
+ {
+ }
+ function1 (); // marker for until
+ }
+
+ void until ()
+ {
+ function1 ();
+ function1 (); // until here
+ }
+
+};
+NextOverThrowDerivates next_cases;
+
+
+int main ()
+{
+ try
+ {
+ next_cases.function1 ();
+ }
+ catch (...)
+ {
+ // Discard
+ }
+
+ try
+ {
+ next_cases.function2 ();
+ }
+ catch (...)
+ {
+ // Discard
+ }
+
+ try
+ {
+ // This is duplicated so we can next over one but step into
+ // another.
+ next_cases.function2 ();
+ }
+ catch (...)
+ {
+ // Discard
+ }
+
+ next_cases.function3 ();
+
+ try
+ {
+ next_cases.rethrow ();
+ }
+ catch (...)
+ {
+ // Discard
+ }
+
+ try
+ {
+ // Another duplicate so we can test "finish".
+ next_cases.function2 ();
+ }
+ catch (...)
+ {
+ // Discard
+ }
+
+ // Another test for "finish".
+ try
+ {
+ next_cases.finish ();
+ }
+ catch (...)
+ {
+ }
+
+ // Test of "until".
+ try
+ {
+ next_cases.finish ();
+ }
+ catch (...)
+ {
+ }
+
+ // Test of "until" with an argument.
+ try
+ {
+ next_cases.until ();
+ }
+ catch (...)
+ {
+ }
+
+ // Test of "advance".
+ try
+ {
+ next_cases.until ();
+ }
+ catch (...)
+ {
+ }
+}
+
diff --git a/gdb/testsuite/gdb.cp/gdb9593.exp b/gdb/testsuite/gdb.cp/gdb9593.exp
new file mode 100644
index 0000000..ee9aeff
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/gdb9593.exp
@@ -0,0 +1,185 @@
+# Copyright 2008, 2009 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/>.
+
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+if { [skip_cplus_tests] } { continue }
+
+set prms_id 9593
+set bug_id 0
+
+set testfile "gdb9593"
+set srcfile ${testfile}.cc
+set binfile $objdir/$subdir/$testfile
+
+# Create and source the file that provides information about the compiler
+# used to compile the test case.
+if [get_compiler_info ${binfile} "c++"] {
+ untested gdb9593.exp
+ return -1
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+ untested gdb9593.exp
+ return -1
+}
+
+# Some targets can't do function calls, so don't even bother with this
+# test.
+if [target_info exists gdb,cannot_call_functions] {
+ setup_xfail "*-*-*" 9593
+ fail "This target can not call functions"
+ continue
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] then {
+ perror "couldn't run to main"
+ continue
+}
+
+# See whether we have the needed unwinder hooks.
+set ok 1
+gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
+ -re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
+ pass "check for unwinder hook"
+ }
+ -re "No symbol .* in current context.\r\n$gdb_prompt $" {
+ # Pass the test so we don't get bogus fails in the results.
+ pass "check for unwinder hook"
+ set ok 0
+ }
+}
+if {!$ok} {
+ untested gdb9593.exp
+ return -1
+}
+
+# See http://sourceware.org/bugzilla/show_bug.cgi?id=9593
+
+gdb_test "next" \
+ ".*catch (...).*" \
+ "next over a throw 1"
+
+gdb_test "next" \
+ ".*next_cases.function2.*" \
+ "next past catch 1"
+
+gdb_test "next" \
+ ".*catch (...).*" \
+ "next over a throw 2"
+
+gdb_test "next" \
+ ".*next_cases.function2.*" \
+ "next past catch 2"
+
+gdb_test "step" \
+ ".*function1().*" \
+ "step into function2 1"
+
+gdb_test "next" \
+ ".*catch (...).*" \
+ "next over a throw 3"
+
+gdb_test "next" \
+ ".*next_cases.function3.*" \
+ "next past catch 3"
+
+gdb_test "next" \
+ ".*next_cases.rethrow.*" \
+ "next over a throw 4"
+
+gdb_test "next" \
+ ".*catch (...).*" \
+ "next over a rethrow"
+
+gdb_test "next" \
+ ".*next_cases.function2.*" \
+ "next after a rethrow"
+
+gdb_test "step" \
+ ".*function1().*" \
+ "step into function2 2"
+
+gdb_test "finish" \
+ ".*catch (...).*" \
+ "finish 1"
+
+gdb_test "next" \
+ ".*next_cases.finish ().*" \
+ "next past catch 4"
+
+gdb_test "step" \
+ ".*function1 ().*" \
+ "step into finish method"
+
+gdb_test "finish" \
+ ".*catch (...).*" \
+ "finish 2"
+
+gdb_test "next" \
+ ".*next_cases.finish ().*" \
+ "next past catch 5"
+
+gdb_test "step" \
+ ".*function1 ().*" \
+ "step into finish, for until"
+
+gdb_test "until" \
+ ".*catch .int x.*" \
+ "until with no argument 1"
+
+set line [gdb_get_line_number "marker for until" $testfile.cc]
+
+gdb_test "until $line" \
+ ".*function1 ().*" \
+ "next past catch 6"
+
+gdb_test "until" \
+ ".*catch (...).*" \
+ "until with no argument 2"
+
+set line [gdb_get_line_number "until here" $testfile.cc]
+
+gdb_test "next" \
+ ".*next_cases.until ().*" \
+ "next past catch 6"
+
+gdb_test "step" \
+ ".*function1 ().*" \
+ "step into until"
+
+gdb_test "until $line" \
+ ".*catch (...).*" \
+ "until-over-throw"
+
+gdb_test "next" \
+ ".*next_cases.until ().*" \
+ "next past catch 7"
+
+gdb_test "step" \
+ ".*function1 ().*" \
+ "step into until, for advance"
+
+gdb_test "advance $line" \
+ ".*catch (...).*" \
+ "advance-over-throw"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-aranges.S b/gdb/testsuite/gdb.dwarf2/dw2-aranges.S
new file mode 100644
index 0000000..d5b9ca5
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-aranges.S
@@ -0,0 +1,140 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2004, 2007, 2008, 2009 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/>. */
+
+/* Test .debug_aranges containing zero address_size. */
+
+/* Dummy function to provide debug information for. */
+
+ .text
+.Lbegin_text1:
+ .globl main
+ .type main, %function
+main:
+.Lbegin_main:
+ .int 0
+.Lend_main:
+ .size main, .-main
+.Lend_text1:
+
+/* Debug information */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .4byte .Lend_text1 /* DW_AT_high_pc */
+ .4byte .Lbegin_text1 /* DW_AT_low_pc */
+ .ascii "file1.txt\0" /* DW_AT_name */
+ .ascii "GNU C 3.3.3\0" /* DW_AT_producer */
+ .byte 1 /* DW_AT_language (C) */
+
+ /* main */
+ .uleb128 2 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_external */
+ .byte 1 /* DW_AT_decl_file */
+ .byte 2 /* DW_AT_decl_line */
+ .ascii "main\0" /* DW_AT_name */
+ .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */
+ .4byte .Lbegin_main /* DW_AT_low_pc */
+ .4byte .Lend_main /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_frame_base: length */
+ .byte 0x55 /* DW_AT_frame_base: DW_OP_reg5 */
+
+.Ltype_int:
+ .uleb128 3 /* Abbrev: DW_TAG_base_type */
+ .ascii "int\0" /* DW_AT_name */
+ .byte 4 /* DW_AT_byte_size */
+ .byte 5 /* DW_AT_encoding */
+
+ .byte 0 /* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+ .section .debug_abbrev
+.Labbrev1_begin:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 2 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 0 /* has_children */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3a /* DW_AT_decl_file */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3b /* DW_AT_decl_line */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x40 /* DW_AT_frame_base */
+ .uleb128 0xa /* DW_FORM_block1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x24 /* DW_TAG_base_type */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3e /* DW_AT_encoding */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+/* aranges table */
+ .section .debug_aranges
+ .long .Laranges_end - 1f
+1:
+ .2byte 2 /* aranges Version */
+ .4byte .Lcu1_begin - .debug_info /* Offset into .debug_info section */
+ /* The GDB crasher is this zero value. */
+ .byte 0 /* aranges address_size */
+ .byte 0 /* aranges segment_size */
+
+.Laranges_end:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-aranges.exp b/gdb/testsuite/gdb.dwarf2/dw2-aranges.exp
new file mode 100644
index 0000000..39632d5
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-aranges.exp
@@ -0,0 +1,40 @@
+# Copyright 2004, 2005, 2007, 2008, 2009 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/>.
+
+# Test .debug_aranges containing zero address_size.
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-aranges"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {nodebug}] != "" } {
+ return -1
+}
+
+clean_restart $testfile
+
+# Failed gdb_load would abort the testcase execution earlier.
+pass "file loaded"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.c b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c
new file mode 100644
index 0000000..1f02d90
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2004 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+
+/* The function `func1' traced into must have debug info on offset > 0;
+ (DW_UNSND (attr)). This is the reason of `func0' existence. */
+
+void
+func0(int a, int b)
+{
+}
+
+/* `func1' being traced into must have some arguments to dump. */
+
+void
+func1(int a, int b)
+{
+ func0 (a,b);
+}
+
+int
+main(void)
+{
+ func1 (1, 2);
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp
new file mode 100644
index 0000000..1c6e84a
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp
@@ -0,0 +1,79 @@
+# Copyright 2006 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Minimal DWARF-2 unit test
+
+# This test can only be run on targets which support DWARF-2.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-stripped"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}.x
+
+remote_exec build "rm -f ${binfile}"
+
+# get the value of gcc_compiled
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+# This test can only be run on gcc as we use additional_flags=FIXME
+if {$gcc_compiled == 0} {
+ return 0
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-ggdb3}] != "" } {
+ return -1
+}
+
+remote_exec build "objcopy -R .debug_loc ${binfile}"
+set strip_output [remote_exec build "objdump -h ${binfile}"]
+
+set test "stripping test file preservation"
+if [ regexp ".debug_info " $strip_output] {
+ pass "$test (.debug_info preserved)"
+} else {
+ fail "$test (.debug_info got also stripped)"
+}
+
+set test "stripping test file functionality"
+if [ regexp ".debug_loc " $strip_output] {
+ fail "$test (.debug_loc still present)"
+} else {
+ pass "$test (.debug_loc stripped)"
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# For C programs, "start" should stop in main().
+
+gdb_test "start" \
+ ".*main \\(\\) at .*" \
+ "start"
+gdb_test "step" \
+ "func.* \\(.*\\) at .*" \
+ "step"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S
new file mode 100644
index 0000000..5fcdd84
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S
@@ -0,0 +1,83 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>. */
+
+/* Debug information */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .ascii "dw2-struct-member-data-location.c\0" /* DW_AT_name */
+ .ascii "GNU C 4.3.2\0" /* DW_AT_producer */
+ .byte 1 /* DW_AT_language (C) */
+
+.Ltype_uchar:
+ .uleb128 2 /* Abbrev: DW_TAG_structure_type */
+ .ascii "some_struct\0" /* DW_AT_name */
+
+ .uleb128 3 /* Abbrev: DW_TAG_member */
+ .ascii "field\0" /* DW_AT_name */
+ .byte 0 /* DW_AT_data_member_location */
+
+ .byte 0 /* End of children of some_struct */
+
+ .byte 0 /* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+ .section .debug_abbrev
+.Labbrev1_begin:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 2 /* Abbrev code */
+ .uleb128 0x13 /* DW_TAG_structure_type */
+ .byte 1 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x0d /* DW_TAG_member */
+ .byte 0 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x38 /* DW_AT_data_member_location */
+ .uleb128 0x0b /* DW_FORM_data1 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp
new file mode 100644
index 0000000..c41151c
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp
@@ -0,0 +1,37 @@
+# Copyright 2009 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 test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+ && ![istarget *-*-gnu*]
+ && ![istarget *-*-elf*]
+ && ![istarget *-*-openbsd*]
+ && ![istarget arm-*-eabi*]
+ && ![istarget powerpc-*-eabi*]} {
+ return 0
+}
+
+set testfile "dw2-struct-member-data-location"
+set srcfile ${testfile}.S
+set binfile ${testfile}.x
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${binfile}" object {nodebug}] != "" } {
+ return -1
+}
+
+clean_restart $binfile
+
+gdb_test "ptype struct some_struct" "type = struct some_struct {\[\r\n \t\]*void field;\[\r\n \t\]*}"
diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.exp b/gdb/testsuite/gdb.fortran/dwarf-stride.exp
new file mode 100644
index 0000000..cd3486b
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dwarf-stride.exp
@@ -0,0 +1,42 @@
+# Copyright 2009 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. Array element stride must not be
+# specified in the number of elements but in a number of bytes instead.
+# Original problem:
+# (gdb) p c40pt(1)
+# $1 = '0-hello', ' ' <repeats 33 times>
+# (gdb) p c40pt(2)
+# warning: Fortran array stride not divisible by the element size
+
+set testfile dwarf-stride
+set srcfile ${testfile}.f90
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f77}] } {
+ return -1
+}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".*break-here.*"
+gdb_test "p c40pt(1)" " = '0-hello.*"
+gdb_test "p c40pt(2)" " = '1-hello.*"
diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.f90 b/gdb/testsuite/gdb.fortran/dwarf-stride.f90
new file mode 100644
index 0000000..e492b3a
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dwarf-stride.f90
@@ -0,0 +1,40 @@
+! Copyright 2009 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! File written by Alan Matsuoka.
+
+program repro
+
+ type small_stride
+ character*40 long_string
+ integer small_pad
+ end type small_stride
+
+ type(small_stride), dimension (20), target :: unpleasant
+ character*40, pointer, dimension(:):: c40pt
+
+ integer i
+
+ do i = 0,19
+ unpleasant(i+1)%small_pad = i+1
+ unpleasant(i+1)%long_string = char (ichar('0') + i) // '-hello'
+ end do
+
+ c40pt => unpleasant%long_string
+
+ print *, c40pt ! break-here
+
+end program repro
diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp
new file mode 100644
index 0000000..0ccebe0
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic.exp
@@ -0,0 +1,145 @@
+# Copyright 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. It contains tests for dynamically
+# allocated Fortran arrays.
+# It depends on the GCC dynamic Fortran arrays DWARF support:
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244
+
+set testfile "dynamic"
+set srcfile ${testfile}.f90
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "varx-init"]
+gdb_continue_to_breakpoint "varx-init"
+gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx unallocated"
+gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx unallocated"
+gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) unallocated"
+gdb_test "p varx(1,5,17)=1" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17)=1 unallocated"
+gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) unallocated"
+
+gdb_breakpoint [gdb_get_line_number "varx-allocated"]
+gdb_continue_to_breakpoint "varx-allocated"
+# $1 = (( ( 0, 0, 0, 0, 0, 0) ( 0, 0, 0, 0, 0, 0) --- , 0) ) ( ( 0, 0, ...) ...) ...)
+gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx allocated"
+# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1.
+gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varx allocated"
+
+gdb_breakpoint [gdb_get_line_number "varx-filled"]
+gdb_continue_to_breakpoint "varx-filled"
+gdb_test "p varx(2, 5, 17)" "\\$\[0-9\]* = 6"
+gdb_test "p varx(1, 5, 17)" "\\$\[0-9\]* = 7"
+gdb_test "p varx(2, 6, 18)" "\\$\[0-9\]* = 8"
+gdb_test "p varx(6, 15, 28)" "\\$\[0-9\]* = 9"
+# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type.
+gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv unassociated"
+gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv unassociated"
+
+gdb_breakpoint [gdb_get_line_number "varv-associated"]
+gdb_continue_to_breakpoint "varv-associated"
+gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated"
+gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated"
+# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1.
+gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated"
+gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated"
+# Intel Fortran Compiler 10.1.008 uses the pointer type.
+gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated"
+
+gdb_breakpoint [gdb_get_line_number "varv-filled"]
+gdb_continue_to_breakpoint "varv-filled"
+gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled"
+gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled"
+
+gdb_breakpoint [gdb_get_line_number "varv-deassociated"]
+gdb_continue_to_breakpoint "varv-deassociated"
+# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type.
+gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated"
+gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated"
+gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated"
+gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\."
+gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\."
+
+gdb_breakpoint [gdb_get_line_number "varx-deallocated"]
+gdb_continue_to_breakpoint "varx-deallocated"
+gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated"
+gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated"
+gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated"
+gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated"
+gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated"
+
+gdb_breakpoint [gdb_get_line_number "vary-passed"]
+gdb_continue_to_breakpoint "vary-passed"
+# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...)
+gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)"
+
+gdb_breakpoint [gdb_get_line_number "vary-filled"]
+gdb_continue_to_breakpoint "vary-filled"
+gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)"
+gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8"
+gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9"
+gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10"
+# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...)
+gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)"
+
+gdb_breakpoint [gdb_get_line_number "varw-almostfilled"]
+gdb_continue_to_breakpoint "varw-almostfilled"
+gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)"
+gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1"
+# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...)
+gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled"
+# "up" works with GCC but other Fortran compilers may copy the values into the
+# outer function only on the exit of the inner function.
+# We need both variants as depending on the arch we optionally may still be
+# executing the caller line or not after `finish'.
+gdb_test "finish" ".*(call bar \\(y, x\\)|call foo \\(x, z\\(2:6, 4:7, 6:8\\)\\))"
+gdb_test "p z(2,4,5)" "\\$\[0-9\]* = 3"
+gdb_test "p z(2,4,6)" "\\$\[0-9\]* = 6"
+gdb_test "p z(2,4,7)" "\\$\[0-9\]* = 5"
+gdb_test "p z(4,4,6)" "\\$\[0-9\]* = 1"
+
+gdb_breakpoint [gdb_get_line_number "varz-almostfilled"]
+gdb_continue_to_breakpoint "varz-almostfilled"
+# GCC uses the pointer type here, Intel Fortran Compiler 10.1.008 does not.
+gdb_test "ptype varz" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(\\*\\)\\)?"
+# Intel Fortran Compiler 10.1.008 has a bug here - (2:11,7:7)
+# as it produces DW_AT_lower_bound == DW_AT_upper_bound == 7.
+gdb_test "ptype vart" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(2:11,7:\\*\\)\\)?"
+gdb_test "p varz" "\\$\[0-9\]* = \\(\\)"
+gdb_test "p vart" "\\$\[0-9\]* = \\(\\)"
+gdb_test "p varz(3)" "\\$\[0-9\]* = 4"
+# maps to foo::vary(1,1)
+gdb_test "p vart(2,7)" "\\$\[0-9\]* = 8"
+# maps to foo::vary(2,2)
+gdb_test "p vart(3,8)" "\\$\[0-9\]* = 9"
+# maps to foo::vary(1,3)
+gdb_test "p vart(2,9)" "\\$\[0-9\]* = 10"
diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90
new file mode 100644
index 0000000..0f43564
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dynamic.f90
@@ -0,0 +1,98 @@
+! Copyright 2007 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine baz
+ real, target, allocatable :: varx (:, :, :)
+ real, pointer :: varv (:, :, :)
+ real, target :: varu (1, 2, 3)
+ logical :: l
+ allocate (varx (1:6, 5:15, 17:28)) ! varx-init
+ l = allocated (varx)
+ varx(:, :, :) = 6 ! varx-allocated
+ varx(1, 5, 17) = 7
+ varx(2, 6, 18) = 8
+ varx(6, 15, 28) = 9
+ varv => varx ! varx-filled
+ l = associated (varv)
+ varv(3, 7, 19) = 10 ! varv-associated
+ varv => null () ! varv-filled
+ l = associated (varv)
+ deallocate (varx) ! varv-deassociated
+ l = allocated (varx)
+ varu(:, :, :) = 10 ! varx-deallocated
+ allocate (varv (1:6, 5:15, 17:28))
+ l = associated (varv)
+ varv(:, :, :) = 6
+ varv(1, 5, 17) = 7
+ varv(2, 6, 18) = 8
+ varv(6, 15, 28) = 9
+ deallocate (varv)
+ l = associated (varv)
+ varv => varu
+ varv(1, 1, 1) = 6
+ varv(1, 2, 3) = 7
+ l = associated (varv)
+end subroutine baz
+subroutine foo (vary, varw)
+ real :: vary (:, :)
+ real :: varw (:, :, :)
+ vary(:, :) = 4 ! vary-passed
+ vary(1, 1) = 8
+ vary(2, 2) = 9
+ vary(1, 3) = 10
+ varw(:, :, :) = 5 ! vary-filled
+ varw(1, 1, 1) = 6
+ varw(2, 2, 2) = 7 ! varw-almostfilled
+end subroutine foo
+subroutine bar (varz, vart)
+ real :: varz (*)
+ real :: vart (2:11, 7:*)
+ varz(1:3) = 4
+ varz(2) = 5 ! varz-almostfilled
+ vart(2,7) = vart(2,7)
+end subroutine bar
+program test
+ interface
+ subroutine foo (vary, varw)
+ real :: vary (:, :)
+ real :: varw (:, :, :)
+ end subroutine
+ end interface
+ interface
+ subroutine bar (varz, vart)
+ real :: varz (*)
+ real :: vart (2:11, 7:*)
+ end subroutine
+ end interface
+ real :: x (10, 10), y (5), z(8, 8, 8)
+ x(:,:) = 1
+ y(:) = 2
+ z(:,:,:) = 3
+ call baz
+ call foo (x, z(2:6, 4:7, 6:8))
+ call bar (y, x)
+ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort
+ if (x (1, 3) .ne. 10) call abort
+ if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort
+ if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort
+ call foo (transpose (x), z)
+ if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort
+ if (x (3, 1) .ne. 10) call abort
+end
diff --git a/gdb/testsuite/gdb.fortran/library-module-lib.f90 b/gdb/testsuite/gdb.fortran/library-module-lib.f90
new file mode 100644
index 0000000..6369d34
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/library-module-lib.f90
@@ -0,0 +1,28 @@
+! Copyright 2009 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/>.
+
+module lib
+ integer :: var_i = 1
+contains
+ subroutine lib_func
+ if (var_i .ne. 1) call abort
+ var_i = 2
+ end subroutine lib_func
+end module lib
+
+module libmany
+ integer :: var_j = 3
+ integer :: var_k = 4
+end module libmany
diff --git a/gdb/testsuite/gdb.fortran/library-module-main.f90 b/gdb/testsuite/gdb.fortran/library-module-main.f90
new file mode 100644
index 0000000..de63a65
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/library-module-main.f90
@@ -0,0 +1,23 @@
+! Copyright 2009 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/>.
+
+ use lib
+ use libmany, only: var_j
+ if (var_i .ne. 1) call abort
+ call lib_func
+ if (var_i .ne. 2) call abort
+ if (var_j .ne. 3) call abort
+ var_i = var_i ! i-is-2
+end
diff --git a/gdb/testsuite/gdb.fortran/library-module.exp b/gdb/testsuite/gdb.fortran/library-module.exp
new file mode 100644
index 0000000..4b4ea4c
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/library-module.exp
@@ -0,0 +1,53 @@
+# Copyright 2009 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/>.
+
+set testfile "library-module"
+set srcfile ${testfile}-main.f90
+set srclibfile ${testfile}-lib.f90
+set libfile ${testfile}-lib.so
+set binfile ${testfile}
+
+# Required for -fPIC by gdb_compile_shlib.
+if [get_compiler_info not-used] {
+ warning "Could not get compiler info"
+ return -1
+}
+
+if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfile}" $objdir/$subdir/$libfile {debug f77}] != "" } {
+ untested "Couldn't compile ${srclibfile}"
+ return -1
+}
+
+# prepare_for_testing cannot be used as linking with $libfile cannot be passed
+# just for the linking phase (and not the source compilation phase). And any
+# warnings on ignored $libfile abort the process.
+
+if { [gdb_compile [list $srcdir/$subdir/$srcfile $objdir/$subdir/$libfile] $objdir/$subdir/$binfile executable {debug f77}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+clean_restart $binfile
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "i-is-2"]
+gdb_continue_to_breakpoint "i-is-2" ".*i-is-2.*"
+gdb_test "print var_i" " = 2"
+gdb_test "print var_j" " = 3"
+gdb_test "print var_k" "No symbol \"var_k\" in current context\\."
diff --git a/gdb/testsuite/gdb.fortran/module.exp b/gdb/testsuite/gdb.fortran/module.exp
index 0acce4f..b952162 100644
--- a/gdb/testsuite/gdb.fortran/module.exp
+++ b/gdb/testsuite/gdb.fortran/module.exp
@@ -15,21 +15,31 @@
set testfile "module"
set srcfile ${testfile}.f90
-set binfile ${objdir}/${subdir}/${testfile}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
- untested "Couldn't compile ${srcfile}"
+if { [prepare_for_testing $testfile.exp $testfile $srcfile {debug f77}] } {
return -1
}
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-gdb_load ${binfile}
-
if ![runto MAIN__] then {
perror "couldn't run to breakpoint MAIN__"
continue
}
-gdb_test "print i" " = 42"
+# Do not use simple single-letter names as GDB would pick up for expectedly
+# nonexisting symbols some static variables from system libraries debuginfos.
+
+gdb_breakpoint [gdb_get_line_number "i-is-1"]
+gdb_continue_to_breakpoint "i-is-1" ".*i-is-1.*"
+gdb_test "print var_i" " = 1" "print var_i value 1"
+
+gdb_breakpoint [gdb_get_line_number "i-is-2"]
+gdb_continue_to_breakpoint "i-is-2" ".*i-is-2.*"
+gdb_test "print var_i" " = 2" "print var_i value 2"
+
+gdb_breakpoint [gdb_get_line_number "a-b-c-d"]
+gdb_continue_to_breakpoint "a-b-c-d" ".*a-b-c-d.*"
+gdb_test "print var_a" "No symbol \"var_a\" in current context\\."
+gdb_test "print var_b" " = 11"
+gdb_test "print var_c" "No symbol \"var_c\" in current context\\."
+gdb_test "print var_d" " = 12"
+gdb_test "print var_i" " = 14" "print var_i value 14"
diff --git a/gdb/testsuite/gdb.fortran/module.f90 b/gdb/testsuite/gdb.fortran/module.f90
index 81ef376..fb6eccd 100644
--- a/gdb/testsuite/gdb.fortran/module.f90
+++ b/gdb/testsuite/gdb.fortran/module.f90
@@ -13,10 +13,37 @@
! You should have received a copy of the GNU General Public License
! along with this program. If not, see <http://www.gnu.org/licenses/>.
-module mod
- integer :: i = 42
-end module mod
+module mod1
+ integer :: var_i = 1
+end module mod1
- use mod
- print *, i
+module mod2
+ integer :: var_i = 2
+end module mod2
+
+module modmany
+ integer :: var_a = 10, var_b = 11, var_c = 12, var_i = 14
+end module modmany
+
+ subroutine sub1
+ use mod1
+ if (var_i .ne. 1) call abort
+ var_i = var_i ! i-is-1
+ end
+
+ subroutine sub2
+ use mod2
+ if (var_i .ne. 2) call abort
+ var_i = var_i ! i-is-2
+ end
+
+ use modmany, only: var_b, var_d => var_c, var_i
+
+ call sub1
+ call sub2
+
+ if (var_b .ne. 11) call abort
+ if (var_d .ne. 12) call abort
+ if (var_i .ne. 14) call abort
+ var_b = var_b ! a-b-c-d
end
diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp
new file mode 100644
index 0000000..b1120c3
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/string.exp
@@ -0,0 +1,59 @@
+# Copyright 2008 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# This file is part of the gdb testsuite. It contains tests for Fortran
+# strings with dynamic length.
+
+set testfile "string"
+set srcfile ${testfile}.f90
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "var-init"]
+gdb_continue_to_breakpoint "var-init"
+gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)"
+gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)"
+gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)"
+gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)"
+gdb_test "ptype *e" "Attempt to take contents of a non-pointer value."
+gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)"
+gdb_test "p c" "\\$\[0-9\]* = 'c'"
+gdb_test "p d" "\\$\[0-9\]* = 'd '"
+gdb_test "p e" "\\$\[0-9\]* = 'g '"
+gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)"
+gdb_test "p *e" "Attempt to take contents of a non-pointer value."
+gdb_test "p *f" "Attempt to take contents of a non-pointer value."
+
+gdb_breakpoint [gdb_get_line_number "var-finish"]
+gdb_continue_to_breakpoint "var-finish"
+gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set"
+gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set"
diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90
new file mode 100644
index 0000000..226dc5d
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/string.f90
@@ -0,0 +1,37 @@
+! Copyright 2008 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+subroutine foo (e, f)
+ character (len=1) :: c
+ character (len=8) :: d
+ character (len=*) :: e
+ character (len=*) :: f (1:7, 8:10)
+ c = 'c'
+ d = 'd'
+ e = 'e' ! var-init
+ f = 'f'
+ f(1,9) = 'f2'
+ c = 'c' ! var-finish
+end subroutine foo
+ character (len=4) :: g, h (1:7, 8:10)
+ g = 'g'
+ h = 'h'
+ call foo (g, h)
+end
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index 9e787f0..5ca15d5 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -95,6 +95,10 @@ proc do_steps_and_nexts {} {
set description "step over ttyarg initialization"
set command "step"
}
+ -re ".*python_script = 0.*$gdb_prompt $" {
+ set description "step over python_script initialization"
+ set command "step"
+ }
-re ".*time_at_startup = get_run_time.*$gdb_prompt $" {
set description "next over get_run_time and everything it calls"
set command "next"
diff --git a/gdb/testsuite/gdb.java/jnpe.exp b/gdb/testsuite/gdb.java/jnpe.exp
new file mode 100644
index 0000000..e71391e
--- /dev/null
+++ b/gdb/testsuite/gdb.java/jnpe.exp
@@ -0,0 +1,77 @@
+# Copyright 2009 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/>.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+load_lib "java.exp"
+
+set testfile "jnpe"
+set srcfile ${testfile}.java
+set binfile ${objdir}/${subdir}/${testfile}
+if { [compile_java_from_source ${srcdir}/$subdir/${srcfile} ${binfile} "-g"] != "" } {
+ untested "Couldn't compile ${srcdir}/$subdir/${srcfile}"
+ return -1
+}
+
+set prms_id 0
+set bug_id 0
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set line [gdb_get_line_number "break here" $testfile.java]
+gdb_test "break $testfile.java:$line" ""
+
+gdb_test "run" \
+ "// break here.*" \
+ "run java next-over-throw"
+
+# See whether we have the needed unwinder hooks.
+set ok 1
+gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook in java" {
+ -re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
+ pass "check for unwinder hook in java"
+ }
+ -re "No symbol .* in current context.?\r\n$gdb_prompt $" {
+ # Pass the test so we don't get bogus fails in the results.
+ setup_xfail *-*-*
+ fail "check for unwinder hook in java"
+ set ok 0
+ }
+}
+if {!$ok} {
+ untested jnpe.exp
+ return -1
+}
+
+gdb_test "handle SIGSEGV nostop noprint" \
+ "SIGSEGV.*fault" \
+ "disable SIGSEGV for next-over-NPE"
+
+# The line where we stop differ according to gcj; check just we did not already
+# execute the catch point.
+
+gdb_test "next" \
+ "" \
+ "next over NPE"
+
+gdb_breakpoint [gdb_get_line_number "catch point"]
+gdb_continue_to_breakpoint "catch point" ".*// catch point.*"
diff --git a/gdb/testsuite/gdb.java/jnpe.java b/gdb/testsuite/gdb.java/jnpe.java
new file mode 100644
index 0000000..3524830
--- /dev/null
+++ b/gdb/testsuite/gdb.java/jnpe.java
@@ -0,0 +1,38 @@
+// Test next-over-NPE.
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>.
+ */
+
+public class jnpe
+{
+ public static String npe ()
+ {
+ return ((Object) null).toString();
+ }
+
+ public static void main (String[] args)
+ {
+ try
+ {
+ System.out.println (npe ()); // break here
+ }
+ catch (NullPointerException n)
+ {
+ System.out.println ("success"); // catch point
+ }
+ }
+}
diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c
new file mode 100644
index 0000000..729f457
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register-func.c
@@ -0,0 +1,22 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>. */
+
+int
+func (int *arr)
+{
+ return arr[0];
+}
diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c
new file mode 100644
index 0000000..3090e7e
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register.c
@@ -0,0 +1,28 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2009 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/>. */
+
+extern int func (int *arr);
+
+int
+main (void)
+{
+ int arr[] = { 42 };
+
+ func (arr);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp
new file mode 100644
index 0000000..f2de718
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/array-from-register.exp
@@ -0,0 +1,33 @@
+# Copyright 2009 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# This file is part of the gdb testsuite.
+
+if { [prepare_for_testing array-from-register.exp "array-from-register" \
+ {array-from-register.c array-from-register-func.c} \
+ {debug optimize=-O2}] } {
+ return -1
+}
+
+if ![runto func] then {
+ return -1
+}
+
+gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+"
+
+# Seen regression:
+# Address requested for identifier "arr" which is in register $rdi
+gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42"
diff --git a/gdb/testsuite/gdb.opt/fortran-string.exp b/gdb/testsuite/gdb.opt/fortran-string.exp
new file mode 100644
index 0000000..f997eec
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/fortran-string.exp
@@ -0,0 +1,41 @@
+# Copyright 2009 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+# Test GDB can cope with Fortran strings having their length present in a CPU
+# register. With -O0 the string length is passed on the stack. To make this
+# test meaningful the follow assertion should pass. It is not being checked
+# here as the "_s" symbol is compiler dependent:
+# (gdb) info address _s
+# Symbol "_s" is a variable in register XX.
+
+set test fortran-string
+set srcfile ${test}.f90
+if { [prepare_for_testing ${test}.exp ${test} ${srcfile} {debug f77 additional_flags=-O2}] } {
+ return -1
+}
+
+if ![runto MAIN__] then {
+ perror "couldn't run to breakpoint MAIN__"
+ continue
+}
+
+gdb_breakpoint [gdb_get_line_number "s = s"]
+gdb_continue_to_breakpoint "s = s"
+gdb_test "frame" ".*s='foo'.*"
+gdb_test "ptype s" "type = character\\*3"
+gdb_test "p s" "\\$\[0-9\]* = 'foo'"
diff --git a/gdb/testsuite/gdb.opt/fortran-string.f90 b/gdb/testsuite/gdb.opt/fortran-string.f90
new file mode 100644
index 0000000..e48d520
--- /dev/null
+++ b/gdb/testsuite/gdb.opt/fortran-string.f90
@@ -0,0 +1,28 @@
+! Copyright 2009 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 2 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, write to the Free Software
+! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+!
+! Ihis file is the Fortran source file for dynamic.exp.
+! Original file written by Jakub Jelinek <jakub@redhat.com>.
+! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+ subroutine f(s)
+ character*(*) s
+ s = s
+ end
+
+ program main
+ call f ('foo')
+ end
diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp
index 2a3ed0d..ff5de33 100644
--- a/gdb/testsuite/gdb.python/py-cmd.exp
+++ b/gdb/testsuite/gdb.python/py-cmd.exp
@@ -20,36 +20,15 @@ if $tracelevel then {
strace $tracelevel
}
-# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
-# Run a test named NAME, consisting of multiple lines of input.
-# After each input line INPUT, search for result line RESULT.
-# Succeed if all results are seen; fail otherwise.
-proc gdb_py_test_multiple {name args} {
- global gdb_prompt
- foreach {input result} $args {
- if {[gdb_test_multiple $input "$name - $input" {
- -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
- pass "$name - $input"
- }
- }]} {
- return 1
- }
- }
- return 0
-}
-
# Start with a fresh gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
-gdb_test_multiple "python print 'hello, world!'" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
}
# Test a simple command.
diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp
index 86fe660..4c7295f 100644
--- a/gdb/testsuite/gdb.python/py-frame.exp
+++ b/gdb/testsuite/gdb.python/py-frame.exp
@@ -20,40 +20,28 @@ if $tracelevel then {
strace $tracelevel
}
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
+}
+
set testfile "py-frame"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
+
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
untested "Couldn't compile ${srcfile}"
return -1
}
-# Run a command in GDB, and report a failure if a Python exception is thrown.
-# If report_pass is true, report a pass if no exception is thrown.
-proc gdb_py_test_silent_cmd {cmd name report_pass} {
- global gdb_prompt
-
- gdb_test_multiple $cmd $name {
- -re "Traceback.*$gdb_prompt $" { fail $name }
- -re "$gdb_prompt $" { if $report_pass { pass $name } }
- }
-}
-
-# Start with a fresh gdb.
-
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
-gdb_test_multiple "python print 'hello, world!'" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
-}
-
# The following tests require execution.
if ![runto_main] then {
@@ -65,19 +53,20 @@ gdb_breakpoint "f2"
gdb_continue_to_breakpoint "breakpoint at f2"
gdb_test "up" "" ""
-gdb_py_test_silent_cmd "python f1 = gdb.selected_frame ()" "get second frame" 0
-gdb_py_test_silent_cmd "python f0 = f1.newer ()" "get first frame" 0
+gdb_py_test_silent_cmd "python frames = gdb.selected_thread ().frames ()" "get frames list" 1
+gdb_test "python print frames" "\\(<gdb.Frame object at 0x\[\[:xdigit:\]\]+>, <gdb.Frame object at 0x\[\[:xdigit:\]\]+>, <gdb.Frame object at 0x\[\[:xdigit:\]\]+>\\)" "verify frames list"
+gdb_py_test_silent_cmd "python f0 = frames\[0\]" "get first frame" 0
+gdb_py_test_silent_cmd "python f1 = frames\[1\]" "get second frame" 0
gdb_test "python print 'result =', f0 == f1" " = False" "test equality comparison (false)"
gdb_test "python print 'result =', f0 == f0" " = True" "test equality comparison (true)"
-gdb_test "python print 'result =', f0 != f1" " = True" "test inequality comparison (true)"
-gdb_test "python print 'result =', f0 != f0" " = False" "test inequality comparison (false)"
gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid"
gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name"
gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type"
gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type"
gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string"
gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc"
+gdb_test "python print 'result =', f0.function ()" " = symbol for f2" "test Frame.function"
gdb_test "python print 'result =', f0.older () == f1" " = True" "test Frame.older"
gdb_test "python print 'result =', f1.newer () == f0" " = True" "test Frame.newer"
gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \
@@ -85,4 +74,7 @@ gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_ex
"test Frame.read_var - error"
gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success"
+gdb_test "python print 'result =', gdb.selected_thread ().newest_frame () == f0" " = True" "test gdb.newest_frame"
gdb_test "python print 'result =', gdb.selected_frame () == f1" " = True" "test gdb.selected_frame"
+
+gdb_test "python print 'result =', f0.block ()" "<gdb.Block object at 0x\[\[:xdigit:\]\]+>" "test Frame.block"
diff --git a/gdb/testsuite/gdb.python/py-function.exp b/gdb/testsuite/gdb.python/py-function.exp
index 461295d..ea33596 100644
--- a/gdb/testsuite/gdb.python/py-function.exp
+++ b/gdb/testsuite/gdb.python/py-function.exp
@@ -20,36 +20,15 @@ if $tracelevel then {
strace $tracelevel
}
-# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
-# Run a test named NAME, consisting of multiple lines of input.
-# After each input line INPUT, search for result line RESULT.
-# Succeed if all results are seen; fail otherwise.
-proc gdb_py_test_multiple {name args} {
- global gdb_prompt
- foreach {input result} $args {
- if {[gdb_test_multiple $input "$name - $input" {
- -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
- pass "$name - $input"
- }
- }]} {
- return 1
- }
- }
- return 0
-}
-
# Start with a fresh gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
-gdb_test_multiple "python print 'hello, world!'" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
}
gdb_py_test_multiple "input convenience function" \
diff --git a/gdb/testsuite/gdb.python/py-inferior.c b/gdb/testsuite/gdb.python/py-inferior.c
new file mode 100644
index 0000000..0b48299
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-inferior.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#define CHUNK_SIZE 16000 /* same as findcmd.c's */
+#define BUF_SIZE (2 * CHUNK_SIZE) /* at least two chunks */
+
+static int8_t int8_search_buf[100];
+static int16_t int16_search_buf[100];
+static int32_t int32_search_buf[100];
+static int64_t int64_search_buf[100];
+
+static char *search_buf;
+static int search_buf_size;
+
+static int x;
+
+
+int f2 (int a)
+{
+ char *str = "hello, testsuite";
+
+ puts (str); /* Break here. */
+
+ return ++a;
+}
+
+int f1 (int a, int b)
+{
+ return f2(a) + b;
+}
+
+static void
+init_bufs ()
+{
+ search_buf_size = BUF_SIZE;
+ search_buf = malloc (search_buf_size);
+ if (search_buf == NULL)
+ exit (1);
+ memset (search_buf, 'x', search_buf_size);
+}
+
+int main (int argc, char *argv[])
+{
+ init_bufs ();
+
+ return f1 (1, 2);
+}
diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp
new file mode 100644
index 0000000..719b178
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-inferior.exp
@@ -0,0 +1,201 @@
+# Copyright (C) 2009 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 the mechanism
+# exposing inferiors to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
+}
+
+set testfile "py-inferior"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_load ${binfile}
+
+# The following tests require execution.
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+runto [gdb_get_line_number "Break here."]
+
+# Test basic gdb.Inferior attributes and methods.
+
+gdb_py_test_silent_cmd "python inferiors = gdb.inferiors ()" "get inferiors list" 1
+gdb_test "python print inferiors" "\\(<gdb.Inferior object at 0x\[\[:xdigit:\]\]+>,\\)" "verify inferiors list"
+gdb_py_test_silent_cmd "python i0 = inferiors\[0\]" "get first inferior" 0
+
+gdb_test "python print 'result =', i0 == inferiors\[0\]" " = True" "test equality comparison (true)"
+gdb_test "python print 'result =', i0.num" " = \[0-9\]+" "test Inferior.num"
+gdb_test "python print 'result =', i0.pid" " = \[0-9\]+" "test Inferior.pid"
+gdb_test "python print 'result =', i0.was_attached" " = False" "test Inferior.was_attached"
+gdb_test "python print i0.threads ()" "\\(<gdb.InferiorThread object at 0x\[\[:xdigit:\]\]+>,\\)" "test Inferior.threads"
+
+# Test memory read and write operations.
+
+gdb_py_test_silent_cmd "python addr = gdb.selected_frame ().read_var ('str')" \
+ "read str address" 0
+gdb_py_test_silent_cmd "python str = gdb.inferiors()\[0\].read_memory (addr, 5)" \
+ "read str contents" 1
+gdb_py_test_silent_cmd "python str\[1\] = 'a'" "change str" 0
+gdb_py_test_silent_cmd "python gdb.inferiors()\[0\].write_memory (addr, str)" \
+ "write str" 1
+gdb_test "print str" " = 0x\[\[:xdigit:\]\]+ \"hallo, testsuite\"" \
+ "ensure str was changed in the inferior"
+
+# Test memory search.
+
+set hex_number {0x[0-9a-fA-F][0-9a-fA-F]*}
+set dec_number {[0-9]+}
+set history_prefix {[$][0-9]* = }
+set newline {[\r\n]+}
+set pattern_not_found "${newline}.]"
+set one_pattern_found "${newline}.${dec_number}L]"
+set two_patterns_found "${newline}.${dec_number}L, ${dec_number}L]"
+
+# Test string pattern.
+
+gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int8_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 'aaa')" \
+ "${two_patterns_found}" "find string pattern"
+
+# Test not finding pattern because search range too small, with
+# potential find at the edge of the range.
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3, 'aaaa')" \
+ "${pattern_not_found}" "pattern not found at end of range"
+
+# Increase the search range by 1 and we should find the pattern.
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3+1, \['a', 'a', 'a', 'a'\])" \
+ "${one_pattern_found}" "pattern found at end of range"
+
+# Test max-count with size, with different parameter position
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], 1, 1)" \
+ "${one_pattern_found}" "size = 1, max_count = 1"
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], 1, 2)" \
+ "${two_patterns_found}" "size = 1, max_count = 2, normal ordering"
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], size = 1, max_count = 2)" \
+ "${two_patterns_found}" "size = 1, max_count = 2, normal ordering, with keywords"
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], max_count = 2, size = 1)" \
+ "${two_patterns_found}" "size = 1, max_count = 2, inverted ordering"
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \['a', 'a'\], max_count = 2)" \
+ "${two_patterns_found}" "max_count = 2, with keyword"
+
+# Test 16-bit pattern.
+
+gdb_test "set int16_search_buf\[10\] = 0x1234" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int16_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int16_t) 0x1234')" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x1234, 2)" \
+ "${one_pattern_found}" "find 16-bit pattern, with python pattern"
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+ "${one_pattern_found}" "find 16-bit pattern, with value pattern"
+
+# Test 32-bit pattern.
+
+gdb_test "set int32_search_buf\[10\] = 0x12345678" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int32_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int32_t) 0x12345678')" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x12345678, 4)" \
+ "${one_pattern_found}" "find 32-bit pattern, with python pattern"
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+ "${one_pattern_found}" "find 32-bit pattern, with value pattern"
+
+# Test 64-bit pattern.
+
+gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('int64_search_buf')" "" ""
+gdb_test "py start_addr = search_buf.address" "" ""
+gdb_test "py length = search_buf.type.sizeof" "" ""
+gdb_test "py pattern = gdb.parse_and_eval ('(int64_t) 0xfedcba9876543210LL')" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0xfedcba9876543210, 8)" \
+ "${one_pattern_found}" "find 64-bit pattern, with python pattern"
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \
+ "${one_pattern_found}" "find 64-bit pattern, with value pattern"
+
+# Test mixed-sized patterns.
+
+gdb_test "set *(int8_t*) &search_buf\[10\] = 0x62" "" ""
+gdb_test "set *(int16_t*) &search_buf\[11\] = 0x6363" "" ""
+gdb_test "set *(int32_t*) &search_buf\[13\] = 0x64646464" "" ""
+gdb_test "py search_buf = gdb.selected_frame ().read_var ('search_buf')" "" ""
+gdb_test "py start_addr = search_buf\[0\].address" "" ""
+gdb_test "py pattern1 = gdb.parse_and_eval ('(int8_t) 0x62')" "" ""
+gdb_test "py pattern2 = gdb.parse_and_eval ('(int16_t) 0x6363')" "" ""
+gdb_test "py pattern3 = gdb.parse_and_eval ('(int32_t) 0x64646464')" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 100, \[pattern1, pattern2, pattern3\])" \
+ "${one_pattern_found}" "find mixed-sized pattern"
+
+# Test search spanning a large range, in the particular case of native
+# targets, test the search spanning multiple chunks.
+# Remote targets may implement the search differently.
+
+set CHUNK_SIZE 16000 ;
+
+gdb_test "set *(int32_t*) &search_buf\[0*${CHUNK_SIZE}+100\] = 0x12345678" "" ""
+gdb_test "set *(int32_t*) &search_buf\[1*${CHUNK_SIZE}+100\] = 0x12345678" "" ""
+gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" ""
+gdb_test "py length = gdb.selected_frame ().read_var ('search_buf_size')" "" ""
+
+gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x12345678, 4)" \
+ "${two_patterns_found}" "search spanning large range"
+
+# For native targets, test a pattern straddling a chunk boundary.
+
+if [isnative] {
+ gdb_test "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" "" ""
+
+ gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0xfdb97531, 4)" \
+ "${one_pattern_found}" "find pattern straddling chunk boundary"
+}
diff --git a/gdb/testsuite/gdb.python/py-infthread.c b/gdb/testsuite/gdb.python/py-infthread.c
new file mode 100644
index 0000000..22eb9f2
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-infthread.c
@@ -0,0 +1,14 @@
+int f2 (int a)
+{
+ return ++a;
+}
+
+int f1 (int a, int b)
+{
+ return f2(a) + b;
+}
+
+int main (int argc, char *argv[])
+{
+ return f1 (1, 2);
+}
diff --git a/gdb/testsuite/gdb.python/py-infthread.exp b/gdb/testsuite/gdb.python/py-infthread.exp
new file mode 100644
index 0000000..e9d18b7
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-infthread.exp
@@ -0,0 +1,58 @@
+# Copyright (C) 2009 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 the mechanism
+# exposing inferior threads to Python.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
+}
+
+set testfile "py-infthread"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_load ${binfile}
+
+# The following tests require execution.
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+runto [gdb_get_line_number "Break here."]
+
+# Test basic gdb.Inferior attributes and methods.
+
+gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1
+gdb_test "python print t0" "\\<gdb.InferiorThread object at 0x\[\[:xdigit:\]\]+>" "verify InferiorThread object"
+gdb_test "python print 'result =', t0.num" " = \[0-9\]+" "test Inferior.num"
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp
index 2626895..cd0d7e7 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.exp
+++ b/gdb/testsuite/gdb.python/py-prettyprint.exp
@@ -27,12 +27,20 @@ set binfile ${objdir}/${subdir}/${testfile}
# Start with a fresh gdb.
gdb_exit
gdb_start
-gdb_test_multiple "python print 'hello, world!'" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
}
# Run a command in GDB, and report a failure if a Python exception is thrown.
@@ -105,6 +113,8 @@ proc run_lang_tests {lang} {
gdb_test "print estring" "\"embedded x\\\\201\\\\202\\\\203\\\\204\""
gdb_test "print c" " = container \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}"
+ gdb_test "print nullstr" "RuntimeError: Error reading string from inferior.*"
+
gdb_test "continue" "Program exited normally\."
remote_file host delete ${remote_python_file}
diff --git a/gdb/testsuite/gdb.python/py-template.exp b/gdb/testsuite/gdb.python/py-template.exp
index 713ad5f..5d17b26 100644
--- a/gdb/testsuite/gdb.python/py-template.exp
+++ b/gdb/testsuite/gdb.python/py-template.exp
@@ -20,6 +20,17 @@ if $tracelevel then {
strace $tracelevel
}
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
+}
+
set testfile "py-template"
set srcfile ${testfile}.cc
set binfile ${objdir}/${subdir}/${testfile}
@@ -29,20 +40,6 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
return -1
}
-# Start with a fresh gdb.
-
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-
-gdb_test_multiple "python print 23" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
-}
-
proc test_template_arg {type} {
global testfile srcdir subdir srcfile binfile
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp
index aa4e519..f87277d 100644
--- a/gdb/testsuite/gdb.python/py-value.exp
+++ b/gdb/testsuite/gdb.python/py-value.exp
@@ -305,6 +305,15 @@ proc test_value_after_death {} {
"print value's type"
}
+# Regression test for a cast failure. The bug was that if we cast a
+# value to its own type, gdb could crash. This happened because we
+# could end up double-freeing a struct value.
+proc test_cast_regression {} {
+ gdb_test "python v = gdb.Value(5)" "" "create value for cast test"
+ gdb_test "python v = v.cast(v.type)" "" "cast value for cast test"
+ gdb_test "python print v" "5" "print value for cast test"
+}
+
# Regression test for invalid subscript operations. The bug was that
# the type of the value was not being checked before allowing a
# subscript operation to proceed.
@@ -390,16 +399,23 @@ proc test_parse_and_eval {} {
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
-gdb_load ${binfile}
-gdb_test_multiple "python print 'hello, world!'" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
}
+set testfile "py-value"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_load ${binfile}
+
test_value_creation
test_value_numeric_ops
test_value_boolean
@@ -417,6 +433,7 @@ if ![runto_main] then {
test_value_in_inferior
test_lazy_strings
test_value_after_death
+test_cast_regression
# The following test recompiles the binary to test either C or C++
# values.
diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp
index 951c295..9dd0c12 100644
--- a/gdb/testsuite/gdb.python/python.exp
+++ b/gdb/testsuite/gdb.python/python.exp
@@ -26,30 +26,9 @@ gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
-gdb_test_multiple "python print 23" "verify python support" {
- -re "not supported.*$gdb_prompt $" {
- unsupported "python support is disabled"
- return -1
- }
- -re "$gdb_prompt $" {}
-}
-
-# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
-# Run a test named NAME, consisting of multiple lines of input.
-# After each input line INPUT, search for result line RESULT.
-# Succeed if all results are seen; fail otherwise.
-proc gdb_py_test_multiple {name args} {
- global gdb_prompt
- foreach {input result} $args {
- if {[gdb_test_multiple $input "$name - $input" {
- -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
- pass "$name - $input"
- }
- }]} {
- return 1
- }
- }
- return 0
+if ![python_supported] then {
+ unsupported "python support is disabled"
+ return -1
}
gdb_py_test_multiple "multi-line python command" \
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c b/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c
new file mode 100644
index 0000000..4dc308b
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c
@@ -0,0 +1,175 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <errno.h>
+
+static void
+delay (void)
+{
+ int i = usleep (1000000 / 100);
+ assert (i == 0 || errno == EINTR);
+}
+
+#if defined FOLLOW_PARENT
+
+static void
+forkoff (int nr)
+{
+ pid_t child, pid_got;
+ int exit_code = 42 + nr;
+ int status, i;
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ assert (0);
+ case 0:
+ printf ("child%d: %d\n", nr, (int) getpid ());
+ /* Delay to get both the "child%d" and "parent%d" message printed without
+ a race breaking expect by its endless wait on `$gdb_prompt$':
+ Breakpoint 3, breakpoint () at ../../../gdb/testsuite/gdb.threads/watchpoint-fork.c:33
+ 33 }
+ (gdb) parent2: 14223 */
+ i = sleep (1);
+ assert (i == 0);
+
+ /* We must not get caught here (against a forgotten breakpoint). */
+ var++;
+ breakpoint ();
+
+ _exit (exit_code);
+ default:
+ printf ("parent%d: %d\n", nr, (int) child);
+ /* Delay to get both the "child%d" and "parent%d" message printed, see
+ above. */
+ i = sleep (1);
+ assert (i == 0);
+
+ pid_got = wait (&status);
+ assert (pid_got == child);
+ assert (WIFEXITED (status));
+ assert (WEXITSTATUS (status) == exit_code);
+
+ /* We must get caught here (against a false watchpoint removal). */
+ breakpoint ();
+ }
+}
+
+#elif defined FOLLOW_CHILD
+
+static volatile int usr1_got;
+
+static void
+handler_usr1 (int signo)
+{
+ usr1_got++;
+}
+
+static void
+forkoff (int nr)
+{
+ pid_t child;
+ int i, loop;
+ struct sigaction act, oldact;
+#ifdef THREAD
+ void *thread_result;
+#endif
+
+ memset (&act, 0, sizeof act);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = handler_usr1;
+ sigemptyset (&act.sa_mask);
+ i = sigaction (SIGUSR1, &act, &oldact);
+ assert (i == 0);
+
+ child = fork ();
+ switch (child)
+ {
+ case -1:
+ assert (0);
+ default:
+ printf ("parent%d: %d\n", nr, (int) child);
+
+ /* Sleep for a while to possibly get incorrectly ATTACH_THREADed by GDB
+ tracing the child fork with no longer valid thread/lwp entries of the
+ parent. */
+
+ i = sleep (2);
+ assert (i == 0);
+
+ /* We must not get caught here (against a forgotten breakpoint). */
+
+ var++;
+ breakpoint ();
+
+#ifdef THREAD
+ /* And neither got caught our thread. */
+
+ step = 99;
+ i = pthread_join (thread, &thread_result);
+ assert (i == 0);
+ assert (thread_result == (void *) 99UL);
+#endif
+
+ /* Be sure our child knows we did not get caught above. */
+
+ i = kill (child, SIGUSR1);
+ assert (i == 0);
+
+ /* Sleep for a while to check GDB's `info threads' no longer tracks us in
+ the child fork. */
+
+ i = sleep (2);
+ assert (i == 0);
+
+ _exit (0);
+ case 0:
+ printf ("child%d: %d\n", nr, (int) getpid ());
+
+ /* Let the parent signal us about its success. Be careful of races. */
+
+ for (loop = 0; loop < 1000; loop++)
+ {
+ /* Parent either died (and USR1_GOT is zero) or it succeeded. */
+ if (kill (getppid (), 0) != 0)
+ break;
+ /* Parent succeeded? */
+ if (usr1_got)
+ break;
+
+ delay ();
+ }
+ assert (usr1_got);
+
+ /* We must get caught here (against a false watchpoint removal). */
+
+ breakpoint ();
+ }
+
+ i = sigaction (SIGUSR1, &oldact, NULL);
+ assert (i == 0);
+}
+
+#else
+# error "!FOLLOW_PARENT && !FOLLOW_CHILD"
+#endif
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c
new file mode 100644
index 0000000..edacfc0
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c
@@ -0,0 +1,157 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <asm/unistd.h>
+#include <unistd.h>
+#define gettid() syscall (__NR_gettid)
+
+/* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP
+ variable. Hit-comments need to be duplicite there to catch both at-stops
+ and behind-stops, depending on the target. */
+
+static volatile int var;
+
+static void
+dummy (void)
+{
+}
+
+static void
+breakpoint (void)
+{
+}
+
+/* Include here the functions:
+ static void forkoff (int nr);
+ static void delay (void); */
+
+static pthread_t thread;
+static volatile int step;
+#define THREAD
+
+#include "watchpoint-fork-forkoff.c"
+
+static void *
+start (void *arg)
+{
+ if (step >= 3)
+ goto step_3;
+
+ while (step != 1)
+ delay ();
+
+ var++; /* validity-thread-B */
+ dummy (); /* validity-thread-B */
+ step = 2;
+ while (step != 3)
+ {
+ if (step == 99)
+ goto step_99;
+ delay ();
+ }
+
+step_3:
+ if (step >= 5)
+ goto step_5;
+
+ var++; /* after-fork1-B */
+ dummy (); /* after-fork1-B */
+ step = 4;
+ while (step != 5)
+ {
+ if (step == 99)
+ goto step_99;
+ delay ();
+ }
+
+step_5:
+ var++; /* after-fork2-B */
+ dummy (); /* after-fork2-B */
+ return (void *) 5UL;
+
+step_99:
+ /* We must not get caught here (against a forgotten breakpoint). */
+ var++;
+ breakpoint ();
+ return (void *) 99UL;
+}
+
+int
+main (void)
+{
+ int i;
+ void *thread_result;
+
+ setbuf (stdout, NULL);
+ printf ("main: %d\n", (int) gettid ());
+
+ /* General watchpoints validity. */
+ var++; /* validity-first */
+ dummy (); /* validity-first */
+
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+
+ var++; /* validity-thread-A */
+ dummy (); /* validity-thread-A */
+ step = 1;
+ while (step != 2)
+ delay ();
+
+ /* Hardware watchpoints got disarmed here. */
+ forkoff (1);
+
+ var++; /* after-fork1-A */
+ dummy (); /* after-fork1-A */
+ step = 3;
+#ifdef FOLLOW_CHILD
+ /* Spawn new thread as it was deleted in the child of FORK. */
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+#endif
+ while (step != 4)
+ delay ();
+
+ /* A sanity check for double hardware watchpoints removal. */
+ forkoff (2);
+
+ var++; /* after-fork2-A */
+ dummy (); /* after-fork2-A */
+ step = 5;
+#ifdef FOLLOW_CHILD
+ /* Spawn new thread as it was deleted in the child of FORK. */
+ i = pthread_create (&thread, NULL, start, NULL);
+ assert (i == 0);
+#endif
+
+ i = pthread_join (thread, &thread_result);
+ assert (i == 0);
+ assert (thread_result == (void *) 5UL);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.c b/gdb/testsuite/gdb.threads/watchpoint-fork.c
new file mode 100644
index 0000000..5f62e7f
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork.c
@@ -0,0 +1,57 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+ Copyright 2008, 2009 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static volatile int var;
+
+static void
+breakpoint (void)
+{
+}
+
+/* Include here the function:
+ static void forkoff (int nr); */
+
+#include "watchpoint-fork-forkoff.c"
+
+int
+main (void)
+{
+ setbuf (stdout, NULL);
+ printf ("main: %d\n", (int) getpid ());
+
+ /* General watchpoints validity. */
+ var++;
+ /* Hardware watchpoints got disarmed here. */
+ forkoff (1);
+ /* This watchpoint got lost before. */
+ var++;
+ /* A sanity check for double hardware watchpoints removal. */
+ forkoff (2);
+ var++;
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.exp b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
new file mode 100644
index 0000000..1dc93ab
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
@@ -0,0 +1,130 @@
+# Copyright 2008, 2009 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/>.
+
+# Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+proc test {type symbol} {
+ global objdir subdir srcdir
+
+ set test watchpoint-fork
+
+ global pf_prefix
+ set prefix_test $pf_prefix
+ lappend pf_prefix "$type:"
+ set prefix_mt $pf_prefix
+
+ # no threads
+
+ set pf_prefix $prefix_mt
+ lappend pf_prefix "singlethreaded:"
+
+ set executable ${test}-${type}
+ if { [gdb_compile ${srcdir}/${subdir}/${test}.c ${objdir}/${subdir}/${executable} executable [list debug additional_flags=-D$symbol]] != "" } {
+ untested ${test}.exp
+ return -1
+ }
+ clean_restart $executable
+
+ gdb_test "show detach-on-fork" "Whether gdb will detach the child of a fork is on."
+ gdb_test "set follow-fork-mode $type"
+ gdb_test "show follow-fork-mode" "Debugger response to a program call of fork or vfork is \"$type\"."
+ # Testcase uses it for the `follow-fork-mode child' type.
+ gdb_test "handle SIGUSR1 nostop noprint pass"
+
+ if { ![runto_main] } then {
+ gdb_suppress_tests
+ return
+ }
+
+ # Install the watchpoint only after getting into MAIN - workaround some PPC
+ # problem.
+ gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint"
+
+ # It is never hit but it should not be left over in the fork()ed-off child.
+ gdb_breakpoint "breakpoint"
+
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work"
+ gdb_test "continue" \
+ "reakpoint 3, breakpoint.*" "breakpoint after the first fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork"
+ gdb_test "continue" \
+ "reakpoint 3, breakpoint.*" "breakpoint after the second fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 2.*New value = 3.*return *0;" "watchpoint after the second fork"
+ gdb_test "continue" "Continuing..*Program exited normally." "finish"
+
+
+ # threads
+
+ set pf_prefix $prefix_mt
+ lappend pf_prefix "multithreaded:"
+
+ set executable ${test}-mt-${type}
+ if { [gdb_compile_pthreads ${srcdir}/${subdir}/${test}-mt.c ${objdir}/${subdir}/${executable} executable [list debug additional_flags=-D$symbol]] != "" } {
+ untested ${test}.exp
+ return -1
+ }
+ clean_restart $executable
+
+ gdb_test "set follow-fork-mode $type"
+ # Testcase uses it for the `follow-fork-mode child' type.
+ gdb_test "handle SIGUSR1 nostop noprint pass"
+
+ if { ![runto_main] } then {
+ gdb_suppress_tests
+ return
+ }
+
+ # Install the watchpoint only after getting into MAIN - workaround some PPC
+ # problem.
+ gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint"
+
+ # It is never hit but it should not be left over in the fork()ed-off child.
+ gdb_breakpoint "breakpoint"
+
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B"
+ gdb_test "continue" \
+ "reakpoint 3, breakpoint.*" "breakpoint (A) after the first fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork"
+ gdb_test "continue" \
+ "reakpoint 3, breakpoint.*" "breakpoint (A) after the second fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork"
+ gdb_test "continue" \
+ "atchpoint 2: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork"
+ gdb_test "continue" "Continuing..*Program exited normally." "finish"
+
+
+ # cleanup
+
+ set pf_prefix $prefix_test
+}
+
+test parent FOLLOW_PARENT
+
+# Only GNU/Linux is known to support `set follow-fork-mode child'.
+if {[istarget "*-*-linux*"]} {
+ test child FOLLOW_CHILD
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 9b06a2f..419d5a9 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -27,6 +27,7 @@ if {$tool == ""} {
}
load_lib libgloss.exp
+load_lib python-support.exp
global GDB
diff --git a/gdb/testsuite/lib/python-support.exp b/gdb/testsuite/lib/python-support.exp
new file mode 100644
index 0000000..b8e9836
--- /dev/null
+++ b/gdb/testsuite/lib/python-support.exp
@@ -0,0 +1,53 @@
+global python_supported_saved
+
+# Return 1 if Python scripting is supported in GDB, 0 if not.
+proc python_supported { } {
+ global gdb_prompt
+ global python_supported_saved
+
+ if [info exists python_supported_saved] {
+ verbose "python_supported: returning saved $python_supported_saved" 2
+ return $python_supported_saved
+ }
+
+ gdb_test_multiple "python print 'hello, world!'" "verify python support" {
+ -re "not supported.*$gdb_prompt $" {
+ return [set python_supported_saved 0]
+ }
+ -re "$gdb_prompt $" {
+ return [set python_supported_saved 1]
+ }
+ }
+
+ return [set python_supported_saved 0]
+}
+
+# Run a command in GDB, and report a failure if a Python exception is thrown.
+# If report_pass is true, report a pass if no exception is thrown.
+proc gdb_py_test_silent_cmd {cmd name report_pass} {
+ global gdb_prompt
+
+ gdb_test_multiple $cmd $name {
+ -re "Traceback.*$gdb_prompt $" { fail $name }
+ -re "$gdb_prompt $" { if $report_pass { pass $name } }
+ }
+}
+
+# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+proc gdb_py_test_multiple {name args} {
+ global gdb_prompt
+
+ foreach {input result} $args {
+ if {[gdb_test_multiple $input "$name - $input" {
+ -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+ pass "$name - $input"
+ }
+ }]} {
+ return 1
+ }
+ }
+ return 0
+}
diff --git a/gdb/thread.c b/gdb/thread.c
index 16a207c..c3cff06 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -61,7 +61,6 @@ static int thread_alive (struct thread_info *);
static void info_threads_command (char *, int);
static void thread_apply_command (char *, int);
static void restore_current_thread (ptid_t);
-static void prune_threads (void);
/* Frontend view of the thread state. Possible extensions: stepping,
finishing, until(ling),... */
@@ -517,7 +516,7 @@ thread_alive (struct thread_info *tp)
return 1;
}
-static void
+void
prune_threads (void)
{
struct thread_info *tp, *next;
diff --git a/gdb/top.c b/gdb/top.c
index 85e7b62..b4f0bf7 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -346,6 +346,7 @@ void
prepare_execute_command (void)
{
free_all_values ();
+ free_all_types ();
/* With multiple threads running while the one we're examining is stopped,
the dcache can get stale without us being able to detect it.
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index ce9f551..5f9d739 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -36,6 +36,7 @@
#include "gdb_string.h"
#include "exceptions.h"
#include "valprint.h"
+#include "dwarf2loc.h"
#include <errno.h>
extern void _initialize_typeprint (void);
@@ -77,6 +78,9 @@ void
type_print (struct type *type, char *varstring, struct ui_file *stream,
int show)
{
+ if (show >= 0)
+ type = check_typedef (type);
+
LA_PRINT_TYPE (type, varstring, stream, show, 0);
}
@@ -115,7 +119,8 @@ whatis_exp (char *exp, int show)
{
struct expression *expr;
struct value *val;
- struct cleanup *old_chain = NULL;
+ /* Required at least for the object_address_set call. */
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
struct type *real_type = NULL;
struct type *type;
int full = 0;
@@ -126,12 +131,13 @@ whatis_exp (char *exp, int show)
if (exp)
{
expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
+ make_cleanup (free_current_contents, &expr);
val = evaluate_type (expr);
}
else
val = access_value_history (0);
+ object_address_set (value_raw_address (val));
type = value_type (val);
get_user_print_options (&opts);
@@ -168,8 +174,7 @@ whatis_exp (char *exp, int show)
type_print (type, "", gdb_stdout, show);
printf_filtered ("\n");
- if (exp)
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
}
static void
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 2b66f85..9c36e56 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -139,7 +139,6 @@ an integer nor a pointer of the same type."));
struct value *
value_subscript (struct value *array, LONGEST index)
{
- struct value *bound;
int c_style = current_language->c_style_arrays;
struct type *tarray;
@@ -154,12 +153,26 @@ value_subscript (struct value *array, LONGEST index)
get_discrete_bounds (range_type, &lowerbound, &upperbound);
if (VALUE_LVAL (array) != lval_memory)
- return value_subscripted_rvalue (array, index, lowerbound);
+ {
+ if (index >= lowerbound && index <= upperbound)
+ {
+ CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray));
+ CORE_ADDR offset = (index - lowerbound) * element_size;
+
+ return value_subscripted_rvalue (array, offset);
+ }
+ error (_("array or string index out of range"));
+ }
if (c_style == 0)
{
if (index >= lowerbound && index <= upperbound)
- return value_subscripted_rvalue (array, index, lowerbound);
+ {
+ CORE_ADDR element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tarray));
+ CORE_ADDR offset = (index - lowerbound) * element_size;
+
+ return value_subscripted_rvalue (array, offset);
+ }
/* Emit warning unless we have an array of unknown size.
An array of unknown size has lowerbound 0 and upperbound -1. */
if (upperbound > -1)
@@ -178,33 +191,37 @@ value_subscript (struct value *array, LONGEST index)
error (_("not an array or string"));
}
-/* Return the value of EXPR[IDX], expr an aggregate rvalue
- (eg, a vector register). This routine used to promote floats
- to doubles, but no longer does. */
+/* Return the value of *((void *) ARRAY + ELEMENT), ARRAY an aggregate rvalue
+ (eg, a vector register). This routine used to promote floats to doubles,
+ but no longer does. OFFSET is zero-based with 0 for the lowermost existing
+ element, it must be expressed in bytes (therefore multiplied by
+ check_typedef (TYPE_TARGET_TYPE (array_type)). */
struct value *
-value_subscripted_rvalue (struct value *array, LONGEST index, int lowerbound)
+value_subscripted_rvalue (struct value *array, CORE_ADDR offset)
{
struct type *array_type = check_typedef (value_type (array));
struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type));
- unsigned int elt_size = TYPE_LENGTH (elt_type);
- unsigned int elt_offs = elt_size * longest_to_int (index - lowerbound);
struct value *v;
- if (index < lowerbound || elt_offs >= TYPE_LENGTH (array_type))
- error (_("no such vector element"));
+ /* Do not check TYPE_LENGTH (array_type) as we may have been given the
+ innermost dimension of a multi-dimensional Fortran array where its length
+ is shorter than the possibly accessed element offset. */
v = allocate_value (elt_type);
if (VALUE_LVAL (array) == lval_memory && value_lazy (array))
set_value_lazy (v, 1);
else
- memcpy (value_contents_writeable (v),
- value_contents (array) + elt_offs, elt_size);
+ {
+ unsigned int elt_size = TYPE_LENGTH (elt_type);
+ memcpy (value_contents_writeable (v),
+ value_contents (array) + offset, elt_size);
+ }
set_value_component_location (v, array);
VALUE_REGNUM (v) = VALUE_REGNUM (array);
VALUE_FRAME_ID (v) = VALUE_FRAME_ID (array);
- set_value_offset (v, value_offset (array) + elt_offs);
+ set_value_offset (v, value_offset (array) + offset);
return v;
}
diff --git a/gdb/valops.c b/gdb/valops.c
index 1667368..e1a6bef 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -38,6 +38,7 @@
#include "cp-support.h"
#include "dfp.h"
#include "user-regs.h"
+#include "dwarf2loc.h"
#include <errno.h>
#include "gdb_string.h"
@@ -374,8 +375,6 @@ value_cast (struct type *type, struct value *arg2)
new_length = val_length / element_length;
if (val_length % element_length != 0)
warning (_("array element type size does not divide object size in cast"));
- /* FIXME-type-allocation: need a way to free this type when
- we are done with it. */
range_type = create_range_type ((struct type *) NULL,
TYPE_TARGET_TYPE (range_type),
low_bound,
@@ -570,6 +569,64 @@ value_one (struct type *type, enum lval_type lv)
return val;
}
+/* object_address_set must be already called before this function. */
+
+const char *
+object_address_data_not_valid (struct type *type)
+{
+ /* Attributes are present only at the target type of a typedef. Make the
+ call conditional as it would otherwise loop through type_length_get. */
+ if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+ CHECK_TYPEDEF (type);
+
+ /* DW_AT_associated has a preference over DW_AT_allocated. */
+ if (TYPE_NOT_ASSOCIATED (type)
+ || (TYPE_ASSOCIATED (type) != NULL
+ && 0 == dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (type))))
+ return N_("object is not associated");
+
+ if (TYPE_NOT_ALLOCATED (type)
+ || (TYPE_ALLOCATED (type) != NULL
+ && 0 == dwarf_locexpr_baton_eval (TYPE_ALLOCATED (type))))
+ return N_("object is not allocated");
+
+ return NULL;
+}
+
+/* Return non-zero if the variable is valid. If it is valid the function
+ may store the data address (DW_AT_DATA_LOCATION) of TYPE at *ADDRESS_RETURN.
+ You must set *ADDRESS_RETURN from value_raw_address (VAL) before calling this
+ function. If no DW_AT_DATA_LOCATION is present for TYPE the address at
+ *ADDRESS_RETURN is left unchanged. ADDRESS_RETURN must not be NULL, use
+ object_address_data_not_valid () for just the data validity check. */
+
+int
+object_address_get_data (struct type *type, CORE_ADDR *address_return)
+{
+ gdb_assert (address_return != NULL);
+
+ object_address_set (*address_return);
+
+ /* TYPE_DATA_LOCATION_DWARF_BLOCK / TYPE_DATA_LOCATION_ADDR are present only
+ at the target type of a typedef. */
+ CHECK_TYPEDEF (type);
+
+ if (object_address_data_not_valid (type) != NULL)
+ {
+ /* Do not try to evaluate DW_AT_data_location as it may even crash
+ (it would just return the value zero in the gfortran case). */
+ return 0;
+ }
+
+ if (TYPE_DATA_LOCATION_IS_ADDR (type))
+ *address_return = TYPE_DATA_LOCATION_ADDR (type);
+ else if (TYPE_DATA_LOCATION_DWARF_BLOCK (type) != NULL)
+ *address_return
+ = dwarf_locexpr_baton_eval (TYPE_DATA_LOCATION_DWARF_BLOCK (type));
+
+ return 1;
+}
+
/* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */
static struct value *
@@ -661,15 +718,21 @@ value_fetch_lazy (struct value *val)
}
else if (VALUE_LVAL (val) == lval_memory)
{
- CORE_ADDR addr = value_address (val);
- int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val)));
+ CORE_ADDR addr = value_raw_address (val);
- if (length)
+ if (object_address_get_data (value_type (val), &addr))
{
- if (value_stack (val))
- read_stack (addr, value_contents_all_raw (val), length);
- else
- read_memory (addr, value_contents_all_raw (val), length);
+ struct type *type = value_enclosing_type (val);
+ int length = TYPE_LENGTH (check_typedef (type));
+
+ if (length)
+ {
+ addr += value_offset (val);
+ if (value_stack (val))
+ read_stack (addr, value_contents_all_raw (val), length);
+ else
+ read_memory (addr, value_contents_all_raw (val), length);
+ }
}
}
else if (VALUE_LVAL (val) == lval_register)
@@ -1077,7 +1140,18 @@ address_of_variable (struct symbol *var, struct block *b)
if ((VALUE_LVAL (val) == lval_memory && value_lazy (val))
|| TYPE_CODE (type) == TYPE_CODE_FUNC)
{
- CORE_ADDR addr = value_address (val);
+ CORE_ADDR addr;
+
+ if (VALUE_LVAL (val) == lval_memory)
+ {
+ addr = value_raw_address (val);
+ if (!object_address_get_data (type, &addr))
+ error (_("Can't take address of memory lvalue \"%s\"."),
+ SYMBOL_PRINT_NAME (var));
+ set_value_address (val, addr);
+ }
+
+ addr = value_address (val);
return value_from_pointer (lookup_pointer_type (type), addr);
}
@@ -1183,6 +1257,7 @@ struct value *
value_coerce_array (struct value *arg1)
{
struct type *type = check_typedef (value_type (arg1));
+ CORE_ADDR address;
/* If the user tries to do something requiring a pointer with an
array that has not yet been pushed to the target, then this would
@@ -1192,8 +1267,12 @@ value_coerce_array (struct value *arg1)
if (VALUE_LVAL (arg1) != lval_memory)
error (_("Attempt to take address of value not located in memory."));
+ address = value_raw_address (arg1);
+ if (!object_address_get_data (type, &address))
+ error (_("Attempt to take address of non-valid value."));
+
return value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)),
- value_address (arg1));
+ address + value_offset (arg1));
}
/* Given a value which is a function, return a value which is a pointer
@@ -3042,8 +3121,6 @@ value_slice (struct value *array, int lowbound, int length)
|| lowbound + length - 1 > upperbound)
error (_("slice out of range"));
- /* FIXME-type-allocation: need a way to free this type when we are
- done with it. */
slice_range_type = create_range_type ((struct type *) NULL,
TYPE_TARGET_TYPE (range_type),
lowbound,
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 3f21ae4..9b15b1a 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -236,7 +236,6 @@ scalar_type_p (struct type *type)
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_SET:
- case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
return 0;
default:
@@ -1154,6 +1153,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr,
for (; i < len && things_printed < options->print_max; i++)
{
+ size_t elt_offset = i * eltlen;
if (i != 0)
{
if (options->prettyprint_arrays)
@@ -1173,7 +1173,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr,
rep1 = i + 1;
reps = 1;
while ((rep1 < len) &&
- !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen))
+ !memcmp (valaddr + elt_offset, valaddr + rep1 * eltlen, eltlen))
{
++reps;
++rep1;
diff --git a/gdb/value.c b/gdb/value.c
index a462ee4..968cdf4 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -37,8 +37,10 @@
#include "block.h"
#include "dfp.h"
#include "objfiles.h"
+#include "cli/cli-decode.h"
#include "valprint.h"
#include "cli/cli-decode.h"
+#include "observer.h"
#include "python/python.h"
@@ -170,6 +172,14 @@ struct value
taken off this list. */
struct value *next;
+ /* The reference count. A value that is still on the `all_values'
+ list will have a reference count of 0. A call to `release_value'
+ will increment the reference count (and remove the value from the
+ list, the first time). A call to `value_free' will decrement the
+ reference count, and will free the value when there are no more
+ references. */
+ int refcount;
+
/* Register number if the value is from a register. */
short regnum;
@@ -631,6 +641,13 @@ value_free (struct value *val)
if (val->parent != NULL)
value_free (val->parent);
+#if 0
+ /* We need type GC instead. This can fail when an objfile is
+ reclaimed and then a value is later freed. */
+ type_decref (val->type);
+ type_decref (val->enclosing_type);
+#endif
+
if (VALUE_LVAL (val) == lval_computed)
{
struct lval_funcs *funcs = val->location.computed.funcs;
@@ -735,6 +752,7 @@ value_copy (struct value *arg)
val = allocate_value_lazy (encl_type);
else
val = allocate_value (encl_type);
+
val->type = arg->type;
VALUE_LVAL (val) = VALUE_LVAL (arg);
val->location = arg->location;
@@ -770,12 +788,15 @@ value_copy (struct value *arg)
void
set_value_component_location (struct value *component, struct value *whole)
{
+ CORE_ADDR addr;
+
if (VALUE_LVAL (whole) == lval_internalvar)
VALUE_LVAL (component) = lval_internalvar_component;
else
VALUE_LVAL (component) = VALUE_LVAL (whole);
component->location = whole->location;
+
if (VALUE_LVAL (whole) == lval_computed)
{
struct lval_funcs *funcs = whole->location.computed.funcs;
@@ -783,6 +804,12 @@ set_value_component_location (struct value *component, struct value *whole)
if (funcs->copy_closure)
component->location.computed.closure = funcs->copy_closure (whole);
}
+
+ addr = value_raw_address (component);
+ object_address_get_data (value_type (whole), &addr);
+ if (component->lval != lval_internalvar
+ && component->lval != lval_internalvar_component)
+ set_value_address (component, addr);
}
@@ -913,6 +940,29 @@ show_values (char *num_exp, int from_tty)
num_exp[1] = '\0';
}
}
+
+/* Sanity check for memory leaks and proper types reference counting. */
+
+static void
+value_history_cleanup (void *unused)
+{
+ while (value_history_chain)
+ {
+ struct value_history_chunk *chunk = value_history_chain;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (chunk->values); i++)
+ value_free (chunk->values[i]);
+
+ value_history_chain = chunk->next;
+ xfree (chunk);
+ }
+ value_history_count = 0;
+
+ /* Free the unreferenced types above. */
+ free_all_values ();
+ free_all_types ();
+}
/* Internal variables. These are variables within the debugger
that hold values assigned by debugger commands.
@@ -1388,6 +1438,40 @@ call_internal_function (struct gdbarch *gdbarch,
return (*ifn->handler) (gdbarch, language, ifn->cookie, argc, argv);
}
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+value_types_mark_used (void)
+{
+ struct internalvar *var;
+ struct value_history_chunk *chunk;
+
+ for (var = internalvars; var != NULL; var = var->next)
+ switch (var->kind)
+ {
+ case INTERNALVAR_VALUE:
+ type_mark_used (value_type (var->u.value));
+ break;
+
+ case INTERNALVAR_INTEGER:
+ type_mark_used (var->u.integer.type);
+ break;
+
+ case INTERNALVAR_POINTER:
+ type_mark_used (var->u.pointer.type);
+ break;
+ }
+
+ for (chunk = value_history_chain; chunk != NULL; chunk = chunk->next)
+ {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (chunk->values); i++)
+ if (chunk->values[i])
+ type_mark_used (value_type (chunk->values[i]));
+ }
+}
+
/* The 'function' command. This does nothing -- it is just a
placeholder to let "help function NAME" work. This is also used as
the implementation of the sub-command that is created when
@@ -1435,11 +1519,10 @@ preserve_one_value (struct value *value, struct objfile *objfile,
htab_t copied_types)
{
if (TYPE_OBJFILE (value->type) == objfile)
- value->type = copy_type_recursive (objfile, value->type, copied_types);
+ value->type = copy_type_recursive (value->type, copied_types);
if (TYPE_OBJFILE (value->enclosing_type) == objfile)
- value->enclosing_type = copy_type_recursive (objfile,
- value->enclosing_type,
+ value->enclosing_type = copy_type_recursive (value->enclosing_type,
copied_types);
}
@@ -1454,13 +1537,13 @@ preserve_one_internalvar (struct internalvar *var, struct objfile *objfile,
case INTERNALVAR_INTEGER:
if (var->u.integer.type && TYPE_OBJFILE (var->u.integer.type) == objfile)
var->u.integer.type
- = copy_type_recursive (objfile, var->u.integer.type, copied_types);
+ = copy_type_recursive (var->u.integer.type, copied_types);
break;
case INTERNALVAR_POINTER:
if (TYPE_OBJFILE (var->u.pointer.type) == objfile)
var->u.pointer.type
- = copy_type_recursive (objfile, var->u.pointer.type, copied_types);
+ = copy_type_recursive (var->u.pointer.type, copied_types);
break;
case INTERNALVAR_VALUE:
@@ -2192,6 +2275,42 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
}
+/* Pack NUM into BUF using a target format of TYPE. */
+
+void
+pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+ int len;
+
+ type = check_typedef (type);
+ len = TYPE_LENGTH (type);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLAGS:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_MEMBERPTR:
+ store_unsigned_integer (buf, len, byte_order, num);
+ break;
+
+ case TYPE_CODE_REF:
+ case TYPE_CODE_PTR:
+ store_typed_address (buf, type, (CORE_ADDR) num);
+ break;
+
+ default:
+ error (_("\
+Unexpected type (%d) encountered for unsigned integer constant."),
+ TYPE_CODE (type));
+ }
+}
+
+
/* Convert C numbers into newly allocated values. */
struct value *
@@ -2205,6 +2324,19 @@ value_from_longest (struct type *type, LONGEST num)
}
+/* Convert C unsigned numbers into newly allocated values. */
+
+struct value *
+value_from_ulongest (struct type *type, ULONGEST num)
+{
+ struct value *val = allocate_value (type);
+
+ pack_unsigned_long (value_contents_raw (val), type, num);
+
+ return val;
+}
+
+
/* Create a value representing a pointer of type TYPE to the address
ADDR. */
struct value *
@@ -2363,4 +2495,8 @@ VARIABLE is already initialized."));
add_prefix_cmd ("function", no_class, function_command, _("\
Placeholder command for showing help on convenience functions."),
&functionlist, "function ", 0, &cmdlist);
+
+ make_final_cleanup (value_history_cleanup, NULL);
+
+ observer_attach_mark_used (value_types_mark_used);
}
diff --git a/gdb/value.h b/gdb/value.h
index 8ac62b8..051c8c5 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -342,11 +342,16 @@ extern LONGEST unpack_field_as_long (struct type *type,
extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num);
extern struct value *value_from_longest (struct type *type, LONGEST num);
+extern struct value *value_from_ulongest (struct type *type, ULONGEST num);
extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr);
extern struct value *value_from_double (struct type *type, DOUBLEST num);
extern struct value *value_from_decfloat (struct type *type,
const gdb_byte *decbytes);
+extern const char *object_address_data_not_valid (struct type *type);
+extern int object_address_get_data (struct type *type,
+ CORE_ADDR *address_return);
+
extern struct value *value_at (struct type *type, CORE_ADDR addr);
extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
@@ -684,7 +689,7 @@ extern struct value *value_allocate_space_in_inferior (int);
extern struct value *value_of_local (const char *name, int complain);
extern struct value *value_subscripted_rvalue (struct value *array,
- LONGEST index, int lowerbound);
+ CORE_ADDR offset);
/* User function handler. */
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 46d6b34..0536753 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -26,6 +26,8 @@
#include "gdbcmd.h"
#include "block.h"
#include "valprint.h"
+#include "objfiles.h"
+#include "parser-defs.h"
#include "gdb_assert.h"
#include "gdb_string.h"
@@ -3468,6 +3470,19 @@ java_value_of_variable (struct varobj *var, enum varobj_display_formats format)
return cplus_value_of_variable (var, format);
}
+/* Iterate all the existing VAROBJs and call the FUNC callback for them with an
+ arbitrary caller supplied DATA pointer. */
+
+static void
+all_varobjs (void (*func) (struct varobj *var, void *data), void *data)
+{
+ struct vlist **vlp, *vl;
+
+ for (vlp = varobj_table; vlp < varobj_table + VAROBJ_TABLE_SIZE; vlp++)
+ for (vl = *vlp; vl != NULL; vl = vl->next)
+ (*func) (vl->var, data);
+}
+
/* Iterate all the existing _root_ VAROBJs and call the FUNC callback for them
with an arbitrary caller supplied DATA pointer. */
@@ -3485,6 +3500,43 @@ all_root_varobjs (void (*func) (struct varobj *var, void *data), void *data)
(*func) (var_root->rootvar, data);
}
}
+
+/* Helper for varobj_types_mark_used. Call type_mark_used for any TYPEs
+ referenced from this VAR. */
+
+static void
+varobj_types_mark_used_iter (struct varobj *var, void *unused)
+{
+ /* Even FLOATING or IS_INVALID VARs with non-NULL TYPE references will
+ free them in free_variable. Still EXP may also reference TYPEs
+ but these belong to SYMBOLs which should be always associated with
+ an OBJFILE (and therefore not useful to be type_mark_used). */
+
+ type_mark_used (var->type);
+ if (var->value)
+ type_mark_used (value_type (var->value));
+
+ /* Check VAROBJROOTs only once during the varobj_types_mark_used pass. */
+
+ if (var->root->rootvar == var)
+ {
+ if (var->root->exp)
+ exp_types_mark_used (var->root->exp);
+ }
+}
+
+/* Call type_mark_used for any TYPEs referenced from this GDB source file. */
+
+static void
+varobj_types_mark_used (void)
+{
+ /* Check all the VAROBJs, even non-root ones. Child VAROBJs can reference
+ types from other OBJFILEs through TYPE_IS_OPAQUE resolutions by
+ check_typedef. Such types references will not be interconnected into the
+ same TYPE_GROUP. */
+
+ all_varobjs (varobj_types_mark_used_iter, NULL);
+}
extern void _initialize_varobj (void);
void
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 6301b61..47c2acb 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3035,6 +3035,7 @@ static struct sym_fns xcoff_sym_fns =
xcoff_new_init, /* sym_new_init: init anything gbl to entire symtab */
xcoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */
xcoff_initial_scan, /* sym_read: read a symbol file into symtab */
+ NULL, /* sym_read_psymbols */
xcoff_symfile_finish, /* sym_finish: finished with file, cleanup */
xcoff_symfile_offsets, /* sym_offsets: xlate offsets ext->int form */
default_symfile_segments, /* sym_segments: Get segment information from