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 . */
+
+#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 . */
+
+#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 . */
+
+#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
#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 ".", 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 '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
@@ -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 . */
+
+#include "server.h"
+#include "linux-low.h"
+#include "i387-fp.h"
+
+#include "gdb_proc_service.h"
+
+#include
+
+#ifdef HAVE_SYS_REG_H
+#include
+#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
+#include
+
+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 . */
+
+#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
+#include
+#include
+
+/* 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 ."), 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 .
+
+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 .
+
+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 (" \n")
+ elif self.type () == gdb.SIGTRAMP_FRAME:
+ stream.write (" \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 .
+
+# 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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 . */
+
+#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 . */
+
+#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 . */
+
+#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 . */
+
+#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 . */
+
+#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 . */
+
+#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 . */
+
+
+#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 . */
+
+#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 . */
+
+#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)? "" :
+ 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
@@ -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 (©, 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 . */
+
+#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 .
+
+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 . */
+
+#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 .
+
+# 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 . */
+
+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 .
+
+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 . */
+
+#include
+
+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 .
+
+# 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 . */
+
+#include
+
+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 .
+
+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' " "first: print temp1"
+gdb_test "p temp2" " = '2' " "first: print temp2"
+gdb_test "p temp3" " = '3' " "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' " "second: print temp1"
+gdb_test "p temp2" " = '2' " "second: print temp2"
+gdb_test "p temp3" " = '3' " "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 .
+ */
+#include
+
+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 .
+
+
+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 . */
+
+/* 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 .
+
+# 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 . */
+
+/* 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 .
+
+# 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 .
+
+# 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', ' '
+# (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 .
+
+# 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 .
+! Modified for the GDB testcase by Jan Kratochvil .
+
+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 .
+
+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 .
+
+ 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 .
+
+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 .
-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 .
+
+# 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 .
+! Modified for the GDB testcase by Jan Kratochvil .
+
+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 .
+
+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 .
+ */
+
+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 . */
+
+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 . */
+
+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 .
+
+# 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 .
+! Modified for the GDB testcase by Jan Kratochvil .
+
+ 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" "\\(, , \\)" "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 ()" "" "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
+#include
+#include
+#include
+
+#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 .
+
+# 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" "\\(,\\)" "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 ()" "\\(,\\)" "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 .
+
+# 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" "\\" "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
+#include
+
+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
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#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
+#include
+#include
+#include
+#include
+
+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 .
+
+# 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
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
#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