http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: commit a081d2f12945e9468edd5f4341d3e945bd0fefe9 branch `archer' - the merge of branches: archer-tromey-call-frame-cfa archer-tromey-delayed-symfile archer-tromey-dw-op-value archer-jankratochvil-vla archer-jankratochvil-misc archer-keiths-expr-cumulative archer-tromey-python archer-jankratochvil-fortran-module archer-jankratochvil-watchpoint diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9c2b9c7..032b0cf 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -166,6 +166,13 @@ INTL_CFLAGS = @INCINTL@ 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@ + # Helper code from gnulib. LIBGNU = gnulib/libgnu.a INCGNU = -I$(srcdir)/gnulib -Ignulib @@ -264,21 +271,37 @@ SUBDIR_TUI_CFLAGS= \ # SUBDIR_PYTHON_OBS = \ python.o \ + python-block.o \ + python-breakpoint.o \ python-cmd.o \ python-frame.o \ python-function.o \ + python-hooks.o \ + python-inferior.o \ + python-infthread.o \ python-objfile.o \ + python-param.o \ python-prettyprint.o \ + python-symbol.o \ + python-symtab.o \ python-type.o \ python-utils.o \ python-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ + python/python-block.c \ + python/python-breakpoint.c \ python/python-cmd.c \ python/python-frame.c \ python/python-function.c \ + python/python-hooks.c \ + python/python-inferior.c \ + python/python-infthread.c \ python/python-objfile.c \ + python/python-param.c \ python/python-prettyprint.c \ + python/python-symbol.c \ + python/python-symtab.c \ python/python-type.c \ python/python-utils.c \ python/python-value.c @@ -745,7 +768,7 @@ 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 +gdb_usleep.h python/python.h python/python-internal.h # Header files that already have srcdir in them, or which are in objdir. @@ -862,7 +885,7 @@ generated_files = config.h observer.h observer.inc ada-lex.c \ $(COMPILE) $< $(POSTCOMPILE) -all: gdb$(EXEEXT) $(CONFIG_ALL) +all: gdb$(EXEEXT) $(CONFIG_ALL) .gdbinit @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do .PHONY: all-tui all-tui: $(TUI)$(EXEEXT) @@ -1218,6 +1241,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 @@ -1917,6 +1946,14 @@ python.o: $(srcdir)/python/python.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c $(POSTCOMPILE) +python-block.o: $(srcdir)/python/python-block.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-block.c + $(POSTCOMPILE) + +python-breakpoint.o: $(srcdir)/python/python-breakpoint.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-breakpoint.c + $(POSTCOMPILE) + python-cmd.o: $(srcdir)/python/python-cmd.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-cmd.c $(POSTCOMPILE) @@ -1929,14 +1966,38 @@ python-function.o: $(srcdir)/python/python-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-function.c $(POSTCOMPILE) +python-hooks.o: $(srcdir)/python/python-hooks.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-hooks.c + $(POSTCOMPILE) + +python-inferior.o: $(srcdir)/python/python-inferior.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-inferior.c + $(POSTCOMPILE) + +python-infthread.o: $(srcdir)/python/python-infthread.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-infthread.c + $(POSTCOMPILE) + python-objfile.o: $(srcdir)/python/python-objfile.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c $(POSTCOMPILE) +python-param.o: $(srcdir)/python/python-param.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-param.c + $(POSTCOMPILE) + python-prettyprint.o: $(srcdir)/python/python-prettyprint.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-prettyprint.c $(POSTCOMPILE) +python-symbol.o: $(srcdir)/python/python-symbol.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symbol.c + $(POSTCOMPILE) + +python-symtab.o: $(srcdir)/python/python-symtab.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-symtab.c + $(POSTCOMPILE) + python-type.o: $(srcdir)/python/python-type.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c $(POSTCOMPILE) @@ -1949,6 +2010,36 @@ python-value.o: $(srcdir)/python/python-value.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-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 0b8e3af..446246f 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -425,6 +425,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 9b5d2c6..61676a9 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -1621,7 +1621,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); @@ -4727,14 +4727,10 @@ ada_lookup_symbol (const char *name, const struct block *block0, static struct symbol * ada_lookup_symbol_nonlocal (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain) { - if (linkage_name == NULL) - linkage_name = name; - return ada_lookup_symbol (linkage_name, block_static_block (block), domain, - NULL); + return ada_lookup_symbol (name, block_static_block (block), domain, NULL); } @@ -10839,6 +10835,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) { @@ -11227,6 +11257,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 7d8461c..a6d35d7 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -270,6 +270,8 @@ amd64_linux_dr_get (ptid_t ptid, int regnum) return value; } +/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */ + static void amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { @@ -286,6 +288,8 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) perror_with_name (_("Couldn't write debug register")); } +/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */ + static void amd64_linux_dr_set_control (unsigned long control) { @@ -297,6 +301,8 @@ amd64_linux_dr_set_control (unsigned long control) amd64_linux_dr_set (ptid, DR_CONTROL, control); } +/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */ + static void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr) { @@ -310,18 +316,55 @@ amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr) amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); } +/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */ + static void amd64_linux_dr_reset_addr (int regnum) { amd64_linux_dr_set_addr (regnum, 0); } +/* Get DR_STATUS from only the one LWP of INFERIOR_PTID. */ + static unsigned long amd64_linux_dr_get_status (void) { return amd64_linux_dr_get (inferior_ptid, DR_STATUS); } +/* Unset VALUE bits in DR_STATUS in all LWPs of LWP_LIST. */ + +static void +amd64_linux_dr_unset_status (unsigned long mask) +{ + struct lwp_info *lp; + ptid_t ptid; + + ALL_LWPS (lp, ptid) + { + unsigned long value; + + value = amd64_linux_dr_get (ptid, DR_STATUS); + value &= ~mask; + amd64_linux_dr_set (ptid, DR_STATUS, value); + } +} + +/* 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) { @@ -672,6 +715,8 @@ _initialize_amd64_linux_nat (void) i386_dr_low.set_addr = amd64_linux_dr_set_addr; 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 1889ecd..37fa342 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -223,8 +223,9 @@ block_set_scope (struct block *block, const char *scope, BLOCK_NAMESPACE (block)->scope = scope; } -/* This returns the using directives list associated with BLOCK, if - any. */ +/* This returns the first using directives associated with BLOCK, if + any. Each BLOCK_NAMESPACE()->USING already contains all the namespaces + imported at that code point - even those from its parent blocks. */ struct using_direct * block_using (const struct block *block) @@ -314,6 +315,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 53e7371..d373f8a 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 f3940e1..2349fbc 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -59,6 +59,7 @@ #include "top.h" #include "wrapper.h" #include "valprint.h" +#include "parser-defs.h" /* readline include files */ #include "readline/readline.h" @@ -578,6 +579,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 @@ -598,42 +646,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; } @@ -1690,6 +1703,7 @@ detach_breakpoints (int pid) if (b->inserted) val |= remove_breakpoint (b, mark_inserted); } + val |= target_detach_watchpoints (); do_cleanups (old_chain); return val; } @@ -1782,12 +1796,14 @@ remove_breakpoint (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); @@ -2961,8 +2977,12 @@ bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr) /* 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; @@ -3051,8 +3071,10 @@ bpstat_check_watchpoint (bpstat bs) anything for this watchpoint. */ bs->print_it = print_it_noop; bs->stop = 0; + return 0; } } + return 1; } @@ -3156,6 +3178,8 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) ALL_BP_LOCATIONS (bl) { + bpstat bs_prev = bs; + b = bl->owner; gdb_assert (b); if (!breakpoint_enabled (b) && b->enable_state != bp_permanent) @@ -3176,6 +3200,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) /* 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 @@ -3183,9 +3208,18 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) 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) @@ -8843,6 +8877,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. @@ -9345,4 +9395,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 d93c6b6..a555c16 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -918,6 +918,9 @@ extern void breakpoint_retire_moribund (void); /* 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-exp.y b/gdb/c-exp.y index aacc112..e206983 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -117,6 +117,8 @@ static int yylex (void); void yyerror (char *); +/* Cleanup for 'nonempty_typelist' */ +static struct cleanup *typelist_cleanup; %} /* Although the yacc "value" of an expression is not used, @@ -157,6 +159,7 @@ void yyerror (char *); %{ /* YYSTYPE gets defined by %union */ static int parse_number (char *, int, int, YYSTYPE *); +static struct stoken operator_stoken (const char *); %} %type exp exp1 type_exp start variable qualified_name lcurly @@ -199,9 +202,12 @@ static int parse_number (char *, int, int, YYSTYPE *); %token NAME_OR_INT +%token OPERATOR %token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON %token TEMPLATE %token ERROR +%token NEW DELETE +%type operator /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ @@ -232,7 +238,7 @@ static int parse_number (char *, int, int, YYSTYPE *); %left '+' '-' %left '*' '/' '%' %right UNARY INCREMENT DECREMENT -%right ARROW '.' '[' '(' +%right ARROW ARROW_STAR '.' DOT_STAR '[' '(' %token BLOCKNAME %token FILENAME %type block @@ -333,7 +339,7 @@ exp : exp ARROW qualified_name write_exp_elt_opcode (STRUCTOP_MPTR); } ; -exp : exp ARROW '*' exp +exp : exp ARROW_STAR exp { write_exp_elt_opcode (STRUCTOP_MPTR); } ; @@ -368,7 +374,7 @@ exp : exp '.' qualified_name write_exp_elt_opcode (STRUCTOP_MEMBER); } ; -exp : exp '.' '*' exp +exp : exp DOT_STAR exp { write_exp_elt_opcode (STRUCTOP_MEMBER); } ; @@ -401,6 +407,36 @@ arglist : arglist ',' exp %prec ABOVE_COMMA { arglist_len++; } ; +exp : exp '(' nonempty_typelist ')' const_or_volatile + { int i; + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + do_cleanups (typelist_cleanup); + } + ; + +/* +exp : BLOCKNAME '(' nonempty_typelist ')' + { int i; + write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); + write_exp_elt_sym ($1.sym); + write_exp_elt_opcode (TYPE_INSTANCE_LOOKUP); + + write_exp_elt_opcode (TYPE_INSTANCE); + write_exp_elt_longcst ((LONGEST) $3[0]); + for (i = 0; i < $3[0]; ++i) + write_exp_elt_type ($3[i + 1]); + write_exp_elt_longcst((LONGEST) $3[0]); + write_exp_elt_opcode (TYPE_INSTANCE); + do_cleanups (typelist_cleanup); + } + ; +*/ + rcurly : '}' { $$ = end_arglist () - 1; } ; @@ -703,6 +739,7 @@ variable: block COLONCOLON name qualified_name: typebase COLONCOLON name { struct type *type = $1; + CHECK_TYPEDEF (type); if (TYPE_CODE (type) != TYPE_CODE_STRUCT && TYPE_CODE (type) != TYPE_CODE_UNION && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) @@ -718,6 +755,7 @@ qualified_name: typebase COLONCOLON name { struct type *type = $1; struct stoken tmp_token; + CHECK_TYPEDEF (type); if (TYPE_CODE (type) != TYPE_CODE_STRUCT && TYPE_CODE (type) != TYPE_CODE_UNION && TYPE_CODE (type) != TYPE_CODE_NAMESPACE) @@ -740,12 +778,13 @@ qualified_name: typebase COLONCOLON name ; variable: qualified_name + | COLONCOLON qualified_name | COLONCOLON name { char *name = copy_name ($2); struct symbol *sym; struct minimal_symbol *msymbol; - + sym = lookup_symbol (name, (const struct block *) NULL, VAR_DOMAIN, (int *) NULL); @@ -883,7 +922,7 @@ array_mod: '[' ']' func_mod: '(' ')' { $$ = 0; } | '(' nonempty_typelist ')' - { free ($2); $$ = 0; } + { do_cleanups (typelist_cleanup); $$ = 0; } ; /* We used to try to recognize pointer to member types here, but @@ -1088,12 +1127,15 @@ typename: TYPENAME nonempty_typelist : type { $$ = (struct type **) malloc (sizeof (struct type *) * 2); + typelist_cleanup = make_cleanup (free, $$); $$[0] = 1; /* Number of types in vector */ $$[1] = $1; } | nonempty_typelist ',' type { int len = sizeof (struct type *) * (++($1[0]) + 1); $$ = (struct type **) realloc ((char *) $1, len); + discard_cleanups (typelist_cleanup); + typelist_cleanup = make_cleanup (free, $$); $$[$$[0]] = $3; } ; @@ -1117,10 +1159,135 @@ const_or_volatile_noopt: const_and_volatile { push_type (tp_volatile); } ; +operator: OPERATOR NEW + { $$ = operator_stoken (" new"); } + | OPERATOR DELETE + { $$ = operator_stoken (" delete"); } + | OPERATOR NEW '[' ']' + { $$ = operator_stoken (" new[]"); } + | OPERATOR DELETE '[' ']' + { $$ = operator_stoken (" delete[]"); } + | OPERATOR '+' + { $$ = operator_stoken ("+"); } + | OPERATOR '-' + { $$ = operator_stoken ("-"); } + | OPERATOR '*' + { $$ = operator_stoken ("*"); } + | OPERATOR '/' + { $$ = operator_stoken ("/"); } + | OPERATOR '%' + { $$ = operator_stoken ("%"); } + | OPERATOR '^' + { $$ = operator_stoken ("^"); } + | OPERATOR '&' + { $$ = operator_stoken ("&"); } + | OPERATOR '|' + { $$ = operator_stoken ("|"); } + | OPERATOR '~' + { $$ = operator_stoken ("~"); } + | OPERATOR '!' + { $$ = operator_stoken ("!"); } + | OPERATOR '=' + { $$ = operator_stoken ("="); } + | OPERATOR '<' + { $$ = operator_stoken ("<"); } + | OPERATOR '>' + { $$ = operator_stoken (">"); } + | OPERATOR ASSIGN_MODIFY + { const char *op = "unknown"; + switch ($2) + { + case BINOP_RSH: + op = ">>="; + break; + case BINOP_LSH: + op = "<<="; + break; + case BINOP_ADD: + op = "+="; + break; + case BINOP_SUB: + op = "-="; + break; + case BINOP_MUL: + op = "*="; + break; + case BINOP_DIV: + op = "/="; + break; + case BINOP_REM: + op = "%="; + break; + case BINOP_BITWISE_IOR: + op = "|="; + break; + case BINOP_BITWISE_AND: + op = "&="; + break; + case BINOP_BITWISE_XOR: + op = "^="; + break; + default: + break; + } + + $$ = operator_stoken (op); + } + | OPERATOR LSH + { $$ = operator_stoken ("<<"); } + | OPERATOR RSH + { $$ = operator_stoken (">>"); } + | OPERATOR EQUAL + { $$ = operator_stoken ("=="); } + | OPERATOR NOTEQUAL + { $$ = operator_stoken ("!="); } + | OPERATOR LEQ + { $$ = operator_stoken ("<="); } + | OPERATOR GEQ + { $$ = operator_stoken (">="); } + | OPERATOR ANDAND + { $$ = operator_stoken ("&&"); } + | OPERATOR OROR + { $$ = operator_stoken ("||"); } + | OPERATOR INCREMENT + { $$ = operator_stoken ("++"); } + | OPERATOR DECREMENT + { $$ = operator_stoken ("--"); } + | OPERATOR ',' + { $$ = operator_stoken (","); } + | OPERATOR ARROW_STAR + { $$ = operator_stoken ("->*"); } + | OPERATOR ARROW + { $$ = operator_stoken ("->"); } + | OPERATOR '(' ')' + { $$ = operator_stoken ("()"); } + | OPERATOR '[' ']' + { $$ = operator_stoken ("[]"); } + | OPERATOR ptype + { char *name, *canon; + long length; + struct ui_file *buf = mem_fileopen (); + + c_print_type ($2, NULL, buf, -1, 0); + name = ui_file_xstrdup (buf, &length); + canon = cp_canonicalize_string (name); + if (canon != NULL) + { + xfree (name); + name = canon; + } + ui_file_delete (buf); + $$ = operator_stoken (name); + } + ; + + + name : NAME { $$ = $1.stoken; } | BLOCKNAME { $$ = $1.stoken; } | TYPENAME { $$ = $1.stoken; } | NAME_OR_INT { $$ = $1.stoken; } + | operator { $$ = $1; } ; name_not_typename : NAME @@ -1136,6 +1303,20 @@ name_not_typename : NAME %% +/* Returns a stoken of the operator name given by OP (which does not + include the string "operator"). The result is xmalloc'd. */ +static struct stoken +operator_stoken (const char *op) +{ + static const char *operator_string = "operator"; + struct stoken st = { NULL, 0 }; + st.length = strlen (operator_string) + strlen (op); + st.ptr = xmalloc (st.length + 1); + strcpy (st.ptr, operator_string); + strcat (st.ptr, op); + return st; +}; + /* Take care of parsing a number (anything that starts with a digit). Set yylval and return the token type; update lexptr. LEN is the number of characters in it. */ @@ -1664,7 +1845,8 @@ struct token static const struct token tokentab3[] = { {">>=", ASSIGN_MODIFY, BINOP_RSH, 0}, - {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0} + {"<<=", ASSIGN_MODIFY, BINOP_LSH, 0}, + {"->*", ARROW_STAR, BINOP_END, 1} }; static const struct token tokentab2[] = @@ -1688,7 +1870,8 @@ static const struct token tokentab2[] = {"==", EQUAL, BINOP_END, 0}, {"!=", NOTEQUAL, BINOP_END, 0}, {"<=", LEQ, BINOP_END, 0}, - {">=", GEQ, BINOP_END, 0} + {">=", GEQ, BINOP_END, 0}, + {".*", DOT_STAR, BINOP_END, 0} }; /* Identifier-like tokens. */ @@ -1710,6 +1893,9 @@ static const struct token ident_tokens[] = {"long", LONG, OP_NULL, 0}, {"true", TRUEKEYWORD, OP_NULL, 1}, {"int", INT_KEYWORD, OP_NULL, 0}, + {"new", NEW, OP_NULL, 1}, + {"delete", DELETE, OP_NULL, 1}, + {"operator", OPERATOR, OP_NULL, 1}, {"and", ANDAND, BINOP_END, 1}, {"and_eq", ASSIGN_MODIFY, BINOP_BITWISE_AND, 1}, @@ -1818,6 +2004,13 @@ static int last_was_structop; static int yylex (void) { + /* name_prefix stores the full qualification of a variable that is + specified in the expression. It is used to eleminate confusion + during lookup.*/ + static char *name_prefix = NULL; + static int name_prefix_len = 0; + static int terminate_prefix = 0; + int c; int namelen; unsigned int i; @@ -1826,9 +2019,19 @@ yylex (void) char *copy; last_was_structop = 0; - + retry: - + + if (terminate_prefix + || lexptr != name_prefix + name_prefix_len) + { + /* Some token was skipped, so clear name_prefix. */ + name_prefix = NULL; + name_prefix_len = 0; + } + + terminate_prefix = 1; + /* Check if this is a macro invocation that we need to expand. */ if (! scanning_macro_expansion ()) { @@ -1856,10 +2059,19 @@ yylex (void) for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) if (strncmp (tokstart, tokentab2[i].operator, 2) == 0) { + if (tokentab2[i].token == COLONCOLON) + { + name_prefix_len += 2; + terminate_prefix = 0; + if (name_prefix == NULL) + name_prefix = lexptr; + } + lexptr += 2; yylval.opcode = tokentab2[i].opcode; if (in_parse_field && tokentab2[i].token == ARROW) last_was_structop = 1; + return tokentab2[i].token; } @@ -1888,6 +2100,8 @@ yylex (void) return 0; case ' ': + name_prefix_len++; + terminate_prefix = 0; case '\t': case '\n': lexptr++; @@ -2045,11 +2259,13 @@ yylex (void) error ("Invalid character '%c' in expression.", c); /* It's a name. See how long it is. */ + namelen = 0; for (c = tokstart[namelen]; (c == '_' || c == '$' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');) { + /* Template parameter lists are part of the name. FIXME: This mishandles `print $a<4&&$a>3'. */ @@ -2113,14 +2329,29 @@ yylex (void) currently as names of types; NAME for other symbols. The caller is not constrained to care about the distinction. */ { + char *tmp = copy; struct symbol *sym; int is_a_field_of_this = 0; int hextype; - sym = lookup_symbol (copy, expression_context_block, + if (name_prefix != NULL) + tmp = savestring (name_prefix, name_prefix_len+namelen); + + sym = lookup_symbol (tmp, expression_context_block, VAR_DOMAIN, parse_language->la_language == language_cplus ? &is_a_field_of_this : (int *) NULL); + + /* Keep this name as the prefix for the next name. */ + if (sym) + { + if (name_prefix == NULL) + name_prefix = tokstart; + + name_prefix_len += namelen; + terminate_prefix = 0; + } + /* Call lookup_symtab, not lookup_partial_symtab, in case there are no psymtabs (coff, xcoff, or some future change to blow away the psymtabs once once symbols are read). */ @@ -2179,6 +2410,7 @@ yylex (void) yylval.ssym.is_a_field_of_this = is_a_field_of_this; if (in_parse_field && *lexptr == '\0') saw_name_at_eof = 1; + return NAME; } } diff --git a/gdb/c-lang.c b/gdb/c-lang.c index 4ba81ba..053f685 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -715,7 +715,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; *charset = target_charset (); @@ -1038,6 +1038,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 @@ -1138,6 +1141,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 b193080..04cf3bc 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -32,6 +32,7 @@ #include "c-lang.h" #include "typeprint.h" #include "cp-abi.h" +#include "jv-lang.h" #include "gdb_string.h" #include @@ -40,8 +41,6 @@ static void cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring, int staticp, struct ui_file *stream); -static void c_type_print_args (struct type *, struct ui_file *); - static void cp_type_print_derivation_info (struct ui_file *, struct type *); static void c_type_print_varspec_prefix (struct type *, struct ui_file *, int, @@ -199,6 +198,23 @@ cp_type_print_method_args (struct type *mtype, char *prefix, char *varstring, fprintf_filtered (stream, "void"); fprintf_filtered (stream, ")"); + + /* For non-static methods, read qualifiers from the type of + THIS. */ + if (!staticp) + { + struct type *domain; + + gdb_assert (nargs > 0); + gdb_assert (TYPE_CODE (args[0].type) == TYPE_CODE_PTR); + domain = TYPE_TARGET_TYPE (args[0].type); + + if (TYPE_CONST (domain)) + fprintf_filtered (stream, " const"); + + if (TYPE_VOLATILE (domain)) + fprintf_filtered (stream, " volatile"); + } } @@ -355,10 +371,14 @@ c_type_print_modifier (struct type *type, struct ui_file *stream, /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD or TYPE_CODE_FUNC, to STREAM. Artificial arguments, such as "this" - in non-static methods, are displayed. */ + in non-static methods, are displayed if SHOW_ARTIFICIAL is + non-zero. LANGUAGE is the language in which TYPE was defined. This is + a necessary evil since this code is used by the C, C++, and Java + backends. */ -static void -c_type_print_args (struct type *type, struct ui_file *stream) +void +c_type_print_args (struct type *type, struct ui_file *stream, + int show_artificial, enum language language) { int i, len; struct field *args; @@ -370,13 +390,19 @@ c_type_print_args (struct type *type, struct ui_file *stream) for (i = 0; i < TYPE_NFIELDS (type); i++) { + if (TYPE_FIELD_ARTIFICIAL (type, i) && !show_artificial) + continue; + if (printed_any) { fprintf_filtered (stream, ", "); wrap_here (" "); } - c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); + if (language == language_java) + java_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); + else + c_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0); printed_any = 1; } @@ -560,7 +586,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_BOUND_IS_DWARF_BLOCK (type, 1)) + { + /* 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) @@ -593,7 +624,7 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, if (passed_a_ptr) fprintf_filtered (stream, ")"); if (!demangled_args) - c_type_print_args (type, stream); + c_type_print_args (type, stream, 1, language_c); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, show, passed_a_ptr, 0); break; diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index ce7c2a6..6380fec 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -46,6 +46,8 @@ #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 @@ -183,6 +185,7 @@ struct cmd_list_element *showchecklist; /* Command tracing state. */ +static int source_python = 0; int source_verbose = 0; int trace_commands = 0; @@ -444,6 +447,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) { @@ -476,8 +480,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); } @@ -491,15 +503,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 @@ -507,23 +534,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); } @@ -1307,7 +1339,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 888f8b4..65494b8 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -346,7 +346,7 @@ coff_alloc_type (int index) We will fill it in later if we find out how. */ if (type == NULL) { - type = alloc_type (current_objfile); + type = alloc_type (current_objfile, NULL); *type_addr = type; } return type; @@ -2121,6 +2121,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 f2d56a0..0909c80 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -43,11 +43,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. */ @@ -641,6 +640,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 93f7f4b..a6580e2 100755 --- a/gdb/configure +++ b/gdb/configure @@ -314,7 +314,7 @@ ac_subdirs_all="$ac_subdirs_all doc testsuite" ac_subdirs_all="$ac_subdirs_all gdbtk" ac_subdirs_all="$ac_subdirs_all multi-ice" ac_subdirs_all="$ac_subdirs_all gdbserver" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE DEBUGDIR GDB_DATADIR subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE SYSTEM_GDBINIT WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags GDB_NM_FILE datarootdir docdir htmldir pdfdir LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os am__leading_dot DEPDIR CCDEPMODE MAKE GMAKE_TRUE GMAKE_FALSE SET_MAKE USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE GNULIB_MEMMEM GNULIB_MEMPCPY GNULIB_MEMRCHR GNULIB_STPCPY GNULIB_STPNCPY GNULIB_STRCHRNUL GNULIB_STRDUP GNULIB_STRNDUP GNULIB_STRNLEN GNULIB_STRPBRK GNULIB_STRSEP GNULIB_STRSTR GNULIB_STRCASESTR GNULIB_STRTOK_R GNULIB_MBSLEN GNULIB_MBSNLEN GNULIB_MBSCHR GNULIB_MBSRCHR GNULIB_MBSSTR GNULIB_MBSCASECMP GNULIB_MBSNCASECMP GNULIB_MBSPCASECMP GNULIB_MBSCASESTR GNULIB_MBSCSPN GNULIB_MBSPBRK GNULIB_MBSSPN GNULIB_MBSSEP GNULIB_MBSTOK_R GNULIB_STRERROR GNULIB_STRSIGNAL HAVE_DECL_MEMMEM HAVE_MEMPCPY HAVE_DECL_MEMRCHR HAVE_STPCPY HAVE_STPNCPY HAVE_STRCHRNUL HAVE_DECL_STRDUP HAVE_STRNDUP HAVE_DECL_STRNDUP HAVE_DECL_STRNLEN HAVE_STRPBRK HAVE_STRSEP HAVE_STRCASESTR HAVE_DECL_STRTOK_R HAVE_DECL_STRERROR HAVE_DECL_STRSIGNAL REPLACE_STRERROR REPLACE_STRSIGNAL REPLACE_MEMMEM REPLACE_STRCASESTR REPLACE_STRSTR HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTTYPES_H HAVE_SYS_TYPES_H INCLUDE_NEXT NEXT_STDINT_H HAVE_STDINT_H HAVE_SYS_INTTYPES_H HAVE_SYS_BITYPES_H BITSIZEOF_PTRDIFF_T BITSIZEOF_SIG_ATOMIC_T BITSIZEOF_SIZE_T BITSIZEOF_WCHAR_T BITSIZEOF_WINT_T HAVE_SIGNED_SIG_ATOMIC_T HAVE_SIGNED_WCHAR_T HAVE_SIGNED_WINT_T PTRDIFF_T_SUFFIX SIG_ATOMIC_T_SUFFIX SIZE_T_SUFFIX WCHAR_T_SUFFIX WINT_T_SUFFIX STDINT_H NEXT_STRING_H GNULIB_WCWIDTH HAVE_DECL_WCWIDTH REPLACE_WCWIDTH WCHAR_H HAVE_WCHAR_H NEXT_WCHAR_H LIBGNU_LIBDEPS LIBGNU_LTLIBDEPS GNULIB_STDINT_H PACKAGE INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK AMTAR am__tar am__untar am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH am__fastdepCC_TRUE am__fastdepCC_FALSE DEBUGDIR GDB_DATADIR GDB_DATADIR_PATH pythondir subdirs TARGET_OBS PKGVERSION REPORT_BUGS_TO REPORT_BUGS_TEXI LN_S YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT PYTHON_CFLAGS ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE SYSTEM_GDBINIT WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_PATCH_LEVEL TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_INCLUDE TCL_LIBRARY TCL_DEPS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_INCLUDE TK_LIBRARY TK_DEPS TK_XINCLUDES X_CFLAGS X_LDFLAGS X_LIBS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags GDB_NM_FILE datarootdir docdir htmldir pdfdir LIBOBJS LTLIBOBJS gl_LIBOBJS gl_LTLIBOBJS gltests_LIBOBJS gltests_LTLIBOBJS' ac_subst_files='host_makefile_frag' ac_pwd=`pwd` @@ -891,6 +891,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 @@ -7218,6 +7222,75 @@ _ACEOF fi; +# GDB's datadir relocation + +gdbdatadir=${datadir}/gdb + + +# Check whether --with-gdb-datadir or --without-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}/'*) + +cat >>confdefs.h <<\_ACEOF +#define GDB_DATADIR_RELOCATABLE 1 +_ACEOF + + ;; +esac +GDB_DATADIR_PATH=${gdbdatadir} + + + +# Check whether --with-pythondir or --without-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" @@ -11837,6 +11910,8 @@ _ACEOF 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). @@ -22174,6 +22249,8 @@ s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t s,@DEBUGDIR@,$DEBUGDIR,;t t s,@GDB_DATADIR@,$GDB_DATADIR,;t t +s,@GDB_DATADIR_PATH@,$GDB_DATADIR_PATH,;t t +s,@pythondir@,$pythondir,;t t s,@subdirs@,$subdirs,;t t s,@TARGET_OBS@,$TARGET_OBS,;t t s,@PKGVERSION@,$PKGVERSION,;t t diff --git a/gdb/configure.ac b/gdb/configure.ac index 77f8436..bca368c 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -109,6 +109,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 @@ -660,6 +705,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/cp-name-parser.y b/gdb/cp-name-parser.y index 62800b8..97d587b 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1,7 +1,6 @@ /* YACC parser for C++ names, for GDB. - Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. Parts of the lexer are based on c-exp.y from GDB. @@ -389,7 +388,7 @@ function | colon_ext_only function_arglist start_opt { $$ = fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp); if ($3) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); } - + | colon_ext_only | conversion_op_name start_opt { $$ = $1.comp; if ($2) $$ = fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $2); } diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c index d2d8f2e..7672b2e 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -36,14 +36,17 @@ static struct using_direct *cp_copy_usings (struct using_direct *using, struct obstack *obstack); static struct symbol *lookup_namespace_scope (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain, const char *scope, int scope_len); +static struct symbol *cp_lookup_symbol_in_namespace (const char *namespace, + const char *name, + const struct block *block, + const domain_enum domain); + static struct symbol *lookup_symbol_file (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain, int anonymous_namespace); @@ -119,7 +122,7 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) anonymous namespace. So add symbols in it to the namespace given by the previous component if there is one, or to the global namespace if there isn't. */ - cp_add_using_directive (dest, src); + cp_add_using_directive (dest, src, "", "", 0); } /* The "+ 2" is for the "::". */ previous_component = next_component + 2; @@ -134,7 +137,8 @@ cp_scan_for_anonymous_namespaces (const struct symbol *symbol) has already been added, don't add it twice. */ void -cp_add_using_directive (const char *dest, const char *src) +cp_add_using_directive (const char *dest, const char *src, const char* alias, + const char *declaration, const int line_number) { struct using_direct *current; struct using_direct *new; @@ -148,7 +152,8 @@ cp_add_using_directive (const char *dest, const char *src) return; } - using_directives = cp_add_using (dest, src, using_directives); + using_directives = cp_add_using (dest, src, alias, declaration, + line_number, using_directives); } @@ -201,7 +206,10 @@ cp_is_anonymous (const char *namespace) } /* Create a new struct using direct which imports the namespace SRC - into the scope DEST. + into the scope DEST. ALIAS is the name of the imported namespace + in the current scope. If ALIAS is an empty string then the + namespace is known by its original name. + Set its next member in the linked list to NEXT; allocate all memory using xmalloc. It copies the strings, so NAME can be a temporary string. */ @@ -209,14 +217,21 @@ cp_is_anonymous (const char *namespace) struct using_direct * cp_add_using (const char *dest, const char *src, + const char *alias, + const char *declaration, + const int line_number, struct using_direct *next) { struct using_direct *retval; retval = xmalloc (sizeof (struct using_direct)); - retval->import_src = savestring (src, strlen(src)); - retval->import_dest = savestring (dest, strlen(dest)); + retval->import_src = savestring (src, strlen (src)); + retval->import_dest = savestring (dest, strlen (dest)); + retval->alias = savestring (alias, strlen (alias)); + retval->declaration = savestring (declaration, strlen (declaration)); + retval->line_number = line_number; retval->next = next; + retval->searched = 0; return retval; } @@ -241,10 +256,18 @@ cp_copy_usings (struct using_direct *using, obstack); retval->import_dest = obsavestring (using->import_dest, strlen (using->import_dest), obstack); + retval->alias = obsavestring (using->alias, strlen (using->alias), + obstack); + retval->declaration = obsavestring (using->declaration, strlen (using->declaration), + obstack); retval->next = cp_copy_usings (using->next, obstack); + retval->searched = using->searched; + xfree (using->import_src); xfree (using->import_dest); + xfree (using->alias); + xfree (using->declaration); xfree (using); return retval; @@ -261,12 +284,48 @@ cp_copy_usings (struct using_direct *using, struct symbol * cp_lookup_symbol_nonlocal (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain) { - return lookup_namespace_scope (name, linkage_name, block, domain, - block_scope (block), 0); + struct symbol *sym; + const char *scope = block_scope (block); + + sym = lookup_namespace_scope (name, block, domain, scope, 0); + if (sym != NULL) + return sym; + + return cp_lookup_symbol_namespace(scope, name, block, domain); +} + +/* Searches for NAME in the current namespace, and by applying relevant import + statements belonging to BLOCK and its parents. SCOPE is the namespace + scope of the context in which the search is being evaluated. */ + +struct symbol* +cp_lookup_symbol_namespace (const char *scope, + const char *name, + const struct block *block, + const domain_enum domain) +{ + struct symbol *sym; + + /* First, try to find the symbol in the given namespace. */ + sym = cp_lookup_symbol_in_namespace (scope, name, block, domain); + if ( sym != NULL) + return sym; + + /* Search for name in namespaces imported to this and parent blocks. */ + while (block != NULL) + { + sym = cp_lookup_symbol_imports(scope,name, block, domain,0,1); + + if (sym) + return sym; + + block = BLOCK_SUPERBLOCK(block); + } + + return NULL; } /* Lookup NAME at namespace scope (or, in C terms, in static and @@ -284,9 +343,8 @@ cp_lookup_symbol_nonlocal (const char *name, "A::x", and if that call fails, then the first call looks for "x". */ -static struct symbol * +struct symbol * lookup_namespace_scope (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain, const char *scope, @@ -308,8 +366,7 @@ lookup_namespace_scope (const char *name, new_scope_len += 2; } new_scope_len += cp_find_first_component (scope + new_scope_len); - sym = lookup_namespace_scope (name, linkage_name, block, - domain, scope, new_scope_len); + sym = lookup_namespace_scope (name, block, domain, scope, new_scope_len); if (sym != NULL) return sym; } @@ -320,25 +377,81 @@ lookup_namespace_scope (const char *name, namespace = alloca (scope_len + 1); strncpy (namespace, scope, scope_len); namespace[scope_len] = '\0'; - return cp_lookup_symbol_namespace (namespace, name, linkage_name, - block, domain); + return cp_lookup_symbol_in_namespace (namespace, name,block, domain); } -/* Look up NAME in the C++ namespace NAMESPACE, applying the using - directives that are active in BLOCK. Other arguments are as in +/* Look up NAME in the C++ namespace NAMESPACE. Other arguments are as in cp_lookup_symbol_nonlocal. */ +static struct symbol * +cp_lookup_symbol_in_namespace (const char *namespace, + const char *name, + const struct block *block, + const domain_enum domain) +{ + + if (namespace[0] == '\0') + { + return lookup_symbol_file (name, block,domain, 0); + } + else + { + char *concatenated_name + = alloca (strlen (namespace) + 2 + strlen (name) + 1); + strcpy (concatenated_name, namespace); + strcat (concatenated_name, "::"); + strcat (concatenated_name, name); + return lookup_symbol_file (concatenated_name, block, domain, + cp_is_anonymous (namespace)); + } +} + +/* Search for NAME by applying all import statements belonging + to BLOCK which are applicable in SCOPE. If DECLARATION_ONLY the search + is restricted to using declarations. + Example: + + namespace A{ + int x; + } + using A::x; + + If SEARCH_PARENTS the search will include imports which are applicable in + parents of scopes. + Example: + + namespace A{ + using namespace X; + namespace B{ + using namespace Y; + } + } + + If SCOPE is "A::B" and SEARCH_PARENTS is true the imports of namespaces X + and Y will be considered. If SEARCH_PARENTS is false only the import of Y + is considered. */ + struct symbol * -cp_lookup_symbol_namespace (const char *namespace, - const char *name, - const char *linkage_name, - const struct block *block, - const domain_enum domain) +cp_lookup_symbol_imports (const char *scope, + const char *name, + const struct block *block, + const domain_enum domain, + int declaration_only, + int search_parents) { - const struct using_direct *current; - struct symbol *sym; + struct using_direct *current; + struct symbol *sym = NULL; + int directive_match; + int current_line = find_pc_line (get_frame_pc (get_current_frame ()), 0).line; - /* First, go through the using directives. If any of them add new + if(!declaration_only) + /* First, try to find the symbol in the given namespace. */ + sym = cp_lookup_symbol_in_namespace (scope, name, block, domain); + + if ( sym != NULL) + return sym; + + /* Go through the using directives. If any of them add new names to the namespace we're searching in, see if we can find a match by applying them. */ @@ -346,39 +459,74 @@ cp_lookup_symbol_namespace (const char *namespace, current != NULL; current = current->next) { - if (strcmp (namespace, current->import_dest) == 0) + + /* If the import destination is the current scope or one of its ancestors then + it is applicable. */ + directive_match = search_parents ? + strncmp (scope, current->import_dest, + strlen(current->import_dest)) == 0 : + strcmp (scope, current->import_dest) == 0; + + if (directive_match && + current->line_number < current_line && + !current->searched) { - sym = cp_lookup_symbol_namespace (current->import_src, - name, - linkage_name, - block, - domain); + current->searched = 1; + /* If there is an import of a single declaration, compare the imported + declaration with the sought out name. If there is a match pass + current->import_src as NAMESPACE to direct the search towards the + imported namespace. */ + if (strcmp ("", current->declaration) != 0) + { + if (strcmp (name, current->declaration) == 0) + { + sym = cp_lookup_symbol_in_namespace (current->import_src, + name, + block, + domain); + } + } + + if (declaration_only) + { + current->searched = 0; + if (sym) + { + return sym; + } else { + continue; + } + } + + if (strcmp (name, current->alias) == 0) + /* If the import is creating an alias and the alias matches the + sought name. Pass current->inner as the NAME to direct the + search towards the aliased namespace */ + { + sym = cp_lookup_symbol_in_namespace (scope, + current->import_src, + block, + domain); + } else if (strcmp ("", current->alias) == 0){ + /* If this import statement creates no alias, pass current->inner as + NAMESPACE to direct the search towards the imported namespace. */ + sym = cp_lookup_symbol_imports (current->import_src, + name, + block, + domain, + 0, + 0); + } + + current->searched = 0; if (sym != NULL) - return sym; + { + return sym; + } } } - /* We didn't find anything by applying any of the using directives - that are still applicable; so let's see if we've got a match - using the current namespace. */ - - if (namespace[0] == '\0') - { - return lookup_symbol_file (name, linkage_name, block, - domain, 0); - } - else - { - char *concatenated_name - = alloca (strlen (namespace) + 2 + strlen (name) + 1); - strcpy (concatenated_name, namespace); - strcat (concatenated_name, "::"); - strcat (concatenated_name, name); - sym = lookup_symbol_file (concatenated_name, linkage_name, - block, domain, - cp_is_anonymous (namespace)); - return sym; - } + return NULL; } /* Look up NAME in BLOCK's static block and in global blocks. If @@ -388,17 +536,15 @@ cp_lookup_symbol_namespace (const char *namespace, static struct symbol * lookup_symbol_file (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain, int anonymous_namespace) { struct symbol *sym = NULL; - sym = lookup_symbol_static (name, linkage_name, block, domain); + sym = lookup_symbol_static (name, block, domain); if (sym != NULL) return sym; - if (anonymous_namespace) { /* Symbols defined in anonymous namespaces have external linkage @@ -408,12 +554,11 @@ lookup_symbol_file (const char *name, const struct block *global_block = block_global_block (block); if (global_block != NULL) - sym = lookup_symbol_aux_block (name, linkage_name, global_block, - domain); + sym = lookup_symbol_aux_block (name, global_block, domain); } else { - sym = lookup_symbol_global (name, linkage_name, block, domain); + sym = lookup_symbol_global (name, block, domain); } if (sym != NULL) @@ -434,6 +579,7 @@ lookup_symbol_file (const char *name, sym = lookup_possible_namespace_symbol (name); if (sym != NULL) return sym; + } return NULL; @@ -461,9 +607,8 @@ cp_lookup_nested_type (struct type *parent_type, lookup_symbol_namespace works when looking them up. */ const char *parent_name = TYPE_TAG_NAME (parent_type); - struct symbol *sym = cp_lookup_symbol_namespace (parent_name, + struct symbol *sym = cp_lookup_symbol_in_namespace (parent_name, nested_name, - NULL, block, VAR_DOMAIN); if (sym == NULL || SYMBOL_CLASS (sym) != LOC_TYPEDEF) @@ -709,7 +854,7 @@ check_one_possible_namespace_symbol (const char *name, int len, memcpy (name_copy, name, len); name_copy[len] = '\0'; - sym = lookup_block_symbol (block, name_copy, NULL, VAR_DOMAIN); + sym = lookup_block_symbol (block, name_copy, VAR_DOMAIN); if (sym == NULL) { @@ -749,7 +894,7 @@ lookup_possible_namespace_symbol (const char *name) struct symbol *sym; sym = lookup_block_symbol (get_possible_namespace_block (objfile), - name, NULL, VAR_DOMAIN); + name, VAR_DOMAIN); if (sym != NULL) return sym; diff --git a/gdb/cp-support.c b/gdb/cp-support.c index f12d785..ca10007 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -70,6 +70,21 @@ struct cmd_list_element *maint_cplus_cmd_list = NULL; static void maint_cplus_command (char *arg, int from_tty); static void first_component_command (char *arg, int from_tty); +/* Operator validation. This is used by cp_validate_opeartor, + which is in turn used by both the expression parser (clex) + and decode_line (decode_compound, actually). + + NOTE: Multi-byte operators (usually the assignment variety operator) + must appear before the single byte version, i.e., "+=" before "+". */ +static const char *operator_tokens[] = + { + "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", "/=", "/", + "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", ">>=", ">>", + "<=", "<", ">=", ">", "~", "&=", "&", "|=", "||", "|", "^=", "^", + "=", "()", "[]", ",", "new", "delete" + /* new[] and delete[] require special whitespace handling */ + }; + /* Return 1 if STRING is clearly already in canonical form. This function is conservative; things which it does not recognize are assumed to be non-canonical, and the parser will sort them out @@ -175,7 +190,8 @@ mangled_name_to_comp (const char *mangled_name, int options, return ret; } -/* Return the name of the class containing method PHYSNAME. */ +/* Return the name of the class or namespace containing + function, method, or variable PHYSNAME. */ char * cp_class_name_from_physname (const char *physname) @@ -825,9 +841,9 @@ read_in_psymtabs (const char *func_name) if (ps->readin) continue; - if ((lookup_partial_symbol (ps, func_name, NULL, 1, VAR_DOMAIN) + if ((lookup_partial_symbol (ps, func_name, 1, VAR_DOMAIN) != NULL) - || (lookup_partial_symbol (ps, func_name, NULL, 0, VAR_DOMAIN) + || (lookup_partial_symbol (ps, func_name, 0, VAR_DOMAIN) != NULL)) psymtab_to_symtab (ps); } @@ -909,6 +925,72 @@ first_component_command (char *arg, int from_tty) extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */ +#define SKIP_SPACE(P) \ + do \ + { \ + while (*(P) == ' ' || *(P) == '\t') \ + ++(P); \ + } \ + while (0) + +/* Returns the length of the operator name or 0 if INPUT does not + point to a valid C++ operator. INPUT should start with "operator". */ +int +cp_validate_operator (const char *input) +{ + int i; + const char *p = input; + int valid = 0; + + /* Most callers appear to do this already, but since this is not + really time-critical code, it is double-checked here. */ + if (strncmp (p, "operator", 8) == 0) + { + p += 8; + + SKIP_SPACE (p); + for (i = 0; i < sizeof (operator_tokens) / sizeof (operator_tokens[0]); + ++i) + { + int length = strlen (operator_tokens[i]); + /* By using strncmp here, we MUST have operator_tokens ordered! + See additional notes where operator_tokens is defined above. */ + if (strncmp (p, operator_tokens[i], length) == 0) + { + const char *op = p; + valid = 1; + p += length; + + if (strncmp (op, "new", 3) == 0 + || strncmp (op, "delete", 6) == 0) + { + + /* Special case: new[] and delete[]. We must be careful + to swallow whitespace before/in "[]".*/ + SKIP_SPACE (p); + + if (*p == '[') + { + ++p; + SKIP_SPACE (p); + if (*p == ']') + ++p; + else + valid = 0; + } + } + + break; + } + } + + if (!valid) + p = input; + } + + return (p - input); +} + void _initialize_cp_support (void) { diff --git a/gdb/cp-support.h b/gdb/cp-support.h index b5a5c5f..3f48f98 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -38,15 +38,33 @@ struct demangle_component; /* This struct is designed to store data from using directives. It says that names from namespace IMPORT_SRC should be visible within - namespace IMPORT_DEST. IMPORT_DEST should always be a strict initial - substring of IMPORT_SRC. These form a linked list; NEXT is the next element - of the list. */ + namespace IMPORT_DEST. IMPORT_DEST should always be a strict initial + substring of IMPORT_SRC. These form a linked list; NEXT is the next + element of the list. ALIAS is set to a non empty string if the imported + namespace has been aliased.Eg: + namespace C=A::B; + ALIAS = "C" + DECLARATION is the name of the imported declaration, if this import + statement represents one. Eg: + using A::x; + Where x is variable in namespace A. declaration is set to x. +*/ struct using_direct { char *import_src; char *import_dest; + + char *alias; + + char *declaration; + + int line_number; + struct using_direct *next; + + /* Used during import search to temporarly mark this node as searced. */ + int searched; }; @@ -54,6 +72,7 @@ struct using_direct extern char *cp_canonicalize_string (const char *string); + extern char *cp_class_name_from_physname (const char *physname); extern char *method_name_from_physname (const char *physname); @@ -72,15 +91,23 @@ extern struct symbol **make_symbol_overload_list (const char *, extern struct type *cp_lookup_rtti_type (const char *name, struct block *block); +extern int cp_validate_operator (const char *input); + /* Functions/variables from cp-namespace.c. */ extern int cp_is_anonymous (const char *namespace); extern void cp_add_using_directive (const char *dest, - const char *src); + const char *src, + const char *alias, + const char *declaration, + const int line_number); extern struct using_direct *cp_add_using (const char *dest, const char *src, + const char *alias, + const char *declaration, + const int line_number, struct using_direct *next); extern void cp_initialize_namespace (void); @@ -97,15 +124,20 @@ extern void cp_set_block_scope (const struct symbol *symbol, extern void cp_scan_for_anonymous_namespaces (const struct symbol *symbol); extern struct symbol *cp_lookup_symbol_nonlocal (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain); +struct symbol *cp_lookup_symbol_imports (const char *scope, + const char *name, + const struct block *block, + const domain_enum domain, + int declaration_only, + int search_parents); + extern struct symbol *cp_lookup_symbol_namespace (const char *namespace, - const char *name, - const char *linkage_name, - const struct block *block, - const domain_enum domain); + const char *name, + const struct block *block, + const domain_enum domain); extern struct type *cp_lookup_nested_type (struct type *parent_type, const char *nested_name, diff --git a/gdb/dbxread.c b/gdb/dbxread.c index 7cb016d..bb9e35a 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -3581,6 +3581,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 4016acc..1042303 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -958,8 +958,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} @@ -1151,6 +1153,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} @@ -18465,7 +18477,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 @@ -18482,6 +18494,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 @@ -18743,8 +18760,6 @@ containing @code{end}. For example: @smallexample (@value{GDBP}) python -Type python script -End with a line saying just "end". >print 23 >end 23 @@ -18757,6 +18772,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 @@ -18764,6 +18787,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 @@ -18776,13 +18807,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. @end menu @@ -18809,6 +18844,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 @@ -18825,6 +18866,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 @@ -18836,6 +18878,28 @@ If no exception is raised, the return value is always an instance of @code{gdb.Value} (@pxref{Values From Inferior}). @end defun +@findex gdb.parse_and_eval +@defun parse_and_eval expression +Parse @var{expression} as an expression in the current language, +evaluate it, and return the result as a @code{gdb.Value}. +@var{expression} must be a string. +@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. @@ -18850,6 +18914,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 @@ -18986,6 +19055,13 @@ The type of this @code{gdb.Value}. The value of this attribute is a The following methods are provided: @table @code +@defmethod Value cast type +Cast the @code{gdb.Value} to the type represented by @var{type}, and +return a new @code{gdb.Value}. @var{type} must be a @code{gdb.Type} +object. If the cast cannot be performed for some reason, an exception +is thrown. +@end defmethod + @defmethod Value dereference For pointer data types, this method returns a new @code{gdb.Value} object whose contents is the object pointed to by the pointer. For example, if @@ -19057,6 +19133,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 @@ -19109,6 +19188,12 @@ This is @code{True} if the field is artificial, usually meaning that it was provided by the compiler and not the user. This attribute is always provided, and is @code{False} if the field is not artificial. +@item is_base_class +This is @code{True} if the field represents a base class of a C@t{++} +structure. This attribute is always provided, and is @code{False} +if the field is not a base class of the type on which @code{fields} was +called, or if that type was not a C@t{++} class. + @item bitsize If the field is packed, or is a bitfield, then this will have a non-zero value, which is the size of the field in bits. Otherwise, @@ -19161,7 +19246,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. @@ -19169,7 +19254,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 @@ -19523,6 +19609,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}). 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 @@ -19775,6 +19976,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 @@ -19879,6 +20209,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. @@ -19943,6 +20349,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 @@ -19951,10 +20365,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 Interpreters @@ -23306,6 +23728,8 @@ access this functionality: @item @strong{Operation} @tab @strong{Description} +@item @code{-enable-pretty-printing} +@tab enable Python-based pretty-printing @item @code{-var-create} @tab create a variable object @item @code{-var-delete} @@ -23334,6 +23758,8 @@ access this functionality: @tab update the variable and its children @item @code{-var-set-frozen} @tab set frozeness attribute +@item @code{-var-set-update-range} +@tab set range of children to display on update @end multitable In the next subsection we describe each operation in detail and suggest @@ -23341,6 +23767,23 @@ how it can be used. @subheading Description And Use of Operations on Variable Objects +@subheading The @code{-enable-pretty-printing} Command +@findex -enable-pretty-printing + +@smallexample +-enable-pretty-printing +@end smallexample + +@var{GDBN} allows Python-based visualizers to affect the output of the +MI variable object commands. However, because there was no way to +implement this in a fully backward-compatible way, a front end must +request that this functionality be enabled. + +Once sent, this command cannot be undone. + +Note that if Python support has not been compiled into @var{GDBN}, +this command will still succeed. + @subheading The @code{-var-create} Command @findex -var-create @@ -23473,7 +23916,7 @@ Returns the number of children of a variable object @var{name}: @subsubheading Synopsis @smallexample - -var-list-children [@var{print-values}] @var{name} + -var-list-children [@var{print-values}] @var{name} [@var{from} @var{to}] @end smallexample @anchor{-var-list-children} @@ -23486,6 +23929,12 @@ values; and if it is 2 or @code{--simple-values} print the name and value for simple data types and just the name for arrays, structures and unions. +@var{from} and @var{to}, if specified, indicate the range of children +to report. If @var{from} or @var{to} is less than zero, the range is +reset and all children will be reported. Otherwise, children starting +at @var{from} (zero-based) and ending just before @var{to} will be +reported. + For each child the following results are returned: @table @var @@ -23519,6 +23968,14 @@ Otherwise this result is not present. If the variable object is frozen, this variable will be present with a value of 1. @end table +The result may have its own attributes: + +@table @var +@item has_more +This is an integer attribute which is nonzero if there are children +remaining after the end of the selected range. +@end table + @subsubheading Example @smallexample @@ -23700,6 +24157,9 @@ With the @samp{*} parameter, if a variable object is bound to a currently running thread, it will not be updated, without any diagnostic. +If @code{-var-set-update-range} was previously used on a varobj, then +only the selected range of children will be reported. + @subsubheading Example @smallexample @@ -23767,6 +24227,32 @@ Unfreezing a variable does not update it, only subsequent (gdb) @end smallexample +@subheading The @code{-var-set-update-range} command +@findex -var-set-update-range +@anchor{-var-set-update-range} + +@subsubheading Synopsis + +@smallexample + -var-set-update-range @var{name} @var{from} @var{to} +@end smallexample + +Set the range of children to be returned by future invocations of +@code{-var-update}. + +@var{from} and @var{to} indicate the range of children to report. If +@var{from} or @var{to} is less than zero, the range is reset and all +children will be reported. Otherwise, children starting at @var{from} +(zero-based) and ending just before @var{to} will be reported. + +@subsubheading Example + +@smallexample +(gdb) +-var-set-update-range V 1 2 +^done +@end smallexample + @subheading The @code{-var-set-visualizer} command @findex -var-set-visualizer @anchor{-var-set-visualizer} diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index b1c0452..da24b98 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -2106,6 +2106,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 @@ -2198,6 +2210,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: @@ -2293,6 +2306,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}). @@ -2315,6 +2329,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 @@ -2329,6 +2344,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 @@ -2414,6 +2430,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 @@ -2485,6 +2502,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 @@ -2507,6 +2525,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 @@ -2518,10 +2537,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 4984f31..fcf1b5d 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -206,6 +206,11 @@ Either @value{GDBN} detached from the inferior, or the inferior exited. The argument @var{pid} identifies the inferior. @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 427f58f..e66f007 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; @@ -310,6 +311,13 @@ no_get_frame_base (void *baton, gdb_byte **start, size_t *length) } static CORE_ADDR +no_get_frame_cfa (void *baton) +{ + internal_error (__FILE__, __LINE__, + _("Support for DW_OP_call_frame_cfa is unimplemented")); +} + +static CORE_ADDR no_get_tls_address (void *baton, CORE_ADDR offset) { internal_error (__FILE__, __LINE__, @@ -363,14 +371,22 @@ execute_stack_op (gdb_byte *exp, ULONGEST len, int addr_size, ctx->read_reg = read_reg; ctx->read_mem = read_mem; ctx->get_frame_base = no_get_frame_base; + ctx->get_frame_cfa = no_get_frame_cfa; ctx->get_tls_address = no_get_tls_address; dwarf_expr_push (ctx, initial); dwarf_expr_eval (ctx, exp, len); result = dwarf_expr_fetch (ctx, 0); - if (ctx->in_reg) + if (ctx->location == DWARF_VALUE_REGISTER) result = read_reg (this_frame, result); + else if (ctx->location != DWARF_VALUE_MEMORY) + { + /* This is actually invalid DWARF, but if we ever do run across + it somehow, we might as well support it. So, instead, report + it as unimplemented. */ + error (_("Not implemented: computing unwound register using explicit value operator")); + } do_cleanups (old_chain); @@ -1250,6 +1266,16 @@ dwarf2_frame_base_sniffer (struct frame_info *this_frame) return NULL; } + +CORE_ADDR +dwarf2_frame_cfa (struct frame_info *this_frame) +{ + while (get_frame_type (this_frame) == INLINE_FRAME) + this_frame = get_prev_frame (this_frame); + if (! frame_unwinder_is (this_frame, &dwarf2_frame_unwind)) + error (_("can't compute CFA for this frame")); + return get_frame_base (this_frame); +} const struct objfile_data *dwarf2_frame_objfile_data; @@ -1539,6 +1565,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/dwarf2-frame.h b/gdb/dwarf2-frame.h index b203661..dd03d59 100644 --- a/gdb/dwarf2-frame.h +++ b/gdb/dwarf2-frame.h @@ -118,4 +118,8 @@ extern const struct frame_base * void dwarf2_frame_build_info (struct objfile *objfile); +/* Compute the DWARF CFA for a frame. */ + +CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame); + #endif /* dwarf2-frame.h */ diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 2721065..0644b46 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -125,8 +125,7 @@ dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n) /* Add a new piece to CTX's piece list. */ static void -add_piece (struct dwarf_expr_context *ctx, - int in_reg, CORE_ADDR value, ULONGEST size) +add_piece (struct dwarf_expr_context *ctx, ULONGEST size) { struct dwarf_expr_piece *p; @@ -141,9 +140,15 @@ add_piece (struct dwarf_expr_context *ctx, * sizeof (struct dwarf_expr_piece)); p = &ctx->pieces[ctx->num_pieces - 1]; - p->in_reg = in_reg; - p->value = value; + p->location = ctx->location; p->size = size; + if (p->location == DWARF_VALUE_LITERAL) + { + p->v.literal.data = ctx->data; + p->v.literal.length = ctx->len; + } + else + p->v.value = dwarf_expr_fetch (ctx, 0); } /* Evaluate the expression at ADDR (LEN bytes long) using the context @@ -287,6 +292,23 @@ signed_address_type (struct gdbarch *gdbarch, int addr_size) } } + +/* Check that the current operator is either at the end of an + expression, or that it is followed by a composition operator. */ + +static void +require_composition (gdb_byte *op_ptr, gdb_byte *op_end, const char *op_name) +{ + /* It seems like DW_OP_GNU_uninit should be handled here. However, + it doesn't seem to make sense for DW_OP_*_value, and it was not + checked at the other place that this function is called. */ + if (op_ptr != op_end && *op_ptr != DW_OP_piece && *op_ptr != DW_OP_bit_piece) + error (_("DWARF-2 expression error: `%s' operations must be " + "used either alone or in conjuction with DW_OP_piece " + "or DW_OP_bit_piece."), + op_name); +} + /* The engine for the expression evaluator. Using the context in CTX, evaluate the expression between OP_PTR and OP_END. */ @@ -295,8 +317,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, gdb_byte *op_ptr, gdb_byte *op_end) { enum bfd_endian byte_order = gdbarch_byte_order (ctx->gdbarch); - - ctx->in_reg = 0; + ctx->location = DWARF_VALUE_MEMORY; ctx->initialized = 1; /* Default is initialized. */ if (ctx->recursion_depth > ctx->max_recursion_depth) @@ -436,20 +457,36 @@ execute_stack_op (struct dwarf_expr_context *ctx, "used either alone or in conjuction with DW_OP_piece.")); result = op - DW_OP_reg0; - ctx->in_reg = 1; - + ctx->location = DWARF_VALUE_REGISTER; break; case DW_OP_regx: op_ptr = read_uleb128 (op_ptr, op_end, ®); - if (op_ptr != op_end && *op_ptr != DW_OP_piece) - error (_("DWARF-2 expression error: DW_OP_reg operations must be " - "used either alone or in conjuction with DW_OP_piece.")); + require_composition (op_ptr, op_end, "DW_OP_regx"); result = reg; - ctx->in_reg = 1; + ctx->location = DWARF_VALUE_REGISTER; break; + case DW_OP_implicit_value: + { + ULONGEST len; + op_ptr = read_uleb128 (op_ptr, op_end, &len); + if (op_ptr + len > op_end) + error (_("DW_OP_implicit_value: too few bytes available.")); + ctx->len = len; + ctx->data = op_ptr; + ctx->location = DWARF_VALUE_LITERAL; + op_ptr += len; + require_composition (op_ptr, op_end, "DW_OP_implicit_value"); + } + goto no_push; + + case DW_OP_stack_value: + ctx->location = DWARF_VALUE_STACK; + require_composition (op_ptr, op_end, "DW_OP_stack_value"); + goto no_push; + case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: @@ -513,12 +550,15 @@ execute_stack_op (struct dwarf_expr_context *ctx, specific this_base method. */ (ctx->get_frame_base) (ctx->baton, &datastart, &datalen); dwarf_expr_eval (ctx, datastart, datalen); + if (ctx->location == DWARF_VALUE_LITERAL + || ctx->location == DWARF_VALUE_STACK) + error (_("Not implemented: computing frame base using explicit value operator")); result = dwarf_expr_fetch (ctx, 0); - if (ctx->in_reg) + if (ctx->location == DWARF_VALUE_REGISTER) result = (ctx->read_reg) (ctx->baton, result); result = result + offset; ctx->stack_len = before_stack_len; - ctx->in_reg = 0; + ctx->location = DWARF_VALUE_MEMORY; } break; case DW_OP_dup: @@ -716,6 +756,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, } break; + case DW_OP_call_frame_cfa: + result = (ctx->get_frame_cfa) (ctx->baton); + break; + case DW_OP_GNU_push_tls_address: /* Variable is at a constant offset in the thread-local storage block into the objfile for the current thread and @@ -754,12 +798,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, /* Record the piece. */ op_ptr = read_uleb128 (op_ptr, op_end, &size); - addr_or_regnum = dwarf_expr_fetch (ctx, 0); - add_piece (ctx, ctx->in_reg, addr_or_regnum, size); + add_piece (ctx, size); - /* Pop off the address/regnum, and clear the in_reg flag. */ - dwarf_expr_pop (ctx); - ctx->in_reg = 0; + /* Pop off the address/regnum, and reset the location + type. */ + if (ctx->location != DWARF_VALUE_LITERAL) + dwarf_expr_pop (ctx); + ctx->location = DWARF_VALUE_MEMORY; } goto no_push; @@ -771,6 +816,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 2306e49..597c2de 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -23,6 +23,19 @@ #if !defined (DWARF2EXPR_H) #define DWARF2EXPR_H +/* The location of a value. */ +enum dwarf_value_location +{ + /* The piece is in memory. */ + DWARF_VALUE_MEMORY, + /* The piece is in a register. */ + DWARF_VALUE_REGISTER, + /* The piece is on the stack. */ + DWARF_VALUE_STACK, + /* The piece is a literal. */ + DWARF_VALUE_LITERAL +}; + /* The expression evaluator works with a dwarf_expr_context, describing its current state and its callbacks. */ struct dwarf_expr_context @@ -55,6 +68,9 @@ struct dwarf_expr_context expression evaluation is complete. */ void (*get_frame_base) (void *baton, gdb_byte **start, size_t *length); + /* Return the CFA for the frame. */ + CORE_ADDR (*get_frame_cfa) (void *baton); + /* Return the thread-local storage address for DW_OP_GNU_push_tls_address. */ CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset); @@ -67,19 +83,23 @@ 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 depth we'll tolerate before raising an error. */ int recursion_depth, max_recursion_depth; - /* Non-zero if the result is in a register. The register number - will be on the expression stack. */ - int in_reg; + /* Location of the value. */ + enum dwarf_value_location location; + + /* For VALUE_LITERAL, a the current literal value's length and + data. */ + ULONGEST len; + gdb_byte *data; /* Initialization status of variable: Non-zero if variable has been initialized; zero otherwise. */ @@ -90,9 +110,9 @@ struct dwarf_expr_context Each time DW_OP_piece is executed, we add a new element to the end of this array, recording the current top of the stack, the - current in_reg flag, and the size given as the operand to - DW_OP_piece. We then pop the top value from the stack, clear the - in_reg flag, and resume evaluation. + current location, and the size given as the operand to + DW_OP_piece. We then pop the top value from the stack, rest the + location, and resume evaluation. The Dwarf spec doesn't say whether DW_OP_piece pops the top value from the stack. We do, ensuring that clients of this interface @@ -103,12 +123,11 @@ struct dwarf_expr_context If an expression never uses DW_OP_piece, num_pieces will be zero. (It would be nice to present these cases as expressions yielding - a single piece, with in_reg clear, so that callers need not - distinguish between the no-DW_OP_piece and one-DW_OP_piece cases. - But expressions with no DW_OP_piece operations have no value to - place in a piece's 'size' field; the size comes from the - surrounding data. So the two cases need to be handled - separately.) */ + a single piece, so that callers need not distinguish between the + no-DW_OP_piece and one-DW_OP_piece cases. But expressions with + no DW_OP_piece operations have no value to place in a piece's + 'size' field; the size comes from the surrounding data. So the + two cases need to be handled separately.) */ int num_pieces; struct dwarf_expr_piece *pieces; }; @@ -117,13 +136,22 @@ struct dwarf_expr_context /* A piece of an object, as recorded by DW_OP_piece. */ struct dwarf_expr_piece { - /* If IN_REG is zero, then the piece is in memory, and VALUE is its address. - If IN_REG is non-zero, then the piece is in a register, and VALUE - is the register number. */ - int in_reg; - - /* This piece's address or register number. */ - CORE_ADDR value; + enum dwarf_value_location location; + + union + { + /* This piece's address or register number. */ + CORE_ADDR value; + + struct + { + /* A pointer to the data making up this piece, for literal + pieces. */ + gdb_byte *data; + /* The length of the available data. */ + ULONGEST length; + } literal; + } v; /* The length of the piece, in bytes. */ ULONGEST size; diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 1df6a9f..939f7a2 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -36,6 +36,7 @@ #include "dwarf2.h" #include "dwarf2expr.h" #include "dwarf2loc.h" +#include "dwarf2-frame.h" #include "gdb_string.h" #include "gdb_assert.h" @@ -115,6 +116,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. */ @@ -176,22 +180,40 @@ dwarf_expr_frame_base (void *baton, gdb_byte **start, size_t * length) *start = find_location_expression (symbaton, length, get_frame_address_in_block (frame)); } - 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)); +} + +static CORE_ADDR +dwarf_expr_frame_cfa (void *baton) +{ + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + return dwarf2_frame_cfa (debaton->frame); } /* Using the objfile specified in BATON, find the address for the @@ -204,6 +226,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; +} + /* Evaluate a location description, starting at DATA and with length SIZE, to find the current location of variable VAR in the context of FRAME. */ @@ -213,9 +358,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) { @@ -225,21 +369,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 = dwarf_expr_prep_ctx (frame, data, size, per_cu); - 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_tls_address = dwarf_expr_tls_address; - - dwarf_expr_eval (ctx, data, size); if (ctx->num_pieces > 0) { int i; @@ -251,36 +382,115 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, for (i = 0; i < ctx->num_pieces; i++) { struct dwarf_expr_piece *p = &ctx->pieces[i]; - if (p->in_reg) - { - struct gdbarch *arch = get_frame_arch (frame); - bfd_byte regval[MAX_REGISTER_SIZE]; - int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->value); - get_frame_register (frame, gdb_regnum, regval); - memcpy (contents + offset, regval, p->size); - } - else /* In memory? */ + switch (p->location) { - read_memory (p->value, contents + offset, p->size); + case DWARF_VALUE_REGISTER: + { + struct gdbarch *arch = get_frame_arch (frame); + bfd_byte regval[MAX_REGISTER_SIZE]; + int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, + p->v.value); + get_frame_register (frame, gdb_regnum, regval); + memcpy (contents + offset, regval, p->size); + } + break; + + case DWARF_VALUE_MEMORY: + read_memory (p->v.value, contents + offset, p->size); + break; + + case DWARF_VALUE_STACK: + { + gdb_byte bytes[sizeof (ULONGEST)]; + size_t n; + store_unsigned_integer (bytes, ctx->addr_size, + gdbarch_byte_order (ctx->gdbarch), + p->v.value); + n = p->size; + if (n > ctx->addr_size) + n = ctx->addr_size; + memcpy (contents + offset, bytes, n); + } + break; + + case DWARF_VALUE_LITERAL: + { + size_t n = p->size; + if (n > p->v.literal.length) + n = p->v.literal.length; + memcpy (contents + offset, p->v.literal.data, n); + } + break; + + default: + internal_error (__FILE__, __LINE__, _("invalid location type")); } offset += p->size; } } - else if (ctx->in_reg) - { - struct gdbarch *arch = get_frame_arch (frame); - CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0); - int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum); - retval = value_from_register (SYMBOL_TYPE (var), gdb_regnum, frame); - } else { - CORE_ADDR address = dwarf_expr_fetch (ctx, 0); - - retval = allocate_value (SYMBOL_TYPE (var)); - VALUE_LVAL (retval) = lval_memory; - set_value_lazy (retval, 1); - set_value_address (retval, address); + switch (ctx->location) + { + case DWARF_VALUE_REGISTER: + { + struct gdbarch *arch = get_frame_arch (frame); + CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0); + int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum); + retval = value_from_register (SYMBOL_TYPE (var), gdb_regnum, frame); + } + break; + + case DWARF_VALUE_MEMORY: + { + CORE_ADDR address = dwarf_expr_fetch (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); + set_value_address (retval, address); + } + break; + + case DWARF_VALUE_STACK: + { + gdb_byte bytes[sizeof (ULONGEST)]; + ULONGEST value = (ULONGEST) dwarf_expr_fetch (ctx, 0); + bfd_byte *contents; + size_t n = ctx->addr_size; + + store_unsigned_integer (bytes, ctx->addr_size, + gdbarch_byte_order (ctx->gdbarch), + value); + retval = allocate_value (SYMBOL_TYPE (var)); + contents = value_contents_raw (retval); + if (n > TYPE_LENGTH (SYMBOL_TYPE (var))) + n = TYPE_LENGTH (SYMBOL_TYPE (var)); + memcpy (contents, bytes, n); + } + break; + + case DWARF_VALUE_LITERAL: + { + bfd_byte *contents; + size_t n = ctx->len; + + retval = allocate_value (SYMBOL_TYPE (var)); + contents = value_contents_raw (retval); + if (n > TYPE_LENGTH (SYMBOL_TYPE (var))) + n = TYPE_LENGTH (SYMBOL_TYPE (var)); + memcpy (contents, ctx->data, n); + } + break; + + default: + internal_error (__FILE__, __LINE__, _("invalid location type")); + } } set_value_initialized (retval, ctx->initialized); @@ -330,6 +540,15 @@ needs_frame_frame_base (void *baton, gdb_byte **start, size_t * length) nf_baton->needs_frame = 1; } +/* CFA accesses require a frame. */ +static CORE_ADDR +needs_frame_frame_cfa (void *baton) +{ + struct needs_frame_baton *nf_baton = baton; + nf_baton->needs_frame = 1; + return 1; +} + /* Thread-local accesses do require a frame. */ static CORE_ADDR needs_frame_tls_address (void *baton, CORE_ADDR offset) @@ -362,11 +581,12 @@ dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size, ctx->read_reg = needs_frame_read_reg; ctx->read_mem = needs_frame_read_mem; ctx->get_frame_base = needs_frame_frame_base; + ctx->get_frame_cfa = needs_frame_frame_cfa; ctx->get_tls_address = needs_frame_tls_address; dwarf_expr_eval (ctx, data, size); - in_reg = ctx->in_reg; + in_reg = ctx->location == DWARF_VALUE_REGISTER; if (ctx->num_pieces > 0) { @@ -375,7 +595,7 @@ dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size, /* If the location has several pieces, and any of them are in registers, then we will need a frame to fetch them from. */ for (i = 0; i < ctx->num_pieces; i++) - if (ctx->pieces[i].in_reg) + if (ctx->pieces[i].location == DWARF_VALUE_REGISTER) in_reg = 1; } @@ -607,7 +827,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; } @@ -623,16 +843,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 0bfcfca..01018d6 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -71,5 +71,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 445bab8..42039ea 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -1,8 +1,7 @@ /* DWARF 2 debugging format support for GDB. Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, Inc. with support from Florida State University (under contract @@ -48,6 +47,12 @@ #include "gdbcmd.h" #include "block.h" #include "addrmap.h" +#include "f-lang.h" +#include "c-lang.h" +#include "jv-lang.h" +#include "typeprint.h" +#include "vec.h" +#include "block.h" #include #include "gdb_string.h" @@ -93,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 @@ -150,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 @@ -336,6 +344,19 @@ struct dwarf2_cu /* Field `ranges_offset' is filled in; flag as the value may be zero. */ unsigned int has_ranges_offset : 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 @@ -474,8 +495,8 @@ struct partial_die_info /* DWARF-2 tag for this DIE. */ ENUM_BITFIELD(dwarf_tag) tag : 16; - /* Language code associated with this DIE. This is only used - for the compilation unit DIE. */ + /* Language code associated with this DIE. This is only used + for the compilation unit DIE. */ unsigned int language : 8; /* Assorted flags describing the data found in this DIE. */ @@ -495,8 +516,7 @@ struct partial_die_info unsigned int has_byte_size : 1; /* The name of this DIE. Normally the value of DW_AT_name, but - sometimes DW_TAG_MIPS_linkage_name or a string computed in some - other fashion. */ + sometimes a default name for unnamed DIEs. */ char *name; char *dirname; @@ -691,6 +711,11 @@ struct field_info int nfnfields; }; +/* A vector used during linkage name generation. */ +typedef struct die_info *die_info_p; +DEF_VEC_P (die_info_p); +static VEC(die_info_p) *die_list; + /* One item on the queue of compilation units to read in full symbols for. */ struct dwarf2_queue_item @@ -802,7 +827,10 @@ static void scan_partial_symbols (struct partial_die_info *, static void add_partial_symbol (struct partial_die_info *, struct dwarf2_cu *); -static int pdi_needs_namespace (enum dwarf_tag tag); +static gdb_byte *read_comp_unit_head (struct comp_unit_head *, gdb_byte *, + bfd *); + +static int die_needs_namespace (struct die_info *, struct dwarf2_cu *); static void add_partial_namespace (struct partial_die_info *pdi, CORE_ADDR *lowpc, CORE_ADDR *highpc, @@ -827,6 +855,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 *); @@ -947,8 +979,13 @@ static struct type *tag_type_to_type (struct die_info *, struct dwarf2_cu *); static struct type *read_type_die (struct die_info *, struct dwarf2_cu *); +static void physname_prefix_1 (struct ui_file *, struct die_info *, + struct dwarf2_cu *); + static char *determine_prefix (struct die_info *die, struct dwarf2_cu *); +static char *physname_prefix (struct die_info *die, struct dwarf2_cu *); + static char *typename_concat (struct obstack *, const char *prefix, const char *suffix, @@ -966,7 +1003,8 @@ static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, struct partial_symtab *); static int dwarf2_get_pc_bounds (struct die_info *, - CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); + CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, + struct partial_symtab *pst); static void get_scope_pc_bounds (struct die_info *, CORE_ADDR *, CORE_ADDR *, @@ -990,17 +1028,25 @@ static void dwarf2_attach_fn_fields_to_type (struct field_info *, static void process_structure_scope (struct die_info *, struct dwarf2_cu *); -static const char *determine_class_name (struct die_info *die, - struct dwarf2_cu *cu); - static void read_common_block (struct die_info *, struct dwarf2_cu *); static void read_namespace (struct die_info *die, struct dwarf2_cu *); +static void read_import_statement (struct die_info *die, struct dwarf2_cu *); + 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 *); @@ -1036,6 +1082,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 *); @@ -1078,7 +1127,8 @@ static int is_ref_attr (struct attribute *); static unsigned int dwarf2_get_ref_die_offset (struct attribute *); -static int dwarf2_get_attr_constant_value (struct attribute *, int); +static CORE_ADDR dwarf2_get_attr_constant_value (struct attribute *, CORE_ADDR, + struct dwarf2_cu *); static struct die_info *follow_die_ref_or_sig (struct die_info *, struct attribute *, @@ -1150,6 +1200,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 *); @@ -1169,22 +1222,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 @@ -1277,10 +1339,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; @@ -1297,6 +1362,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) @@ -1326,8 +1392,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) { @@ -1348,26 +1419,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; @@ -1380,7 +1601,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; } @@ -1403,7 +1624,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; } @@ -1411,8 +1632,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 . @@ -1421,6 +1649,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; } @@ -1429,6 +1659,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 @@ -1666,11 +1909,7 @@ dwarf2_create_include_psymtab (char *name, struct partial_symtab *pst, /* Read the Line Number Program data and extract the list of files included by the source file represented by PST. Build an include - partial symtab for each of these included files. - - This procedure assumes that there *is* a Line Number Program in - the given CU. Callers should check that PDI->HAS_STMT_LIST is set - before calling this procedure. */ + partial symtab for each of these included files. */ static void dwarf2_build_include_psymtabs (struct dwarf2_cu *cu, @@ -1812,6 +2051,37 @@ lookup_signatured_type (struct objfile *objfile, ULONGEST sig) return entry; } +/* Find the base address of the compilation unit for range lists and + location lists. It will normally be specified by DW_AT_low_pc. + In DWARF-3 draft 4, the base address could be overridden by + DW_AT_entry_pc. It's been removed, but GCC still uses this for + compilation units with discontinuous ranges. */ + +static void +dwarf2_find_base_address (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + + cu->base_known = 0; + cu->base_address = 0; + + attr = dwarf2_attr (die, DW_AT_entry_pc, cu); + if (attr) + { + cu->base_address = DW_ADDR (attr); + cu->base_known = 1; + } + else + { + attr = dwarf2_attr (die, DW_AT_low_pc, cu); + if (attr) + { + cu->base_address = DW_ADDR (attr); + cu->base_known = 1; + } + } +} + /* Subroutine of process_type_comp_unit and dwarf2_build_psymtabs_hard to combine the common parts. Process a compilation unit for a psymtab. @@ -1878,7 +2148,7 @@ process_psymtab_comp_unit (struct objfile *objfile, } /* Set the language we're debugging. */ - set_cu_language (comp_unit_die.language, &cu); + set_cu_language (comp_unit_die.language, &cu); /* Allocate a new partial symbol table structure. */ pst = start_psymtab_common (objfile, objfile->section_offsets, @@ -1929,8 +2199,8 @@ process_psymtab_comp_unit (struct objfile *objfile, } else if (comp_unit_die.has_pc_info && comp_unit_die.lowpc < comp_unit_die.highpc) - /* Store the contiguous range if it is not empty; it can be empty for - CUs with no code. */ + /* Store the contiguous range; `DW_AT_ranges' range is stored above. The + range can be also empty for CUs with no code. */ addrmap_set_empty (objfile->psymtabs_addrmap, comp_unit_die.lowpc + baseaddr, comp_unit_die.highpc + baseaddr - 1, pst); @@ -2361,7 +2631,7 @@ partial_die_parent_scope (struct partial_die_info *pdi, ignoring them. */ complaint (&symfile_complaints, _("unhandled containing DIE tag %d for DIE at %d"), - parent->tag, pdi->offset); + parent->tag, real_pdi->offset); parent->scope = grandparent_scope; } @@ -2376,12 +2646,22 @@ partial_die_full_name (struct partial_die_info *pdi, struct dwarf2_cu *cu) { char *parent_scope; + struct partial_die_info *real_pdi; - parent_scope = partial_die_parent_scope (pdi, cu); - if (parent_scope == NULL) - return NULL; - else + /* We need to look at our parent DIE; if we have a DW_AT_specification, + then this means the parent of the specification DIE. + partial_die_parent_scope does this loop also, but we do it here + since we need to examine real_pdi->parent ourselves. */ + + real_pdi = pdi; + while (real_pdi->has_specification) + real_pdi = find_partial_die (real_pdi->spec_offset, cu); + + parent_scope = partial_die_parent_scope (real_pdi, cu); + if (parent_scope != NULL) return typename_concat (NULL, parent_scope, pdi->name, cu); + + return NULL; } static void @@ -2397,12 +2677,9 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - if (pdi_needs_namespace (pdi->tag)) - { - actual_name = partial_die_full_name (pdi, cu); - if (actual_name) - built_actual_name = 1; - } + actual_name = partial_die_full_name (pdi, cu); + if (actual_name) + built_actual_name = 1; if (actual_name == NULL) actual_name = pdi->name; @@ -2493,6 +2770,12 @@ 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), + 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: @@ -2534,22 +2817,6 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) break; } - /* Check to see if we should scan the name for possible namespace - info. Only do this if this is C++, if we don't have namespace - debugging info in the file, if the psym is of an appropriate type - (otherwise we'll have psym == NULL), and if we actually had a - mangled name to begin with. */ - - /* FIXME drow/2004-02-22: Why don't we do this for classes, i.e. the - cases which do not set PSYM above? */ - - if (cu->language == language_cplus - && cu->has_namespace_info == 0 - && psym != NULL - && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL) - cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym), - objfile); - if (built_actual_name) xfree (actual_name); } @@ -2559,9 +2826,9 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) name listed in the die. */ static int -pdi_needs_namespace (enum dwarf_tag tag) +die_needs_namespace (struct die_info *die, struct dwarf2_cu *cu) { - switch (tag) + switch (die->tag) { case DW_TAG_namespace: case DW_TAG_typedef: @@ -2571,7 +2838,23 @@ pdi_needs_namespace (enum dwarf_tag tag) case DW_TAG_union_type: case DW_TAG_enumeration_type: case DW_TAG_enumerator: + case DW_TAG_subprogram: + case DW_TAG_member: return 1; + + case DW_TAG_variable: + { + struct attribute *attr; + attr = dwarf2_attr (die, DW_AT_specification, cu); + if (attr) + return 1; + attr = dwarf2_attr (die, DW_AT_external, cu); + if (attr == NULL && die->parent->tag != DW_TAG_namespace) + return 0; + return 1; + } + break; + default: return 0; } @@ -2604,12 +2887,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 @@ -2700,27 +2983,6 @@ guess_structure_name (struct partial_die_info *struct_pdi, if (real_pdi->die_parent != NULL) return; - - while (child_pdi != NULL) - { - if (child_pdi->tag == DW_TAG_subprogram) - { - char *actual_class_name - = language_class_name_from_physname (cu->language_defn, - child_pdi->name); - if (actual_class_name != NULL) - { - struct_pdi->name - = obsavestring (actual_class_name, - strlen (actual_class_name), - &cu->comp_unit_obstack); - xfree (actual_class_name); - } - break; - } - - child_pdi = child_pdi->die_sibling; - } } } @@ -3170,7 +3432,6 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) CORE_ADDR lowpc, highpc; struct symtab *symtab; struct cleanup *back_to; - struct attribute *attr; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); @@ -3180,30 +3441,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) cu->list_in_scope = &file_symbols; - /* Find the base address of the compilation unit for range lists and - location lists. It will normally be specified by DW_AT_low_pc. - In DWARF-3 draft 4, the base address could be overridden by - DW_AT_entry_pc. It's been removed, but GCC still uses this for - compilation units with discontinuous ranges. */ - - cu->base_known = 0; - cu->base_address = 0; - - attr = dwarf2_attr (cu->dies, DW_AT_entry_pc, cu); - if (attr) - { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; - } - else - { - attr = dwarf2_attr (cu->dies, DW_AT_low_pc, cu); - if (attr) - { - cu->base_address = DW_ADDR (attr); - cu->base_known = 1; - } - } + dwarf2_find_base_address (cu->dies, cu); /* Do line number decoding in read_file_scope () */ process_die (cu->dies, cu); @@ -3234,6 +3472,7 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) static void process_die (struct die_info *die, struct dwarf2_cu *cu) { + switch (die->tag) { case DW_TAG_padding: @@ -3297,6 +3536,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"), @@ -3312,42 +3559,69 @@ process_die (struct die_info *die, struct dwarf2_cu *cu) /* Return the fully qualified name of DIE, based on its DW_AT_name. If scope qualifiers are appropriate they will be added. The result will be allocated on the objfile_obstack, or NULL if the DIE does - not have a name. */ + not have a name. + + The output string will be canonicalized (if C++/Java). */ static const char * dwarf2_full_name (struct die_info *die, struct dwarf2_cu *cu) { - struct attribute *attr; - char *prefix, *name; - struct ui_file *buf = NULL; + char *name; name = dwarf2_name (die, cu); - if (!name) - return NULL; /* These are the only languages we know how to qualify names in. */ - if (cu->language != language_cplus - && cu->language != language_java) - return name; + if (name != NULL + && (cu->language == language_cplus || cu->language == language_java)) + { + if (die_needs_namespace (die, cu)) + { + long length; + char *prefix; + struct ui_file *buf; - /* If no prefix is necessary for this type of DIE, return the - unqualified name. The other three tags listed could be handled - in pdi_needs_namespace, but that requires broader changes. */ - if (!pdi_needs_namespace (die->tag) - && die->tag != DW_TAG_subprogram - && die->tag != DW_TAG_variable - && die->tag != DW_TAG_member) - return name; + buf = mem_fileopen (); + prefix = determine_prefix (die, cu); + if (*prefix != '\0') + { + char *prefixed_name = typename_concat (NULL, prefix, name, cu); + fputs_unfiltered (prefixed_name, buf); + xfree (prefixed_name); + } + else + fputs_unfiltered (name, buf); - prefix = determine_prefix (die, cu); - if (*prefix != '\0') - name = typename_concat (&cu->objfile->objfile_obstack, prefix, - name, cu); + name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, + &length); + ui_file_delete (buf); + + if (cu->language == language_cplus) + { + char *cname + = dwarf2_canonicalize_name (name, cu, + &cu->objfile->objfile_obstack); + if (cname != NULL) + name = cname; + } + } + } return name; } -/* Read the import statement specified by the given die and record it. */ +/* read the given die's decl_line number. Return -1 if in case of an error */ +static const int dwarf2_read_decl_line (struct die_info *die, struct dwarf2_cu *cu){ + struct attribute *line_attr; + + line_attr = dwarf2_attr (die, DW_AT_decl_line, cu); + if (line_attr){ + return DW_UNSND (line_attr); + } + + return -1; +} + +/* Read the import statement specified by the given die and record it. */ static void read_import_statement (struct die_info *die, struct dwarf2_cu *cu) @@ -3356,9 +3630,15 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu) struct die_info *imported_die; const char *imported_name; const char *imported_name_prefix; - const char *import_prefix; char *canonical_name; - + const char *import_alias; + const char *imported_declaration = ""; + const char *import_prefix; + + int line_number = -1; + + int is_anonymous = 0; + import_attr = dwarf2_attr (die, DW_AT_import, cu); if (import_attr == NULL) { @@ -3406,29 +3686,45 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu) return; } - /* FIXME: dwarf2_name (die); for the local name after import. */ - - /* Figure out where the statement is being imported to. */ + /* Figure out the local name after import. */ + import_alias = dwarf2_name(die, cu); + if(import_alias == NULL){ + import_alias = ""; + } + + /* Determine the line number at which the import was made */ + line_number = dwarf2_read_decl_line(die, cu); + + /* Figure out where the statement is being imported to */ import_prefix = determine_prefix (die, cu); - /* Figure out what the scope of the imported die is and prepend it - to the name of the imported die. */ + /* + Figure out what the scope of the imported die is and prepend it + to the name of the imported die + */ imported_name_prefix = determine_prefix (imported_die, cu); - - if (strlen (imported_name_prefix) > 0) - { + + if(imported_die->tag != DW_TAG_namespace){ + imported_declaration = imported_name; + canonical_name = (char*)imported_name_prefix; + }else{ + if(strlen (imported_name_prefix) > 0){ canonical_name = alloca (strlen (imported_name_prefix) + 2 + strlen (imported_name) + 1); strcpy (canonical_name, imported_name_prefix); strcat (canonical_name, "::"); strcat (canonical_name, imported_name); - } - else - { + }else{ canonical_name = alloca (strlen (imported_name) + 1); strcpy (canonical_name, imported_name); } - - using_directives = cp_add_using (import_prefix,canonical_name, using_directives); + } + + using_directives = cp_add_using (import_prefix, + canonical_name, + import_alias, + imported_declaration, + line_number, + using_directives); } static void @@ -3676,7 +3972,7 @@ unsigned_int_compar (const void *ap, const void *bp) return (a > b) - (b > a); } - + /* DW_AT_abstract_origin inherits whole DIEs (not just their attributes). Inherit only the children of the DW_AT_abstract_origin DIE not being already referenced by DW_AT_abstract_origin from the children of the current DIE. */ @@ -3697,6 +3993,14 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu) struct attribute *attr; attr = dwarf2_attr (die, DW_AT_abstract_origin, cu); + + /* GCC 4.3 incorrectly uses DW_AT_specification to indicate die inheritence + in the case of import statements. The following is to accommodate + that. */ + if(!attr){ + attr = dwarf2_attr (die, DW_AT_specification, cu); + } + if (!attr) return; @@ -3795,6 +4099,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) char *name; CORE_ADDR baseaddr; struct block *block; + unsigned die_children = 0; int inlined_func = (die->tag == DW_TAG_inlined_subroutine); if (inlined_func) @@ -3813,13 +4118,23 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - name = dwarf2_linkage_name (die, cu); + name = dwarf2_name (die, cu); /* Ignore functions with missing or empty names and functions with missing or invalid low and high pc attributes. */ - if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) + if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)){ + /* explore abstract origins if present. They might contain useful information + such as import statements. */ + child_die = die->child; + while (child_die && child_die->tag) + { + child_die = sibling_die (child_die); + die_children++; + } + inherit_abstract_dies(die, cu); return; - + } + lowpc += baseaddr; highpc += baseaddr; @@ -3846,14 +4161,19 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) cu->list_in_scope = &local_symbols; - if (die->child != NULL) + switch (cu->language) { - child_die = die->child; - while (child_die && child_die->tag) - { - process_die (child_die, cu); - child_die = sibling_die (child_die); - } + case language_fortran: + cu->language_specific.fortran.use = NULL; + break; + } + + child_die = die->child; + while (child_die && child_die->tag) + { + process_die (child_die, cu); + child_die = sibling_die (child_die); + die_children++; } inherit_abstract_dies (die, cu); @@ -3869,6 +4189,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); @@ -3905,7 +4232,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) as multiple lexical blocks? Handling children in a sane way would be nasty. Might be easier to properly extend generic blocks to describe ranges. */ - if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) + if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)) return; lowpc += baseaddr; highpc += baseaddr; @@ -3922,7 +4249,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) } new = pop_context (); - if (local_symbols != NULL) + if (local_symbols != NULL || using_directives != NULL) { struct block *block = finish_block (0, &local_symbols, new->old_blocks, new->start_addr, @@ -4077,7 +4404,8 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, discontinuous, i.e. derived from DW_AT_ranges information. */ static int dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, - CORE_ADDR *highpc, struct dwarf2_cu *cu) + CORE_ADDR *highpc, struct dwarf2_cu *cu, + struct partial_symtab *pst) { struct attribute *attr; CORE_ADDR low = 0; @@ -4105,7 +4433,7 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, { /* Value of the DW_AT_ranges attribute is the offset in the .debug_ranges section. */ - if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, NULL)) + if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, pst)) return 0; /* Found discontinuous range of addresses. */ ret = -1; @@ -4144,7 +4472,7 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die, CORE_ADDR low, high; struct die_info *child = die->child; - if (dwarf2_get_pc_bounds (die, &low, &high, cu)) + if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL)) { *lowpc = min (*lowpc, low); *highpc = max (*highpc, high); @@ -4181,7 +4509,7 @@ get_scope_pc_bounds (struct die_info *die, CORE_ADDR best_high = (CORE_ADDR) 0; CORE_ADDR current_low, current_high; - if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu)) + if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu, NULL)) { best_low = current_low; best_high = current_high; @@ -4384,21 +4712,8 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, /* Get bit offset of field. */ attr = dwarf2_attr (die, DW_AT_data_member_location, cu); if (attr) - { - int byte_offset; - - if (attr_form_is_section_offset (attr)) - { - dwarf2_complex_location_expr_complaint (); - byte_offset = 0; - } - else if (attr_form_is_constant (attr)) - byte_offset = dwarf2_get_attr_constant_value (attr, 0); - else - byte_offset = decode_locdesc (DW_BLOCK (attr), cu); - - SET_FIELD_BITPOS (*fp, byte_offset * bits_per_byte); - } + SET_FIELD_BITPOS (*fp, dwarf2_get_attr_constant_value (attr, 0, cu) + * bits_per_byte); attr = dwarf2_attr (die, DW_AT_bit_offset, cu); if (attr) { @@ -4476,7 +4791,11 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, if (fieldname == NULL) return; - /* Get physical name. */ + /* Get physical name. We prefer the linkage name if one was specified, + because this lets GDB find a non-debugging version of the symbol. + Otherwise construct the full name from type information. Ideally, + when GDB supports canonicalization of C++ symbol names, we will not + need the linkage name for anything. */ physname = dwarf2_linkage_name (die, cu); /* The name is already allocated along with this objfile, so we don't @@ -4490,7 +4809,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, /* C++ base class field. */ attr = dwarf2_attr (die, DW_AT_data_member_location, cu); if (attr) - SET_FIELD_BITPOS (*fp, decode_locdesc (DW_BLOCK (attr), cu) + SET_FIELD_BITPOS (*fp, dwarf2_get_attr_constant_value (attr, 0, cu) * bits_per_byte); FIELD_BITSIZE (*fp) = 0; FIELD_TYPE (*fp) = die_type (die, cu); @@ -4607,7 +4926,11 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, if (fieldname == NULL) return; - /* Get the mangled name. */ + /* Get physical name. We prefer the linkage name if one was specified, + because this lets GDB find a non-debugging version of the symbol. + Otherwise construct the full name from type information. Ideally, + when GDB supports canonicalization of C++ symbol names, we will not + need the linkage name for anything. */ physname = dwarf2_linkage_name (die, cu); /* Look up member function name in fieldlist. */ @@ -4652,7 +4975,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ fnp->physname = physname ? physname : ""; - fnp->type = alloc_type (objfile); + fnp->type = alloc_type (objfile, NULL); this_type = read_type_die (die, cu); if (this_type && TYPE_CODE (this_type) == TYPE_CODE_FUNC) { @@ -4709,22 +5032,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, /* Get index in virtual function table if it is a virtual member function. */ attr = dwarf2_attr (die, DW_AT_vtable_elem_location, cu); if (attr) - { - /* Support the .debug_loc offsets */ - if (attr_form_is_block (attr)) - { - fnp->voffset = decode_locdesc (DW_BLOCK (attr), cu) + 2; - } - else if (attr_form_is_section_offset (attr)) - { - dwarf2_complex_location_expr_complaint (); - } - else - { - dwarf2_invalid_attrib_class_complaint ("DW_AT_vtable_elem_location", - fieldname); - } - } + fnp->voffset = dwarf2_get_attr_constant_value (attr, -2, cu) + 2; } /* Create the vector of member function fields, and attach it to the type. */ @@ -4836,7 +5144,7 @@ quirk_gcc_member_function_pointer (struct die_info *die, struct dwarf2_cu *cu) return NULL; domain_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (pfn_type, 0)); - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type), TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type), TYPE_VARARGS (pfn_type)); @@ -4889,7 +5197,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, type, cu); } - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); INIT_CPLUS_SPECIFIC (type); name = dwarf2_name (die, cu); @@ -4898,14 +5206,18 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) if (cu->language == language_cplus || cu->language == language_java) { - const char *new_prefix = determine_class_name (die, cu); - TYPE_TAG_NAME (type) = (char *) new_prefix; + TYPE_TAG_NAME (type) = (char *) dwarf2_full_name (die, cu); + if (die->tag == DW_TAG_structure_type + || die->tag == DW_TAG_class_type) + TYPE_NAME (type) = TYPE_TAG_NAME (type); } else { /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ - TYPE_TAG_NAME (type) = name; + TYPE_TAG_NAME (type) = (char *) name; + if (die->tag == DW_TAG_class_type) + TYPE_NAME (type) = TYPE_TAG_NAME (type); } } @@ -5115,7 +5427,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, type, cu); } - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); TYPE_CODE (type) = TYPE_CODE_ENUM; name = dwarf2_full_name (die, cu); @@ -5143,51 +5455,6 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, type, cu); } -/* Determine the name of the type represented by DIE, which should be - a named C++ or Java compound type. Return the name in question, - allocated on the objfile obstack. */ - -static const char * -determine_class_name (struct die_info *die, struct dwarf2_cu *cu) -{ - const char *new_prefix = NULL; - - /* If we don't have namespace debug info, guess the name by trying - to demangle the names of members, just like we did in - guess_structure_name. */ - if (!processing_has_namespace_info) - { - struct die_info *child; - - for (child = die->child; - child != NULL && child->tag != 0; - child = sibling_die (child)) - { - if (child->tag == DW_TAG_subprogram) - { - char *phys_prefix - = language_class_name_from_physname (cu->language_defn, - dwarf2_linkage_name - (child, cu)); - - if (phys_prefix != NULL) - { - new_prefix - = obsavestring (phys_prefix, strlen (phys_prefix), - &cu->objfile->objfile_obstack); - xfree (phys_prefix); - break; - } - } - } - } - - if (new_prefix == NULL) - new_prefix = dwarf2_full_name (die, cu); - - return new_prefix; -} - /* Given a pointer to a die which begins an enumeration, process all the dies that define the members of the enumeration, and create the symbol for the enumeration type. @@ -5265,6 +5532,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. */ @@ -5278,7 +5568,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; @@ -5325,16 +5615,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 @@ -5401,49 +5686,83 @@ read_set_type (struct die_info *die, struct dwarf2_cu *cu) return set_die_type (die, set_type, cu); } -/* First cut: install each common block member as a global variable. */ +/* Create appropriate locally-scoped variables for all the DW_TAG_common_block + entries. Create also TYPE_CODE_STRUCT listing all such variables to be + available for `info common'. COMMON_BLOCK_DOMAIN is used to sepate the + common blocks name namespace from regular variable names. */ static void read_common_block (struct die_info *die, struct dwarf2_cu *cu) { - struct die_info *child_die; struct attribute *attr; struct symbol *sym; CORE_ADDR base = (CORE_ADDR) 0; attr = dwarf2_attr (die, DW_AT_location, cu); if (attr) - { - /* Support the .debug_loc offsets */ - if (attr_form_is_block (attr)) - { - base = decode_locdesc (DW_BLOCK (attr), cu); - } - else if (attr_form_is_section_offset (attr)) - { - dwarf2_complex_location_expr_complaint (); - } - else - { - dwarf2_invalid_attrib_class_complaint ("DW_AT_location", - "common block member"); - } - } + base = dwarf2_get_attr_constant_value (attr, 0, cu); if (die->child != NULL) { + struct objfile *objfile = cu->objfile; + struct die_info *child_die; + struct type *type; + struct field *field; + char *name; + struct symbol *sym; + + type = alloc_type (objfile, NULL); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + /* Artificial type to be used only by `info common'. */ + TYPE_NAME (type) = ""; + + child_die = die->child; + while (child_die && child_die->tag) + { + TYPE_NFIELDS (type)++; + child_die = sibling_die (child_die); + } + + TYPE_FIELDS (type) = obstack_alloc (&objfile->objfile_obstack, + sizeof (*TYPE_FIELDS (type)) + * TYPE_NFIELDS (type)); + memset (TYPE_FIELDS (type), 0, sizeof (*TYPE_FIELDS (type)) + * TYPE_NFIELDS (type)); + + field = TYPE_FIELDS (type); child_die = die->child; while (child_die && child_die->tag) { + /* Create the symbol in the DW_TAG_common_block block in the current + symbol scope. */ sym = new_symbol (child_die, NULL, cu); + + /* Undocumented in DWARF3, when it can be present? */ attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu); if (attr) { SYMBOL_VALUE_ADDRESS (sym) = - base + decode_locdesc (DW_BLOCK (attr), cu); + base + dwarf2_get_attr_constant_value (attr, 0, cu); add_symbol_to_list (sym, &global_symbols); } + + if (SYMBOL_CLASS (sym) == LOC_STATIC) + SET_FIELD_PHYSADDR (*field, SYMBOL_VALUE_ADDRESS (sym)); + else + SET_FIELD_PHYSNAME (*field, SYMBOL_LINKAGE_NAME (sym)); + FIELD_TYPE (*field) = SYMBOL_TYPE (sym); + FIELD_NAME (*field) = SYMBOL_NATURAL_NAME (sym); + field++; child_die = sibling_die (child_die); } + + /* TYPE_LENGTH (type) is left 0 - it is only a virtual structure even + with no consecutive address space. */ + + sym = new_symbol (die, type, cu); + /* SYMBOL_VALUE_ADDRESS never gets used as all its fields are static. */ + SYMBOL_VALUE_ADDRESS (sym) = base; + + set_die_type (die, type, cu); } } @@ -5511,7 +5830,7 @@ read_namespace (struct die_info *die, struct dwarf2_cu *cu) if (is_anonymous) { const char *previous_prefix = determine_prefix (die, cu); - cp_add_using_directive (previous_prefix, TYPE_NAME (type)); + cp_add_using_directive (previous_prefix, TYPE_NAME (type), "", "", dwarf2_read_decl_line(die, cu)); } } @@ -5527,20 +5846,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; + + type = read_module_type (die, cu); + + if (type) + new_symbol (die, type, cu); +} - /* FIXME: Support the separate Fortran module namespaces. */ +/* 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) + (sym)->ginfo.language_specific.cplus_specific.demangled_name = rename; } /* Return the name of the namespace represented by DIE. Set @@ -5705,29 +6159,114 @@ 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, NULL); + /* 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_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = 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_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = + 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, + cu); 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); @@ -5822,7 +6361,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; @@ -5930,8 +6468,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) struct type *base_type; struct type *range_type; struct attribute *attr; - int low = 0; - int high = -1; + int low; char *name; base_type = die_type (die, cu); @@ -5944,42 +6481,91 @@ 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); - /* 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_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 0); + TYPE_FIELD_DWARF_BLOCK (range_type, 0) = 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, cu); + 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; + } + } + 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; - } + 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. */ + } + + if (attr && attr_form_is_block (attr)) + { + TYPE_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 1); + TYPE_FIELD_DWARF_BLOCK (range_type, 1) = 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, + cu); else - high = dwarf2_get_attr_constant_value (attr, 1); + { + TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) = 1; + TYPE_HIGH_BOUND (range_type) = low - 1; + } } - range_type = create_range_type (NULL, base_type, low, high); + /* 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_RANGE_BOUND_SET_DWARF_BLOCK (range_type, 2); + TYPE_FIELD_DWARF_BLOCK (range_type, 2) = 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, + cu); + 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) @@ -6450,6 +7036,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. */ @@ -6670,9 +7257,6 @@ read_partial_die (struct partial_die_info *part_die, if (part_die->dirname == NULL) part_die->dirname = DW_STRING (&attr); break; - case DW_AT_MIPS_linkage_name: - part_die->name = DW_STRING (&attr); - break; case DW_AT_low_pc: has_low_pc_attr = 1; part_die->lowpc = DW_ADDR (&attr); @@ -6744,10 +7328,10 @@ read_partial_die (struct partial_die_info *part_die, else part_die->sibling = buffer + dwarf2_get_ref_die_offset (&attr); break; - case DW_AT_stmt_list: - part_die->has_stmt_list = 1; - part_die->line_offset = DW_UNSND (&attr); - break; + case DW_AT_stmt_list: + part_die->has_stmt_list = 1; + part_die->line_offset = DW_UNSND (&attr); + break; case DW_AT_byte_size: part_die->has_byte_size = 1; break; @@ -6789,13 +7373,6 @@ read_partial_die (struct partial_die_info *part_die, || dwarf2_per_objfile->has_section_at_zero)) part_die->has_pc_info = 1; - if (base_address_type != base_address_none && !cu->base_known) - { - gdb_assert (part_die->tag == DW_TAG_compile_unit); - cu->base_known = 1; - cu->base_address = base_address; - } - return info_ptr; } @@ -6904,7 +7481,8 @@ fixup_partial_die (struct partial_die_info *part_die, /* If we found a reference attribute and the DIE has no name, try to find a name in the referred to DIE. */ - if (part_die->name == NULL && part_die->has_specification) + if (part_die->has_specification + && (part_die->name == NULL || !part_die->is_external)) { struct partial_die_info *spec_die; @@ -8244,10 +8822,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 @@ -8269,21 +8849,30 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - if (die->tag != DW_TAG_namespace) - name = dwarf2_linkage_name (die, cu); - else - name = TYPE_NAME (type); - + name = dwarf2_name (die, cu); if (name) { + const char *linkagename; + sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, 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), objfile); + + /* Cache this symbol's name and the name's demangled form (if any). */ + + linkagename = dwarf2_linkage_name (die, cu); + SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), objfile); + if (cu->language == language_fortran) + { + (sym)->ginfo.language_specific.cplus_specific.demangled_name = + 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. */ @@ -8381,9 +8970,28 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) if (attr) { var_decode_location (attr, sym, cu); + attr2 = dwarf2_attr (die, DW_AT_external, cu); + + /* Fortran explicitely imports any global symbols to the local + scope by DW_TAG_common_block. */ + if (cu->language == language_fortran && die->parent + && die->parent->tag == DW_TAG_common_block) + attr2 = NULL; + 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); } @@ -8513,7 +9121,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) add_symbol_to_list (sym, cu->list_in_scope); break; case DW_TAG_enumerator: - SYMBOL_LINKAGE_NAME (sym) = (char *) dwarf2_full_name (die, cu); + SYMBOL_LINKAGE_NAME (sym) = (char *) dwarf2_name (die, cu); attr = dwarf2_attr (die, DW_AT_const_value, cu); if (attr) { @@ -8537,6 +9145,16 @@ 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_common_block: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_DOMAIN (sym) = COMMON_BLOCK_DOMAIN; + add_symbol_to_list (sym, cu->list_in_scope); + 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 @@ -8550,8 +9168,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) /* For the benefit of old versions of GCC, check for anonymous namespaces based on the demangled name. */ if (!processing_has_namespace_info - && cu->language == language_cplus - && dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu) != NULL) + && cu->language == language_cplus) cp_scan_for_anonymous_namespaces (sym); } return (sym); @@ -8802,12 +9419,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; } @@ -8889,10 +9512,97 @@ determine_prefix (struct die_info *die, struct dwarf2_cu *cu) So it does not need a prefix. */ return ""; default: - return determine_prefix (parent, cu); + return determine_prefix (parent, cu); } } +/* Determines the prefix for a symbol's physname. Unlike determine_prefix, + this method does not simply look at the DIE's immediate parent. + It will compute the symbol's physname by scanning through all parent + DIEs until it gets to the compilation unit's DIE. */ + +static char * +physname_prefix (struct die_info *die, struct dwarf2_cu *cu) +{ + long length; + struct ui_file *buf; + struct die_info *d, *spec_die; + struct dwarf2_cu *spec_cu; + + /* Construct a stack containing all of the DIE's parents. Caution + must be observed for dealing with DW_AT_specification. */ + spec_cu = cu; + spec_die = die_specification (die, &spec_cu); + if (spec_die != NULL) + d = spec_die->parent; + else + d = die->parent; + while (d != NULL && d->tag != DW_TAG_compile_unit) + { + struct attribute *attr; + + spec_die = die_specification (d, &spec_cu); + if (spec_die != NULL) + d = spec_die; + + VEC_quick_push (die_info_p, die_list, d); + d = d->parent; + } + + /* Now pop all the elements, printing their names as we go */ + buf = mem_fileopen (); + while (!VEC_empty (die_info_p, die_list)) + { + d = VEC_pop (die_info_p, die_list); + physname_prefix_1 (buf, d, cu); + + if (!VEC_empty (die_info_p, die_list)) + { + if (cu->language == language_cplus) + fputs_unfiltered ("::", buf); + else + fputs_unfiltered (".", buf); + } + } + + return ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, &length); +} + +static void +physname_prefix_1 (struct ui_file *buf, struct die_info *die, + struct dwarf2_cu *cu) +{ + const char *name = NULL; + gdb_assert (buf != NULL); + + if (die != NULL) + { + switch (die->tag) + { + case DW_TAG_namespace: + name = dwarf2_name (die, cu); + if (name == NULL) + name = "(anonymous namespace)"; + break; + + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_enumeration_type: + case DW_TAG_interface_type: + case DW_TAG_subprogram: + name = dwarf2_name (die, cu); + break; + + default: + break; + } + } + + if (name != NULL) + fputs_unfiltered (name, buf); +} + /* Return a newly-allocated string formed by concatenating PREFIX and SUFFIX with appropriate separator. If PREFIX or SUFFIX is NULL or empty, then simply copy the SUFFIX or PREFIX, respectively. If OBS is non-null, @@ -8948,14 +9658,108 @@ static char * dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; + char *name; + + name = dwarf2_name (die, cu); + + /* These are the only languages we know how to qualify names in. */ + if (cu->language != language_cplus + && cu->language != language_java) + return name; + + if (die_needs_namespace (die, cu)) + { + long length; + char *prefix; + struct ui_file *buf; + + prefix = physname_prefix (die, cu); + buf = mem_fileopen (); + if (*prefix != '\0') + { + char *prefixed_name = typename_concat (NULL, prefix, name, cu); + fputs_unfiltered (prefixed_name, buf); + xfree (prefixed_name); + } + else + fputs_unfiltered (name ? name : "", buf); + + /* For Java and C++ methods, append formal parameter type + information. */ + if ((cu->language == language_cplus || cu->language == language_java) + && die->tag == DW_TAG_subprogram) + { + struct type *type = read_type_die (die, cu); - attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); - if (attr && DW_STRING (attr)) - return DW_STRING (attr); - return dwarf2_name (die, cu); + c_type_print_args (type, buf, 0, cu->language); + + if (cu->language == language_java) + { + /* For java, we must append the return type to method names. */ + if (die->tag == DW_TAG_subprogram) + java_print_type (TYPE_TARGET_TYPE (type), "", buf, 0, 0); + } + else if (cu->language == language_cplus) + { + /* c_type_print_args adds argument types, but it does + not add any necessary "const". */ + if (TYPE_NFIELDS (type) > 0 && TYPE_FIELD_ARTIFICIAL (type, 0) + && TYPE_CONST (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 0)))) + fputs_unfiltered (" const", buf); + } + } + + name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, + &length); + ui_file_delete (buf); + + if (cu->language == language_cplus) + { + char *cname + = dwarf2_canonicalize_name (name, cu, + &cu->objfile->objfile_obstack); + if (cname != NULL) + name = cname; + } + } + + return name; } -/* Get name of a die, return NULL if not found. */ +/* 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; +} + +/* Canonicalize the name of the given DIE. */ static char * dwarf2_canonicalize_name (char *name, struct dwarf2_cu *cu, @@ -10181,11 +10985,12 @@ dwarf2_get_ref_die_offset (struct attribute *attr) return 0; } -/* Return the constant value held by the given attribute. Return -1 +/* Return the constant value held by the given attribute. Return DEFAULT_VALUE if the value held by the attribute is not constant. */ -static int -dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) +static CORE_ADDR +dwarf2_get_attr_constant_value (struct attribute *attr, CORE_ADDR default_value, + struct dwarf2_cu *cu) { if (attr->form == DW_FORM_sdata) return DW_SND (attr); @@ -10195,6 +11000,8 @@ dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) || attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) return DW_UNSND (attr); + else if (attr_form_is_block (attr)) + return decode_locdesc (DW_BLOCK (attr), cu); else { complaint (&symfile_complaints, _("Attribute value is not a constant (%s)"), @@ -10990,8 +11797,6 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, { gdb_byte *mac_ptr, *mac_end; struct macro_source_file *current_file = 0; - enum dwarf_macinfo_record_type macinfo_type; - int at_commandline; if (dwarf2_per_objfile->macinfo.buffer == NULL) { @@ -10999,29 +11804,19 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, return; } - /* First pass: Find the name of the base filename. - This filename is needed in order to process all macros whose definition - (or undefinition) comes from the command line. These macros are defined - before the first DW_MACINFO_start_file entry, and yet still need to be - associated to the base file. - - To determine the base file name, we scan the macro definitions until we - reach the first DW_MACINFO_start_file entry. We then initialize - CURRENT_FILE accordingly so that any macro definition found before the - first DW_MACINFO_start_file can still be associated to the base file. */ - mac_ptr = dwarf2_per_objfile->macinfo.buffer + offset; mac_end = dwarf2_per_objfile->macinfo.buffer + dwarf2_per_objfile->macinfo.size; - do + for (;;) { + enum dwarf_macinfo_record_type macinfo_type; + /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { - /* Complaint is printed during the second pass as GDB will probably - stop the first pass earlier upon finding DW_MACINFO_start_file. */ - break; + dwarf2_macros_too_long_complaint (); + return; } macinfo_type = read_1_byte (abfd, mac_ptr); @@ -11032,92 +11827,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, /* A zero macinfo type indicates the end of the macro information. */ case 0: - break; - - case DW_MACINFO_define: - case DW_MACINFO_undef: - /* Only skip the data by MAC_PTR. */ - { - unsigned int bytes_read; - - read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - read_string (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - } - break; - - case DW_MACINFO_start_file: - { - unsigned int bytes_read; - int line, file; - - line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - - current_file = macro_start_file (file, line, current_file, comp_dir, - lh, cu->objfile); - } - break; - - case DW_MACINFO_end_file: - /* No data to skip by MAC_PTR. */ - break; - - case DW_MACINFO_vendor_ext: - /* Only skip the data by MAC_PTR. */ - { - unsigned int bytes_read; - - read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - read_string (abfd, mac_ptr, &bytes_read); - mac_ptr += bytes_read; - } - break; - - default: - break; - } - } while (macinfo_type != 0 && current_file == NULL); - - /* Second pass: Process all entries. - - Use the AT_COMMAND_LINE flag to determine whether we are still processing - command-line macro definitions/undefinitions. This flag is unset when we - reach the first DW_MACINFO_start_file entry. */ - - mac_ptr = dwarf2_per_objfile->macinfo.buffer + offset; - - /* Determines if GDB is still before first DW_MACINFO_start_file. If true - GDB is still reading the definitions from command line. First - DW_MACINFO_start_file will need to be ignored as it was already executed - to create CURRENT_FILE for the main source holding also the command line - definitions. On first met DW_MACINFO_start_file this flag is reset to - normally execute all the remaining DW_MACINFO_start_file macinfos. */ - - at_commandline = 1; - - do - { - /* Do we at least have room for a macinfo type byte? */ - if (mac_ptr >= mac_end) - { - dwarf2_macros_too_long_complaint (); - break; - } - - macinfo_type = read_1_byte (abfd, mac_ptr); - mac_ptr++; - - switch (macinfo_type) - { - /* A zero macinfo type indicates the end of the macro - information. */ - case 0: - break; + return; case DW_MACINFO_define: case DW_MACINFO_undef: @@ -11132,31 +11842,19 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, mac_ptr += bytes_read; if (! current_file) - { - /* DWARF violation as no main source is present. */ - complaint (&symfile_complaints, - _("debug info with no main source gives macro %s " - "on line %d: %s"), - macinfo_type == - DW_MACINFO_define ? _("definition") : macinfo_type == - DW_MACINFO_undef ? _("undefinition") : - "something-or-other", line, body); - break; - } - if ((line == 0 && !at_commandline) || (line != 0 && at_commandline)) complaint (&symfile_complaints, - _("debug info gives %s macro %s with %s line %d: %s"), - at_commandline ? _("command-line") : _("in-file"), + _("debug info gives macro %s outside of any file: %s"), macinfo_type == - DW_MACINFO_define ? _("definition") : macinfo_type == - DW_MACINFO_undef ? _("undefinition") : - "something-or-other", - line == 0 ? _("zero") : _("non-zero"), line, body); - - if (macinfo_type == DW_MACINFO_define) - parse_macro_definition (current_file, line, body); - else if (macinfo_type == DW_MACINFO_undef) - macro_undef (current_file, line, body); + DW_MACINFO_define ? "definition" : macinfo_type == + DW_MACINFO_undef ? "undefinition" : + "something-or-other", body); + else + { + if (macinfo_type == DW_MACINFO_define) + parse_macro_definition (current_file, line, body); + else if (macinfo_type == DW_MACINFO_undef) + macro_undef (current_file, line, body); + } } break; @@ -11170,22 +11868,9 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; - if ((line == 0 && !at_commandline) || (line != 0 && at_commandline)) - complaint (&symfile_complaints, - _("debug info gives source %d included " - "from %s at %s line %d"), - file, at_commandline ? _("command-line") : _("file"), - line == 0 ? _("zero") : _("non-zero"), line); - - if (at_commandline) - { - /* This DW_MACINFO_start_file was executed in the pass one. */ - at_commandline = 0; - } - else - current_file = macro_start_file (file, line, - current_file, comp_dir, - lh, cu->objfile); + current_file = macro_start_file (file, line, + current_file, comp_dir, + lh, cu->objfile); } break; @@ -11239,7 +11924,7 @@ dwarf_decode_macros (struct line_header *lh, unsigned int offset, } break; } - } while (macinfo_type != 0); + } } /* Check if the attribute's form is a DW_FORM_block* @@ -11299,6 +11984,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) @@ -11328,35 +12041,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; } } @@ -11644,6 +12347,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. */ @@ -11652,6 +12380,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); + if (cu->type_hash == NULL) { gdb_assert (cu->per_cu != NULL); @@ -11794,23 +12524,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. */ @@ -11819,15 +12539,15 @@ static void dwarf2_per_objfile_cleanup (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); @@ -11835,6 +12555,7 @@ void _initialize_dwarf2_read (void); void _initialize_dwarf2_read (void) { + die_list = VEC_alloc (die_info_p, 32); dwarf2_objfile_data_key = register_objfile_data_with_cleanup (dwarf2_per_objfile_cleanup); diff --git a/gdb/elfread.c b/gdb/elfread.c index 6e79d4a..198bae3 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -728,10 +728,18 @@ elf_symfile_read (struct objfile *objfile, int mainline) str_sect->filepos, bfd_section_size (abfd, str_sect)); } + + if (dwarf2_has_info (objfile)) + dwarf2_create_quick_addrmap (objfile); +} + +static void +read_psyms (struct objfile *objfile) +{ if (dwarf2_has_info (objfile)) { /* DWARF 2 sections */ - dwarf2_build_psymtabs (objfile, mainline); + dwarf2_build_psymtabs (objfile, 0); } /* FIXME: kettenis/20030504: This still needs to be integrated with @@ -881,6 +889,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 7e41d39..37ffe23 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -39,8 +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" @@ -651,6 +655,36 @@ ptrmath_type_p (struct type *type) } } +/* Constructs a fake method with the given parameter types. */ +static void +free_param_types (void *arg) +{ + struct type *type = (struct type *) arg; + xfree (TYPE_FIELDS (type)); + xfree (TYPE_MAIN_TYPE (type)); + xfree (type); +} + +static struct type * +make_params (int num_types, struct type **param_types) +{ + struct type *type = XZALLOC (struct type); + TYPE_MAIN_TYPE (type) = XZALLOC (struct main_type); + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_METHOD; + TYPE_VPTR_FIELDNO (type) = -1; + TYPE_CHAIN (type) = type; + TYPE_NFIELDS (type) = num_types; + TYPE_FIELDS (type) = (struct field *) + TYPE_ZALLOC (type, sizeof (struct field) * num_types); + + while (num_types-- > 0) + TYPE_FIELD_TYPE (type, num_types) = param_types[num_types]; + + make_cleanup (free_param_types, type); + return type; +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -671,6 +705,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; @@ -684,7 +719,7 @@ evaluate_subexp_standard (struct type *expect_type, goto nosideret; arg1 = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 0, noside); + expect_type, 0, noside); if (arg1 == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return arg1; @@ -1293,7 +1328,6 @@ evaluate_subexp_standard (struct type *expect_type, argvec = (struct value **) alloca (sizeof (struct value *) * (nargs + 3)); if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - nargs++; /* First, evaluate the structure into arg2 */ pc2 = (*pos)++; @@ -1317,21 +1351,40 @@ evaluate_subexp_standard (struct type *expect_type, arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); - if (TYPE_CODE (check_typedef (value_type (arg1))) - != TYPE_CODE_METHODPTR) - error (_("Non-pointer-to-member value used in pointer-to-member " - "construct")); - - if (noside == EVAL_AVOID_SIDE_EFFECTS) + type = check_typedef (value_type (arg1)); + switch (TYPE_CODE (type)) { - struct type *method_type = check_typedef (value_type (arg1)); - arg1 = value_zero (method_type, not_lval); + case TYPE_CODE_METHODPTR: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + arg1 = value_zero (TYPE_TARGET_TYPE (type), not_lval); + else + arg1 = cplus_method_ptr_to_value (&arg2, arg1); + + /* Now, say which argument to start evaluating from */ + nargs++; + tem = 2; + argvec[1] = arg2; + break; + + case TYPE_CODE_MEMBERPTR: + /* Now, convert these values to an address. */ + arg2 = value_cast (lookup_pointer_type (TYPE_DOMAIN_TYPE (type)), + arg2); + + mem_offset = value_as_long (arg1); + + arg1 = value_from_pointer (lookup_pointer_type (TYPE_TARGET_TYPE (type)), + value_as_long (arg2) + mem_offset); + arg1 = value_ind (arg1); + tem = 1; + break; + + default: + error (_("Non-pointer-to-member value used in pointer-to-member " + "construct")); } - else - arg1 = cplus_method_ptr_to_value (&arg2, arg1); - /* Now, say which argument to start evaluating from */ - tem = 2; + argvec[0] = arg1; } else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR) { @@ -1457,8 +1510,7 @@ evaluate_subexp_standard (struct type *expect_type, } else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR) { - argvec[1] = arg2; - argvec[0] = arg1; + /* Pointer to member. argvec is already set up. */ } else if (op == OP_VAR_VALUE) { @@ -1542,7 +1594,10 @@ 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)); + do_cleanups (old_chain); code = TYPE_CODE (type); if (code == TYPE_CODE_PTR) @@ -1709,6 +1764,37 @@ evaluate_subexp_standard (struct type *expect_type, error (_("non-pointer-to-member value used in pointer-to-member construct")); } + case TYPE_INSTANCE: + nargs = longest_to_int (exp->elts[pc + 1].longconst); + arg_types = (struct type **) alloca (nargs * sizeof (struct type *)); + for (ix = 0; ix < nargs; ++ix) + arg_types[ix] = exp->elts[pc + 1 + ix + 1].type; + + expect_type = make_params (nargs, arg_types); + *(pos) += 3 + nargs; + return evaluate_subexp_standard (expect_type, exp, pos, noside); + + case TYPE_INSTANCE_LOOKUP: + { + int i; + struct symbol *sym; + struct type **arg_types; + (*pos) += 3; + printf ("TYPE_INSTANCE_LOOKUP\n"); + arg_types = (struct type **) alloca (TYPE_NFIELDS (expect_type) + * sizeof (struct type *)); + for (i = 0; i < TYPE_NFIELDS (expect_type); ++i) + arg_types[i] = TYPE_FIELD_TYPE (expect_type, i); + (void) find_overload_match (arg_types, TYPE_NFIELDS (expect_type), + NULL /* no need for name */, + 0 /* not method */, + 0 /* strict match */, + NULL, exp->elts[pc + 1].symbol, NULL, + &sym, NULL); + i = 0; + } + break; + case BINOP_CONCAT: arg1 = evaluate_subexp_with_coercion (exp, pos, noside); arg2 = evaluate_subexp_with_coercion (exp, pos, noside); @@ -1980,13 +2066,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); @@ -2016,6 +2108,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. */ @@ -2034,13 +2129,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 @@ -2050,7 +2157,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: @@ -2591,7 +2698,7 @@ evaluate_subexp_for_address (struct expression *exp, int *pos, (*pos) += 5 + BYTES_TO_EXP_ELEM (tem + 1); x = value_aggregate_elt (exp->elts[pc + 1].type, &exp->elts[pc + 3].string, - 1, noside); + NULL, 1, noside); if (x == NULL) error (_("There is no field named %s"), &exp->elts[pc + 3].string); return x; @@ -2636,7 +2743,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; @@ -2647,12 +2754,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); } @@ -2704,9 +2816,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 12163e3..bf2b518 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -88,6 +88,16 @@ enum exp_opcode when X is a pointer instead of an aggregate. */ STRUCTOP_MPTR, + /* TYPE_INSTANCE is used when the user specifies a specific + type instantiation for overloaded methods/functions. The format + is: TYPE_INSTANCE num_types type0 ... typeN num_types TYPE_INSTANCE*/ + TYPE_INSTANCE, + + /* TYPE_INSTANCE_LOOKUP is used when the user specifies a specific + type instantiation of a function (not a method). In this case, + we must toss the results of the parser and manually do the lookup. */ + TYPE_INSTANCE_LOOKUP, + /* end of C++. */ /* For Modula-2 integer division DIV */ @@ -435,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-exp.y b/gdb/f-exp.y index c04c8f4..ddcd460 100644 --- a/gdb/f-exp.y +++ b/gdb/f-exp.y @@ -196,6 +196,7 @@ static int parse_number (char *, int, int, YYSTYPE *); /* Special type cases, put in to allow the parser to distinguish different legal basetypes. */ %token INT_KEYWORD INT_S2_KEYWORD LOGICAL_S1_KEYWORD LOGICAL_S2_KEYWORD +%token LOGICAL_S8_KEYWORD %token LOGICAL_KEYWORD REAL_KEYWORD REAL_S8_KEYWORD REAL_S16_KEYWORD %token COMPLEX_S8_KEYWORD COMPLEX_S16_KEYWORD COMPLEX_S32_KEYWORD %token BOOL_AND BOOL_OR BOOL_NOT @@ -606,6 +607,8 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */ { $$ = parse_f_type->builtin_integer_s2; } | CHARACTER { $$ = parse_f_type->builtin_character; } + | LOGICAL_S8_KEYWORD + { $$ = parse_f_type->builtin_logical_s8;} | LOGICAL_KEYWORD { $$ = parse_f_type->builtin_logical; } | LOGICAL_S2_KEYWORD @@ -858,6 +861,7 @@ static const struct token f77_keywords[] = { "integer_2", INT_S2_KEYWORD, BINOP_END }, { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END }, { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END }, + { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END }, { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END }, { "integer", INT_KEYWORD, BINOP_END }, { "logical", LOGICAL_KEYWORD, BINOP_END }, diff --git a/gdb/f-lang.c b/gdb/f-lang.c index 19c1316..4cc2a40 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. */ @@ -55,20 +57,6 @@ typedef struct saved_bf_symnum SAVED_BF, *SAVED_BF_PTR; /* Local functions */ extern void _initialize_f_language (void); -#if 0 -static void clear_function_list (void); -static long get_bf_for_fcn (long); -static void clear_bf_list (void); -static void patch_all_commons_by_name (char *, CORE_ADDR, int); -static SAVED_F77_COMMON_PTR find_first_common_named (char *); -static void add_common_entry (struct symbol *); -static void add_common_block (char *, CORE_ADDR, int, char *); -static SAVED_FUNCTION *allocate_saved_function_node (void); -static SAVED_BF_PTR allocate_saved_bf_node (void); -static COMMON_ENTRY_PTR allocate_common_entry_node (void); -static SAVED_F77_COMMON_PTR allocate_saved_f77_common_node (void); -static void patch_common_entries (SAVED_F77_COMMON_PTR, CORE_ADDR, int); -#endif static void f_printchar (int c, struct type *type, struct ui_file * stream); static void f_emit_char (int c, struct type *type, @@ -259,6 +247,7 @@ enum f_primitive_types { f_primitive_type_logical, f_primitive_type_logical_s1, f_primitive_type_logical_s2, + f_primitive_type_logical_s8, f_primitive_type_integer, f_primitive_type_integer_s2, f_primitive_type_real, @@ -289,6 +278,8 @@ f_language_arch_info (struct gdbarch *gdbarch, = builtin->builtin_logical_s1; lai->primitive_type_vector [f_primitive_type_logical_s2] = builtin->builtin_logical_s2; + lai->primitive_type_vector [f_primitive_type_logical_s8] + = builtin->builtin_logical_s8; lai->primitive_type_vector [f_primitive_type_real] = builtin->builtin_real; lai->primitive_type_vector [f_primitive_type_real_s8] @@ -306,6 +297,46 @@ 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 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, 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, 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 +364,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 */ @@ -372,6 +403,10 @@ build_fortran_types (struct gdbarch *gdbarch) = arch_boolean_type (gdbarch, gdbarch_short_bit (gdbarch), 1, "logical*2"); + builtin_f_type->builtin_logical_s8 + = arch_boolean_type (gdbarch, gdbarch_long_long_bit (gdbarch), 1, + "logical*8"); + builtin_f_type->builtin_integer = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), 0, "integer"); @@ -418,395 +453,3 @@ _initialize_f_language (void) add_language (&f_language_defn); } - -#if 0 -static SAVED_BF_PTR -allocate_saved_bf_node (void) -{ - SAVED_BF_PTR new; - - new = (SAVED_BF_PTR) xmalloc (sizeof (SAVED_BF)); - return (new); -} - -static SAVED_FUNCTION * -allocate_saved_function_node (void) -{ - SAVED_FUNCTION *new; - - new = (SAVED_FUNCTION *) xmalloc (sizeof (SAVED_FUNCTION)); - return (new); -} - -static SAVED_F77_COMMON_PTR -allocate_saved_f77_common_node (void) -{ - SAVED_F77_COMMON_PTR new; - - new = (SAVED_F77_COMMON_PTR) xmalloc (sizeof (SAVED_F77_COMMON)); - return (new); -} - -static COMMON_ENTRY_PTR -allocate_common_entry_node (void) -{ - COMMON_ENTRY_PTR new; - - new = (COMMON_ENTRY_PTR) xmalloc (sizeof (COMMON_ENTRY)); - return (new); -} -#endif - -SAVED_F77_COMMON_PTR head_common_list = NULL; /* Ptr to 1st saved COMMON */ -SAVED_F77_COMMON_PTR tail_common_list = NULL; /* Ptr to last saved COMMON */ -SAVED_F77_COMMON_PTR current_common = NULL; /* Ptr to current COMMON */ - -#if 0 -static SAVED_BF_PTR saved_bf_list = NULL; /* Ptr to (.bf,function) - list */ -static SAVED_BF_PTR saved_bf_list_end = NULL; /* Ptr to above list's end */ -static SAVED_BF_PTR current_head_bf_list = NULL; /* Current head of above list - */ - -static SAVED_BF_PTR tmp_bf_ptr; /* Generic temporary for use - in macros */ - -/* The following function simply enters a given common block onto - the global common block chain */ - -static void -add_common_block (char *name, CORE_ADDR offset, int secnum, char *func_stab) -{ - SAVED_F77_COMMON_PTR tmp; - char *c, *local_copy_func_stab; - - /* If the COMMON block we are trying to add has a blank - name (i.e. "#BLNK_COM") then we set it to __BLANK - because the darn "#" character makes GDB's input - parser have fits. */ - - - if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 - || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) - { - - xfree (name); - name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); - strcpy (name, BLANK_COMMON_NAME_LOCAL); - } - - tmp = allocate_saved_f77_common_node (); - - local_copy_func_stab = xmalloc (strlen (func_stab) + 1); - strcpy (local_copy_func_stab, func_stab); - - tmp->name = xmalloc (strlen (name) + 1); - - /* local_copy_func_stab is a stabstring, let us first extract the - function name from the stab by NULLing out the ':' character. */ - - - c = NULL; - c = strchr (local_copy_func_stab, ':'); - - if (c) - *c = '\0'; - else - error (_("Malformed function STAB found in add_common_block()")); - - - tmp->owning_function = xmalloc (strlen (local_copy_func_stab) + 1); - - strcpy (tmp->owning_function, local_copy_func_stab); - - strcpy (tmp->name, name); - tmp->offset = offset; - tmp->next = NULL; - tmp->entries = NULL; - tmp->secnum = secnum; - - current_common = tmp; - - if (head_common_list == NULL) - { - head_common_list = tail_common_list = tmp; - } - else - { - tail_common_list->next = tmp; - tail_common_list = tmp; - } -} -#endif - -/* The following function simply enters a given common entry onto - the "current_common" block that has been saved away. */ - -#if 0 -static void -add_common_entry (struct symbol *entry_sym_ptr) -{ - COMMON_ENTRY_PTR tmp; - - - - /* The order of this list is important, since - we expect the entries to appear in decl. - order when we later issue "info common" calls */ - - tmp = allocate_common_entry_node (); - - tmp->next = NULL; - tmp->symbol = entry_sym_ptr; - - if (current_common == NULL) - error (_("Attempt to add COMMON entry with no block open!")); - else - { - if (current_common->entries == NULL) - { - current_common->entries = tmp; - current_common->end_of_entries = tmp; - } - else - { - current_common->end_of_entries->next = tmp; - current_common->end_of_entries = tmp; - } - } -} -#endif - -/* This routine finds the first encountred COMMON block named "name" */ - -#if 0 -static SAVED_F77_COMMON_PTR -find_first_common_named (char *name) -{ - - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - while (tmp != NULL) - { - if (strcmp (tmp->name, name) == 0) - return (tmp); - else - tmp = tmp->next; - } - return (NULL); -} -#endif - -/* This routine finds the first encountred COMMON block named "name" - that belongs to function funcname */ - -SAVED_F77_COMMON_PTR -find_common_for_function (char *name, char *funcname) -{ - - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - while (tmp != NULL) - { - if (strcmp (tmp->name, name) == 0 - && strcmp (tmp->owning_function, funcname) == 0) - return (tmp); - else - tmp = tmp->next; - } - return (NULL); -} - - -#if 0 - -/* The following function is called to patch up the offsets - for the statics contained in the COMMON block named - "name." */ - -static void -patch_common_entries (SAVED_F77_COMMON_PTR blk, CORE_ADDR offset, int secnum) -{ - COMMON_ENTRY_PTR entry; - - blk->offset = offset; /* Keep this around for future use. */ - - entry = blk->entries; - - while (entry != NULL) - { - SYMBOL_VALUE (entry->symbol) += offset; - SYMBOL_SECTION (entry->symbol) = secnum; - - entry = entry->next; - } - blk->secnum = secnum; -} - -/* Patch all commons named "name" that need patching.Since COMMON - blocks occur with relative infrequency, we simply do a linear scan on - the name. Eventually, the best way to do this will be a - hashed-lookup. Secnum is the section number for the .bss section - (which is where common data lives). */ - -static void -patch_all_commons_by_name (char *name, CORE_ADDR offset, int secnum) -{ - - SAVED_F77_COMMON_PTR tmp; - - /* For blank common blocks, change the canonical reprsentation - of a blank name */ - - if (strcmp (name, BLANK_COMMON_NAME_ORIGINAL) == 0 - || strcmp (name, BLANK_COMMON_NAME_MF77) == 0) - { - xfree (name); - name = alloca (strlen (BLANK_COMMON_NAME_LOCAL) + 1); - strcpy (name, BLANK_COMMON_NAME_LOCAL); - } - - tmp = head_common_list; - - while (tmp != NULL) - { - if (COMMON_NEEDS_PATCHING (tmp)) - if (strcmp (tmp->name, name) == 0) - patch_common_entries (tmp, offset, secnum); - - tmp = tmp->next; - } -} -#endif - -/* This macro adds the symbol-number for the start of the function - (the symbol number of the .bf) referenced by symnum_fcn to a - list. This list, in reality should be a FIFO queue but since - #line pragmas sometimes cause line ranges to get messed up - we simply create a linear list. This list can then be searched - first by a queueing algorithm and upon failure fall back to - a linear scan. */ - -#if 0 -#define ADD_BF_SYMNUM(bf_sym,fcn_sym) \ - \ - if (saved_bf_list == NULL) \ -{ \ - tmp_bf_ptr = allocate_saved_bf_node(); \ - \ - tmp_bf_ptr->symnum_bf = (bf_sym); \ - tmp_bf_ptr->symnum_fcn = (fcn_sym); \ - tmp_bf_ptr->next = NULL; \ - \ - current_head_bf_list = saved_bf_list = tmp_bf_ptr; \ - saved_bf_list_end = tmp_bf_ptr; \ - } \ -else \ -{ \ - tmp_bf_ptr = allocate_saved_bf_node(); \ - \ - tmp_bf_ptr->symnum_bf = (bf_sym); \ - tmp_bf_ptr->symnum_fcn = (fcn_sym); \ - tmp_bf_ptr->next = NULL; \ - \ - saved_bf_list_end->next = tmp_bf_ptr; \ - saved_bf_list_end = tmp_bf_ptr; \ - } -#endif - -/* This function frees the entire (.bf,function) list */ - -#if 0 -static void -clear_bf_list (void) -{ - - SAVED_BF_PTR tmp = saved_bf_list; - SAVED_BF_PTR next = NULL; - - while (tmp != NULL) - { - next = tmp->next; - xfree (tmp); - tmp = next; - } - saved_bf_list = NULL; -} -#endif - -int global_remote_debug; - -#if 0 - -static long -get_bf_for_fcn (long the_function) -{ - SAVED_BF_PTR tmp; - int nprobes = 0; - - /* First use a simple queuing algorithm (i.e. look and see if the - item at the head of the queue is the one you want) */ - - if (saved_bf_list == NULL) - internal_error (__FILE__, __LINE__, - _("cannot get .bf node off empty list")); - - if (current_head_bf_list != NULL) - if (current_head_bf_list->symnum_fcn == the_function) - { - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "*"); - - tmp = current_head_bf_list; - current_head_bf_list = current_head_bf_list->next; - return (tmp->symnum_bf); - } - - /* If the above did not work (probably because #line directives were - used in the sourcefile and they messed up our internal tables) we now do - the ugly linear scan */ - - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "\ndefaulting to linear scan\n"); - - nprobes = 0; - tmp = saved_bf_list; - while (tmp != NULL) - { - nprobes++; - if (tmp->symnum_fcn == the_function) - { - if (global_remote_debug) - fprintf_unfiltered (gdb_stderr, "Found in %d probes\n", nprobes); - current_head_bf_list = tmp->next; - return (tmp->symnum_bf); - } - tmp = tmp->next; - } - - return (-1); -} - -static SAVED_FUNCTION_PTR saved_function_list = NULL; -static SAVED_FUNCTION_PTR saved_function_list_end = NULL; - -static void -clear_function_list (void) -{ - SAVED_FUNCTION_PTR tmp = saved_function_list; - SAVED_FUNCTION_PTR next = NULL; - - while (tmp != NULL) - { - next = tmp->next; - xfree (tmp); - tmp = next; - } - - saved_function_list = NULL; -} -#endif diff --git a/gdb/f-lang.h b/gdb/f-lang.h index 711bdba..9d7d92b 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 *); @@ -47,41 +51,8 @@ enum f90_range_type NONE_BOUND_DEFAULT /* "(low:high)" */ }; -struct common_entry - { - struct symbol *symbol; /* The symbol node corresponding - to this component */ - struct common_entry *next; /* The next component */ - }; - -struct saved_f77_common - { - char *name; /* Name of COMMON */ - char *owning_function; /* Name of parent function */ - int secnum; /* Section # of .bss */ - CORE_ADDR offset; /* Offset from .bss for - this block */ - struct common_entry *entries; /* List of block's components */ - struct common_entry *end_of_entries; /* ptr. to end of components */ - struct saved_f77_common *next; /* Next saved COMMON block */ - }; - -typedef struct saved_f77_common SAVED_F77_COMMON, *SAVED_F77_COMMON_PTR; - -typedef struct common_entry COMMON_ENTRY, *COMMON_ENTRY_PTR; - -extern SAVED_F77_COMMON_PTR head_common_list; /* Ptr to 1st saved COMMON */ -extern SAVED_F77_COMMON_PTR tail_common_list; /* Ptr to last saved COMMON */ -extern SAVED_F77_COMMON_PTR current_common; /* Ptr to current COMMON */ - -extern SAVED_F77_COMMON_PTR find_common_for_function (char *, char *); - -#define UNINITIALIZED_SECNUM -1 -#define COMMON_NEEDS_PATCHING(blk) ((blk)->secnum == UNINITIALIZED_SECNUM) - #define BLANK_COMMON_NAME_ORIGINAL "#BLNK_COM" /* XLF assigned */ #define BLANK_COMMON_NAME_MF77 "__BLNK__" /* MF77 assigned */ -#define BLANK_COMMON_NAME_LOCAL "__BLANK" /* Local GDB */ /* When reasonable array bounds cannot be fetched, such as when you ask to 'mt print symbols' and there is no stack frame and @@ -113,6 +84,7 @@ struct builtin_f_type struct type *builtin_logical; struct type *builtin_logical_s1; struct type *builtin_logical_s2; + struct type *builtin_logical_s8; struct type *builtin_real; struct type *builtin_real_s8; struct type *builtin_real_s16; @@ -125,3 +97,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 6c9668f..852b9a8 100644 --- a/gdb/f-typeprint.c +++ b/gdb/f-typeprint.c @@ -31,7 +31,7 @@ #include "gdbcore.h" #include "target.h" #include "f-lang.h" - +#include "dwarf2loc.h" #include "gdb_string.h" #include @@ -48,6 +48,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 @@ -57,6 +85,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') @@ -166,6 +197,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 0a57404..a9ccc77 100644 --- a/gdb/f-valprint.c +++ b/gdb/f-valprint.c @@ -34,10 +34,8 @@ #include "gdbcore.h" #include "command.h" #include "block.h" - -#if 0 -static int there_is_a_visible_common_named (char *); -#endif +#include "dictionary.h" +#include "gdb_assert.h" extern void _initialize_f_valprint (void); static void info_common_command (char *, int); @@ -54,15 +52,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 +72,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 +138,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 +180,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 +261,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)) { @@ -467,22 +478,54 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, return 0; } -static void -list_all_visible_commons (char *funname) +static int +info_common_command_for_block (struct block *block, struct frame_info *frame, + const char *comname) { - SAVED_F77_COMMON_PTR tmp; - - tmp = head_common_list; - - printf_filtered (_("All COMMON blocks visible at this level:\n\n")); - - while (tmp != NULL) - { - if (strcmp (tmp->owning_function, funname) == 0) - printf_filtered ("%s\n", tmp->name); - - tmp = tmp->next; - } + struct dict_iterator iter; + struct symbol *sym; + int values_printed = 0; + const char *name; + struct value_print_options opts; + + get_user_print_options (&opts); + + ALL_BLOCK_SYMBOLS (block, iter, sym) + if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) + { + struct type *type = SYMBOL_TYPE (sym); + int index; + + gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC); + gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT); + + if (comname && (!SYMBOL_LINKAGE_NAME (sym) + || strcmp (comname, SYMBOL_LINKAGE_NAME (sym)) != 0)) + continue; + + values_printed = 1; + if (SYMBOL_PRINT_NAME (sym)) + printf_filtered (_("Contents of F77 COMMON block '%s':\n"), + SYMBOL_PRINT_NAME (sym)); + else + printf_filtered (_("Contents of blank COMMON block:\n")); + + for (index = 0; index < TYPE_NFIELDS (type); index++) + { + struct value *val; + + gdb_assert (field_is_static (&TYPE_FIELD (type, index))); + val = value_static_field (type, index); + + printf_filtered ("%s = ", TYPE_FIELD_NAME (type, index)); + value_print (val, gdb_stdout, &opts); + putchar_filtered ('\n'); + } + + putchar_filtered ('\n'); + } + + return values_printed; } /* This function is used to print out the values in a given COMMON @@ -492,11 +535,9 @@ list_all_visible_commons (char *funname) static void info_common_command (char *comname, int from_tty) { - SAVED_F77_COMMON_PTR the_common; - COMMON_ENTRY_PTR entry; struct frame_info *fi; - char *funname = 0; - struct symbol *func; + struct block *block; + int values_printed = 0; /* We have been told to display the contents of F77 COMMON block supposedly visible in this function. Let us @@ -508,136 +549,32 @@ info_common_command (char *comname, int from_tty) /* The following is generally ripped off from stack.c's routine print_frame_info() */ - func = find_pc_function (get_frame_pc (fi)); - if (func) - { - /* In certain pathological cases, the symtabs give the wrong - function (when we are in the first function in a file which - is compiled without debugging symbols, the previous function - is compiled with debugging symbols, and the "foo.o" symbol - that is supposed to tell us where the file with debugging symbols - ends has been truncated by ar because it is longer than 15 - characters). - - So look in the minimal symbol tables as well, and if it comes - up with a larger address for the function use that instead. - I don't think this can ever cause any problems; there shouldn't - be any minimal symbols in the middle of a function. - FIXME: (Not necessarily true. What about text labels) */ - - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (get_frame_pc (fi)); - - if (msymbol != NULL - && (SYMBOL_VALUE_ADDRESS (msymbol) - > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) - funname = SYMBOL_LINKAGE_NAME (msymbol); - else - funname = SYMBOL_LINKAGE_NAME (func); - } - else - { - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (get_frame_pc (fi)); - - if (msymbol != NULL) - funname = SYMBOL_LINKAGE_NAME (msymbol); - else /* Got no 'funname', code below will fail. */ - error (_("No function found for frame.")); - } - - /* If comname is NULL, we assume the user wishes to see the - which COMMON blocks are visible here and then return */ - - if (comname == 0) + block = get_frame_block (fi, 0); + if (block == NULL) { - list_all_visible_commons (funname); + printf_filtered (_("No symbol table info available.\n")); return; } - the_common = find_common_for_function (comname, funname); - - if (the_common) + while (block) { - if (strcmp (comname, BLANK_COMMON_NAME_LOCAL) == 0) - printf_filtered (_("Contents of blank COMMON block:\n")); - else - printf_filtered (_("Contents of F77 COMMON block '%s':\n"), comname); - - printf_filtered ("\n"); - entry = the_common->entries; - - while (entry != NULL) - { - print_variable_and_value (NULL, entry->symbol, fi, gdb_stdout, 0); - entry = entry->next; - } + if (info_common_command_for_block (block, fi, comname)) + values_printed = 1; + /* After handling the function's top-level block, stop. Don't + continue to its superblock, the block of per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); } - else - printf_filtered (_("Cannot locate the common block %s in function '%s'\n"), - comname, funname); -} - -/* This function is used to determine whether there is a - F77 common block visible at the current scope called 'comname'. */ - -#if 0 -static int -there_is_a_visible_common_named (char *comname) -{ - SAVED_F77_COMMON_PTR the_common; - struct frame_info *fi; - char *funname = 0; - struct symbol *func; - - if (comname == NULL) - error (_("Cannot deal with NULL common name!")); - fi = get_selected_frame (_("No frame selected")); - - /* The following is generally ripped off from stack.c's routine - print_frame_info() */ - - func = find_pc_function (fi->pc); - if (func) + if (!values_printed) { - /* In certain pathological cases, the symtabs give the wrong - function (when we are in the first function in a file which - is compiled without debugging symbols, the previous function - is compiled with debugging symbols, and the "foo.o" symbol - that is supposed to tell us where the file with debugging symbols - ends has been truncated by ar because it is longer than 15 - characters). - - So look in the minimal symbol tables as well, and if it comes - up with a larger address for the function use that instead. - I don't think this can ever cause any problems; there shouldn't - be any minimal symbols in the middle of a function. - FIXME: (Not necessarily true. What about text labels) */ - - struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (fi->pc); - - if (msymbol != NULL - && (SYMBOL_VALUE_ADDRESS (msymbol) - > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) - funname = SYMBOL_LINKAGE_NAME (msymbol); + if (comname) + printf_filtered (_("No common block '%s'.\n"), comname); else - funname = SYMBOL_LINKAGE_NAME (func); + printf_filtered (_("No common blocks.\n")); } - else - { - struct minimal_symbol *msymbol = - lookup_minimal_symbol_by_pc (fi->pc); - - if (msymbol != NULL) - funname = SYMBOL_LINKAGE_NAME (msymbol); - } - - the_common = find_common_for_function (comname, funname); - - return (the_common ? 1 : 0); } -#endif void _initialize_f_valprint (void) diff --git a/gdb/findcmd.c b/gdb/findcmd.c index 1d28914..d176341 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 8c027c9..d201f76 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. GDB has needed these for a long time... All extract a target-format integer at ADDR which is LEN bytes long. */ @@ -394,27 +395,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); @@ -422,32 +412,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; } @@ -489,12 +487,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: @@ -513,7 +522,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 { @@ -556,18 +564,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. */ @@ -604,10 +627,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 @@ -621,7 +645,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/frame.c b/gdb/frame.c index 67e0607..7dcf2cb 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1109,6 +1109,14 @@ has_stack_frames (void) if (ptid_equal (inferior_ptid, null_ptid)) return 0; + /* FIXME: Workaround archer-tromey-python crash in + add_inferior_object->get_current_arch on FSF GDB update: + is_thread_state would assertion check here as + remote_start_remote->add_inferior_silent->observer_notify_new_inferior is + before remote_start_remote->add_thread_silent. */ + if (find_thread_ptid (inferior_ptid) == NULL) + return 0; + /* Don't try to read from a dead thread. */ if (is_exited (inferior_ptid)) return 0; @@ -1843,6 +1851,17 @@ get_frame_args_address (struct frame_info *fi) return fi->base->this_args (fi, &fi->base_cache); } +/* Return true if the frame base for frame FI is BASE; false + otherwise. */ + +int +frame_unwinder_is (struct frame_info *fi, const struct frame_unwind *unwinder) +{ + if (fi->unwind == NULL) + fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache); + return fi->unwind == unwinder; +} + /* Level of the selected frame: 0 for innermost, 1 for its caller, ... or -1 for a NULL frame. */ diff --git a/gdb/frame.h b/gdb/frame.h index febef5c..611c6d3 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -696,4 +696,10 @@ extern struct frame_info *deprecated_safe_get_selected_frame (void); extern struct frame_info *create_new_frame (CORE_ADDR base, CORE_ADDR pc); +/* Return true if the frame unwinder for frame FI is UNWINDER; false + otherwise. */ + +extern int frame_unwinder_is (struct frame_info *fi, + const struct frame_unwind *unwinder); + #endif /* !defined (FRAME_H) */ 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 79d33fe..aecd820 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -249,6 +249,9 @@ extern struct thread_info *any_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 2f77dca..8146175 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -38,6 +38,9 @@ #include "cp-abi.h" #include "gdb_assert.h" #include "hashtab.h" +#include "observer.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" /* Floatformat pairs. */ @@ -118,13 +121,31 @@ 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 on the objfile's objfile_obstack. */ struct type * -alloc_type (struct objfile *objfile) +alloc_type (struct objfile *objfile, struct type *parent) { struct type *type; @@ -148,6 +169,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. */ @@ -184,7 +238,7 @@ struct type * alloc_type_copy (const struct type *type) { if (TYPE_OBJFILE_OWNED (type)) - return alloc_type (TYPE_OWNER (type).objfile); + return alloc_type (TYPE_OWNER (type).objfile, (struct type *) type); else return alloc_type_arch (TYPE_OWNER (type).gdbarch); } @@ -273,7 +327,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; } @@ -350,7 +404,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; } @@ -721,12 +775,13 @@ create_range_type (struct type *result_type, struct type *index_type, TYPE_TARGET_STUB (result_type) = 1; else TYPE_LENGTH (result_type) = TYPE_LENGTH (check_typedef (index_type)); - TYPE_NFIELDS (result_type) = 2; + TYPE_NFIELDS (result_type) = 3; TYPE_FIELDS (result_type) = TYPE_ZALLOC (result_type, TYPE_NFIELDS (result_type) * sizeof (struct field)); 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; @@ -826,26 +881,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_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 0) + || TYPE_RANGE_BOUND_IS_DWARF_BLOCK (range_type, 1) + || TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (range_type) + || TYPE_RANGE_LOWER_BOUND_IS_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,84 @@ 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 CORE_ADDR +type_length_get (struct type *type, struct type *target_type, int full_span) +{ + struct type *range_type; + int count; + CORE_ADDR byte_stride = 0; /* `= 0' for a false GCC warning. */ + CORE_ADDR element_size; + + 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_RANGE_LOWER_BOUND_IS_UNDEFINED (range_type) + || TYPE_RANGE_UPPER_BOUND_IS_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 %d..%d"), + TYPE_NAME (type), TYPE_LOW_BOUND (range_type), + 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); + } + } + if (full_span) + return count * byte_stride; + if (target_type == NULL) + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + element_size = type_length_get (target_type, NULL, 1); + return (count - 1) * byte_stride + element_size; +} + +/* 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 @@ -1347,7 +1499,8 @@ stub_noname_complaint (void) /* Find the real type of TYPE. This function returns the real type, after removing all layers of typedefs and completing opaque or stub types. Completion changes the TYPE argument, but stripping of - typedefs does not. */ + typedefs does not. Still original passed TYPE will have TYPE_LENGTH + updated. FIXME: Remove this dependency (only ada_to_fixed_type?). */ struct type * check_typedef (struct type *type) @@ -1457,34 +1610,37 @@ 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 (!currently_reading_symtab + && (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 int low_bound = TYPE_LOW_BOUND (range_type); - const int high_bound = TYPE_HIGH_BOUND (range_type); - int nb_elements; - - if (high_bound < low_bound) - nb_elements = 0; - else - nb_elements = high_bound - low_bound + 1; - - TYPE_LENGTH (type) = nb_elements * TYPE_LENGTH (target_type); + 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) @@ -1492,9 +1648,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; } @@ -1716,7 +1875,7 @@ init_type (enum type_code code, int length, int flags, { struct type *type; - type = alloc_type (objfile); + type = alloc_type (objfile, NULL); TYPE_CODE (type) = code; TYPE_LENGTH (type) = length; @@ -1760,6 +1919,10 @@ init_type (enum type_code code, int length, int flags, { INIT_CPLUS_SPECIFIC (type); } + + if (!objfile) + type_incref (type); + return type; } @@ -2820,33 +2983,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; @@ -2861,8 +3033,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; @@ -2873,6 +3047,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)) @@ -2881,12 +3068,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++) { @@ -2895,8 +3115,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)); @@ -2915,6 +3135,16 @@ copy_type_recursive (struct objfile *objfile, xstrdup (TYPE_FIELD_STATIC_PHYSNAME (type, i))); break; + case FIELD_LOC_KIND_DWARF_BLOCK: + /* `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 (new_type) + || TYPE_NOT_ASSOCIATED (new_type)) + SET_FIELD_DWARF_BLOCK (TYPE_FIELD (new_type, i), NULL); + else + SET_FIELD_BITPOS (TYPE_FIELD (new_type, i), + dwarf_locexpr_baton_eval (TYPE_FIELD_DWARF_BLOCK (type, i))); + break; default: internal_error (__FILE__, __LINE__, _("Unexpected type field location kind: %d"), @@ -2923,17 +3153,30 @@ copy_type_recursive (struct objfile *objfile, } } + /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */ + if (TYPE_CODE (type) == TYPE_CODE_RANGE + && TYPE_RANGE_HIGH_BOUND_IS_COUNT (type)) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0; + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (type) + + TYPE_HIGH_BOUND (type) - 1; + } + + /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were + possibly converted. */ + TYPE_DYNAMIC (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 @@ -2951,6 +3194,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. @@ -2973,6 +3227,217 @@ 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) || !TYPE_CPLUS_SPECIFIC (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)); + + /* `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) || !TYPE_CPLUS_SPECIFIC (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); +} + +/* Increment the reference count for TYPE. */ + +void +type_incref (struct type *type) +{ +} + +/* Decrement the reference count for TYPE. If TYPE has no more + references, delete it. */ + +void +type_decref (struct type *type) +{ +} + +/* 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. */ @@ -3463,6 +3928,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 be6ed55..6a51a4e 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -137,6 +137,8 @@ enum type_code TYPE_CODE_DECFLOAT, /* Decimal floating point. */ + TYPE_CODE_MODULE, /* Fortran module. */ + /* Internal function type. */ TYPE_CODE_INTERNAL_FUNCTION }; @@ -213,6 +215,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 @@ -278,6 +285,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. */ @@ -365,6 +414,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; /* Number of fields described for this type. This field appears at this location because it packs nicely here. */ @@ -431,6 +487,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. @@ -538,6 +608,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; }; @@ -812,9 +885,9 @@ extern void allocate_cplus_struct_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 @@ -823,23 +896,44 @@ extern void allocate_cplus_struct_type (struct type *); #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->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_LOW_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 0) #define TYPE_HIGH_BOUND(range_type) TYPE_FIELD_BITPOS (range_type, 1) - -/* Moto-specific stuff for FORTRAN arrays */ - -#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ - (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),1)) +#define TYPE_BYTE_STRIDE(range_type) TYPE_FIELD_BITPOS (range_type, 2) + +/* Whether we should use TYPE_FIELD_DWARF_BLOCK (and not TYPE_FIELD_BITPOS). */ +#define TYPE_RANGE_BOUND_IS_DWARF_BLOCK(range_type, fieldno) \ + (TYPE_FIELD_LOC_KIND (range_type, fieldno) == FIELD_LOC_KIND_DWARF_BLOCK) +#define TYPE_RANGE_BOUND_SET_DWARF_BLOCK(range_type, fieldno) \ + (TYPE_FIELD_LOC_KIND (range_type, fieldno) = FIELD_LOC_KIND_DWARF_BLOCK) +#define TYPE_ARRAY_BOUND_IS_DWARF_BLOCK(array_type, fieldno) \ + TYPE_RANGE_BOUND_IS_DWARF_BLOCK (TYPE_INDEX_TYPE (array_type), fieldno) + +/* Unbound arrays, such as GCC array[]; at end of struct. */ +#define TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED(rangetype) \ + TYPE_FIELD_ARTIFICIAL((rangetype),0) +#define TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED(rangetype) \ + TYPE_FIELD_ARTIFICIAL((rangetype),1) #define TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED(arraytype) \ - (TYPE_FIELD_ARTIFICIAL(TYPE_INDEX_TYPE((arraytype)),0)) - -#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ - (TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype)))) + TYPE_RANGE_LOWER_BOUND_IS_UNDEFINED (TYPE_INDEX_TYPE (arraytype)) +#define TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED(arraytype) \ + TYPE_RANGE_UPPER_BOUND_IS_UNDEFINED (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)) +#define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ + TYPE_HIGH_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++ */ @@ -855,6 +949,7 @@ extern void allocate_cplus_struct_type (struct type *); #define TYPE_CPLUS_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.cplus_stuff #define TYPE_FLOATFORMAT(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.floatformat #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_MAIN_TYPE(thistype)->fields[index].type #define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses #define TYPE_BASECLASS_NAME(thistype,index) TYPE_MAIN_TYPE(thistype)->fields[index].name @@ -1131,7 +1226,7 @@ extern const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN Use alloc_type_arch to allocate a type owned by an architecture. Use alloc_type_copy to allocate a type with the same owner as a pre-existing template type, no matter whether objfile or gdbarch. */ -extern struct type *alloc_type (struct objfile *); +extern struct type *alloc_type (struct objfile *, struct type *); extern struct type *alloc_type_arch (struct gdbarch *); extern struct type *alloc_type_copy (const struct type *); @@ -1226,6 +1321,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); @@ -1262,6 +1369,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]) @@ -1324,10 +1433,15 @@ 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); + +extern void type_incref (struct type *type); + +extern void type_decref (struct type *type); + #endif /* GDBTYPES_H */ diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 0f9d44e..c910e88 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -26,6 +26,7 @@ #include "demangle.h" #include "objfiles.h" #include "valprint.h" +#include "c-lang.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -459,10 +460,8 @@ gnuv3_find_method_in (struct type *domain, CORE_ADDR voffset, LONGEST adjustment) { int i; - const char *physname; /* Search this class first. */ - physname = NULL; if (adjustment == 0) { int len; @@ -590,15 +589,24 @@ gnuv3_print_method_ptr (const gdb_byte *contents, { char *demangled_name = cplus_demangle (physname, DMGL_ANSI | DMGL_PARAMS); - if (demangled_name != NULL) + fprintf_filtered (stream, "&virtual "); + if (demangled_name == NULL) + fputs_filtered (physname, stream); + else { - fprintf_filtered (stream, "&virtual "); fputs_filtered (demangled_name, stream); xfree (demangled_name); - return; } + return; } } + else if (ptr_value != 0) + { + /* Found a non-virtual function: print out the type. */ + fputs_filtered ("(", stream); + c_print_type (type, "", stream, -1, 0); + fputs_filtered (") ", stream); + } /* We didn't find it; print the raw data. */ if (vbit) diff --git a/gdb/gnulib/Makefile.in b/gdb/gnulib/Makefile.in index 5e55573..5439aba 100644 --- a/gdb/gnulib/Makefile.in +++ b/gdb/gnulib/Makefile.in @@ -1,8 +1,8 @@ # Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005 Free Software Foundation, Inc. +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +# 2004, 2005, 2009 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 991b27f..411b41b 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -586,6 +586,8 @@ i386_linux_store_inferior_registers (struct target_ops *ops, static unsigned long i386_linux_dr[DR_CONTROL + 1]; +/* Get debug register REGNUM value from only the one LWP of PTID. */ + static unsigned long i386_linux_dr_get (ptid_t ptid, int regnum) { @@ -614,6 +616,8 @@ i386_linux_dr_get (ptid_t ptid, int regnum) return value; } +/* Set debug register REGNUM to VALUE in only the one LWP of PTID. */ + static void i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) { @@ -630,6 +634,8 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) perror_with_name (_("Couldn't write debug register")); } +/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */ + static void i386_linux_dr_set_control (unsigned long control) { @@ -641,6 +647,8 @@ i386_linux_dr_set_control (unsigned long control) i386_linux_dr_set (ptid, DR_CONTROL, control); } +/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */ + static void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) { @@ -654,18 +662,55 @@ i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr); } +/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */ + static void i386_linux_dr_reset_addr (int regnum) { i386_linux_dr_set_addr (regnum, 0); } +/* Get DR_STATUS from only the one LWP of INFERIOR_PTID. */ + static unsigned long i386_linux_dr_get_status (void) { return i386_linux_dr_get (inferior_ptid, DR_STATUS); } +/* Unset VALUE bits in DR_STATUS in all LWPs of LWP_LIST. */ + +static void +i386_linux_dr_unset_status (unsigned long mask) +{ + struct lwp_info *lp; + ptid_t ptid; + + ALL_LWPS (lp, ptid) + { + unsigned long value; + + value = i386_linux_dr_get (ptid, DR_STATUS); + value &= ~mask; + i386_linux_dr_set (ptid, DR_STATUS, value); + } +} + +/* 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) { @@ -832,6 +877,8 @@ _initialize_i386_linux_nat (void) i386_dr_low.set_addr = i386_linux_dr_set_addr; 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 ab1bd8a..ee330b8 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -137,8 +137,11 @@ struct i386_dr_low_type i386_dr_low; #define I386_DR_GET_RW_LEN(i) \ ((dr_control_mirror >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f) +/* Mask that this I'th watchpoint has triggered. */ +#define I386_DR_WATCH_MASK(i) (1 << (i)) + /* Did the watchpoint whose address is in the I'th register break? */ -#define I386_DR_WATCH_HIT(i) (dr_status_mirror & (1 << (i))) +#define I386_DR_WATCH_HIT(i) (dr_status_mirror & I386_DR_WATCH_MASK (i)) /* A macro to loop over all debug registers. */ #define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++) @@ -358,6 +361,10 @@ i386_insert_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) i386_dr_low.set_addr (i, addr); i386_dr_low.set_control (dr_control_mirror); + /* Only a sanity check for leftover bits (set possibly only by inferior). */ + if (i386_dr_low.unset_status) + i386_dr_low.unset_status (I386_DR_WATCH_MASK (i)); + return 0; } @@ -387,6 +394,11 @@ i386_remove_aligned_watchpoint (CORE_ADDR addr, unsigned len_rw_bits) i386_dr_low.set_control (dr_control_mirror); if (i386_dr_low.reset_addr) i386_dr_low.reset_addr (i); + + /* Status must be already queried for each LWP. Otherwise it will + be lost in all-stop mode + breakpoint always-inserted off. */ + if (i386_dr_low.unset_status) + i386_dr_low.unset_status (I386_DR_WATCH_MASK (i)); } retval = 0; } @@ -520,6 +532,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. */ @@ -575,28 +598,7 @@ static int i386_stopped_by_watchpoint (void) { CORE_ADDR addr = 0; - return i386_stopped_data_address (¤t_target, &addr); -} - -/* Return non-zero if the inferior has some break/watchpoint that - triggered. */ - -static int -i386_stopped_by_hwbp (void) -{ - int i; - - dr_status_mirror = i386_dr_low.get_status (); - if (maint_show_dr) - i386_show_dr ("stopped_by_hwbp", 0, 0, hw_execute); - - ALL_DEBUG_REGISTERS(i) - { - if (I386_DR_WATCH_HIT (i)) - return 1; - } - - return 0; + return target_stopped_data_address (¤t_target, &addr); } /* Insert a hardware-assisted breakpoint at BP_TGT->placed_address. @@ -690,6 +692,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 f49b9f6..cd31958 100644 --- a/gdb/i386-nat.h +++ b/gdb/i386-nat.h @@ -49,16 +49,23 @@ extern void i386_use_watchpoints (struct target_ops *); functions are: set_control -- set the debug control (DR7) - register to a given value + register to a given value for all LWPs set_addr -- put an address into one debug - register + register for all LWPs reset_addr -- reset the address stored in - one debug register + one debug register for all LWPs get_status -- return the value of the debug - status (DR6) register. + status (DR6) register for current LWP + + 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 @@ -70,6 +77,8 @@ struct i386_dr_low_type void (*set_addr) (int, CORE_ADDR); 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/infrun.c b/gdb/infrun.c index e3eddce..8917ac9 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2630,6 +2630,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 (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); @@ -2667,6 +2671,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); + /* This causes the eventpoints and symbol table to be reset. Must do this now, before trying to determine whether to stop. */ diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c index 6b68e7d..5095180 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/language.h b/gdb/language.h index c650e07..660fdf6 100644 --- a/gdb/language.h +++ b/gdb/language.h @@ -237,7 +237,6 @@ struct language_defn variables. */ struct symbol *(*la_lookup_symbol_nonlocal) (const char *, - const char *, const struct block *, const domain_enum); diff --git a/gdb/linespec.c b/gdb/linespec.c index 3e943a1..3b8956c 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -30,6 +30,7 @@ #include "value.h" #include "completer.h" #include "cp-abi.h" +#include "cp-support.h" #include "parser-defs.h" #include "block.h" #include "objc-lang.h" @@ -839,13 +840,33 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, } else if (paren_pointer != NULL) { - p = paren_pointer + 1; + /* We need to deal with method and function overloads + with no parameters. Gdb and gcc (and who knows about other + compilers) are very inconsistent with the keyword "void". + Canonicalizing C++ types is insufficient in this case, since + we still need to enforce the presence (or lack thereof) of + "void". For simplicity, omit the keyword "void" if present. */ + if (strncmp (paren_pointer - 5, "(void)", 6) == 0) + { + char *a, *b; + a = paren_pointer - 4; + b = paren_pointer; + while ((*(a++) = *(b++)) != '\0') ; + *a = '\0'; + p = paren_pointer - 3; + } + else + p = paren_pointer + 1; } else { p = skip_quoted (*argptr); } + /* Make sure we keep important kewords like "const" */ + if (strncmp (p, " const", 6) == 0) + p += 6; + /* Keep any template parameters */ if (*p == '<') p = find_template_name_end (p); @@ -1257,7 +1278,10 @@ decode_compound (char **argptr, int funfirstline, char ***canonical, /* Move pointer ahead to next double-colon. */ while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\'')) { - if (p[0] == '<') + if (current_language->la_language == language_cplus + && strncmp (p, "operator", 8) == 0) + p += cp_validate_operator (p); + else if (p[0] == '<') { temp_end = find_template_name_end (p); if (!temp_end) @@ -1334,6 +1358,16 @@ decode_compound (char **argptr, int funfirstline, char ***canonical, while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':') p++; /* At this point p->"". String ended. */ + /* Nope. C++ operators could have spaces in them + ("foo::operator <" or "foo::operator delete []"). + I apologize, this is a bit hacky... */ + if (current_language->la_language == language_cplus + && *p == ' ' && p - 8 - *argptr + 1 > 0 + && strncmp (p - 8, "operator", 8) == 0) + { + /* The above loop has already swallowed "operator" */ + p += cp_validate_operator (p - 8) - 8; + } } /* Allocate our own copy of the substring between argptr and @@ -1407,6 +1441,7 @@ lookup_prefix_sym (char **argptr, char *p) { char *p1; char *copy; + struct symbol *sym; /* Extract the class name. */ p1 = p; @@ -1425,7 +1460,26 @@ lookup_prefix_sym (char **argptr, char *p) /* At this point p1->"::inA::fun", p->"inA::fun" copy->"AAA", argptr->"inA::fun" */ - return lookup_symbol (copy, 0, STRUCT_DOMAIN, 0); + sym = lookup_symbol (copy, 0, STRUCT_DOMAIN, 0); + if (sym == NULL) + { + /* Typedefs are in VAR_DOMAIN so the above symbol lookup will + fail when the user attempts to lookup a method of a class + via a typedef'd name (NOT via the classes name, which is already + handled in symbol_matches_domain). So try the lookup again + using VAR_DOMAIN (where typedefs live) and double-check that we + found a struct/class type. */ + struct symbol *s = lookup_symbol (copy, 0, VAR_DOMAIN, 0); + if (s != NULL) + { + struct type *t = SYMBOL_TYPE (s); + CHECK_TYPEDEF (t); + if (TYPE_CODE (t) == TYPE_CODE_STRUCT) + return s; + } + } + + return sym; } /* This finds the method COPY in the class whose type is T and whose @@ -1780,7 +1834,7 @@ symbol_found (int funfirstline, char ***canonical, char *copy, { struct blockvector *bv = BLOCKVECTOR (SYMBOL_SYMTAB (sym)); struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - if (lookup_block_symbol (b, copy, NULL, VAR_DOMAIN) != NULL) + if (lookup_block_symbol (b, copy, VAR_DOMAIN) != NULL) build_canonical_line_spec (values.sals, copy, canonical); } return values; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 1308844..e6fad24 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1629,6 +1629,7 @@ resume_callback (struct lwp_info *lp, void *data) lp->stopped = 0; lp->step = 0; memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + lp->watchpoint_hit_set = 0; } else if (lp->stopped && debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (has pending)\n", @@ -1766,6 +1767,7 @@ linux_nat_resume (struct target_ops *ops, linux_ops->to_resume (linux_ops, ptid, step, signo); memset (&lp->siginfo, 0, sizeof (lp->siginfo)); + lp->watchpoint_hit_set = 0; if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, @@ -2164,6 +2166,78 @@ maybe_clear_ignore_sigint (struct lwp_info *lp) } } +/* Fetch the possible triggered data watchpoint info and store it to LP. + The hardware data watchpoint trigger gets cleared during this fetch. */ + +static void +save_sigtrap (struct lwp_info *lp) +{ + struct cleanup *old_chain; + + /* linux_nat_stopped_data_address is not even installed in this case. */ + if (linux_ops->to_stopped_data_address == NULL) + return; + + old_chain = save_inferior_ptid (); + inferior_ptid = lp->ptid; + + lp->watchpoint_hit_set = + linux_ops->to_stopped_data_address (¤t_target, &lp->watchpoint_hit); + + do_cleanups (old_chain); +} + +/* Wrap target_stopped_data_address where the GNU/Linux native target may be + directed by the watchpoint/debug register number. Base the reported value + on the triggered data address instead. During inferior stop the assignment + of watchpoint/debug registers may change making the register number specific + trigger info stale. */ + +static int +linux_nat_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) +{ + struct lwp_info *lp = find_lwp_pid (inferior_ptid); + + gdb_assert (lp != NULL); + + *addr_p = lp->watchpoint_hit; + + return lp->watchpoint_hit_set; +} + +/* 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 @@ -2215,6 +2289,8 @@ stop_wait_callback (struct lwp_info *lp, void *data) /* Save the trap's siginfo in case we need it later. */ save_siginfo (lp); + save_sigtrap (lp); + /* Now resume this LWP and get the SIGSTOP event. */ errno = 0; ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); @@ -2579,9 +2655,13 @@ linux_nat_filter_event (int lwpid, int status, int options) add_thread (lp->ptid); } - /* Save the trap's siginfo in case we need it later. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP) - save_siginfo (lp); + { + /* Save the trap's siginfo in case we need it later. */ + save_siginfo (lp); + + save_sigtrap (lp); + } /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) @@ -4871,6 +4951,10 @@ linux_nat_add_target (struct target_ops *t) t->to_thread_alive = linux_nat_thread_alive; t->to_pid_to_str = linux_nat_pid_to_str; t->to_has_thread_control = tc_schedlock; + if (linux_ops->to_stopped_data_address) + 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/linux-nat.h b/gdb/linux-nat.h index d1ed6fc..faf68bb 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -62,6 +62,12 @@ struct lwp_info be the address of a hardware watchpoint. */ struct siginfo siginfo; + /* WATCHPOINT_HIT_SET is non-zero if this LWP stopped with a trap and a data + watchpoint has been found as triggered. In such case WATCHPOINT_HIT + contains data address of the triggered data watchpoint. */ + unsigned watchpoint_hit_set : 1; + CORE_ADDR watchpoint_hit; + /* Non-zero if we expect a duplicated SIGINT. */ int ignore_sigint; diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 88c7e5e..2d0b3ca 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 5f9a0fe..66fa067 100644 --- a/gdb/machoread.c +++ b/gdb/machoread.c @@ -681,6 +681,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 */ NULL /* next: pointer to next struct sym_fns */ diff --git a/gdb/main.c b/gdb/main.c index 8b66f78..ddeab6f 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 ecbae12..80fc36e 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/mdebugread.c b/gdb/mdebugread.c index aac82e9..626292c 100644 --- a/gdb/mdebugread.c +++ b/gdb/mdebugread.c @@ -4802,7 +4802,7 @@ new_type (char *name) { struct type *t; - t = alloc_type (current_objfile); + t = alloc_type (current_objfile, NULL); TYPE_NAME (t) = name; TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default; return t; diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c index 0cf03d9..e4ca621 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -41,7 +41,7 @@ static void varobj_update_one (struct varobj *var, enum print_values print_values, int explicit); -static int mi_print_value_p (struct type *type, enum print_values print_values); +static int mi_print_value_p (struct varobj *var, enum print_values print_values); /* Print variable object VAR. The PRINT_VALUES parameter controls if the value should be printed. The PRINT_EXPRESSION parameter @@ -59,8 +59,12 @@ print_varobj (struct varobj *var, enum print_values print_values, ui_out_field_string (uiout, "exp", varobj_get_expression (var)); ui_out_field_int (uiout, "numchild", varobj_get_num_children (var)); - if (mi_print_value_p (varobj_get_gdb_type (var), print_values)) - ui_out_field_string (uiout, "value", varobj_get_value (var)); + if (mi_print_value_p (var, print_values)) + { + char *val = varobj_get_value (var); + ui_out_field_string (uiout, "value", val); + xfree (val); + } type = varobj_get_type (var); if (type != NULL) @@ -138,6 +142,8 @@ mi_cmd_var_create (char *command, char **argv, int argc) print_varobj (var, PRINT_ALL_VALUES, 0 /* don't print expression */); + ui_out_field_int (uiout, "has_more", varobj_has_more (var, 0)); + do_cleanups (old_cleanups); } @@ -223,6 +229,7 @@ mi_cmd_var_set_format (char *command, char **argv, int argc) { enum varobj_display_formats format; struct varobj *var; + char *val; if (argc != 2) error (_("mi_cmd_var_set_format: Usage: NAME FORMAT.")); @@ -239,7 +246,9 @@ mi_cmd_var_set_format (char *command, char **argv, int argc) ui_out_field_string (uiout, "format", varobj_format_string[(int) format]); /* Report the value in the new format */ - ui_out_field_string (uiout, "value", varobj_get_value (var)); + val = varobj_get_value (var); + ui_out_field_string (uiout, "value", val); + xfree (val); } void @@ -337,11 +346,12 @@ Must be: 0 or \"%s\", 1 or \"%s\", 2 or \"%s\""), } /* Return 1 if given the argument PRINT_VALUES we should display - a value of type TYPE. */ + the varobj VAR. */ static int -mi_print_value_p (struct type *type, enum print_values print_values) +mi_print_value_p (struct varobj *var, enum print_values print_values) { + struct type *type; if (print_values == PRINT_NO_VALUES) return 0; @@ -349,6 +359,10 @@ mi_print_value_p (struct type *type, enum print_values print_values) if (print_values == PRINT_ALL_VALUES) return 1; + if (varobj_pretty_printed_p (var)) + return 1; + + type = varobj_get_gdb_type (var); if (type == NULL) return 1; else @@ -369,24 +383,35 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) struct varobj *var; VEC(varobj_p) *children; struct varobj *child; - struct cleanup *cleanup_children; int numchild; enum print_values print_values; int ix; + int from, to; char *display_hint; - if (argc != 1 && argc != 2) - error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME")); + if (argc < 1 || argc > 4) + error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME [FROM TO]")); /* Get varobj handle, if a valid var obj name was specified */ - if (argc == 1) + if (argc == 1 || argc == 3) var = varobj_get_handle (argv[0]); else var = varobj_get_handle (argv[1]); - children = varobj_list_children (var); - ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children)); - if (argc == 2) + if (argc > 2) + { + from = atoi (argv[argc - 2]); + to = atoi (argv[argc - 1]); + } + else + { + from = -1; + to = -1; + } + + children = varobj_list_children (var, &from, &to); + ui_out_field_int (uiout, "numchild", to - from); + if (argc == 2 || argc == 4) print_values = mi_parse_values_option (argv[0]); else print_values = PRINT_NO_VALUES; @@ -398,21 +423,28 @@ mi_cmd_var_list_children (char *command, char **argv, int argc) xfree (display_hint); } - if (VEC_length (varobj_p, children) == 0) - return; - - if (mi_version (uiout) == 1) - cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children"); - else - cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children"); - for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix) + if (from < to) { - struct cleanup *cleanup_child; - cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child"); - print_varobj (child, print_values, 1 /* print expression */); - do_cleanups (cleanup_child); + struct cleanup *cleanup_children; + if (mi_version (uiout) == 1) + cleanup_children + = make_cleanup_ui_out_tuple_begin_end (uiout, "children"); + else + cleanup_children + = make_cleanup_ui_out_list_begin_end (uiout, "children"); + for (ix = from; + ix < to && VEC_iterate (varobj_p, children, ix, child); + ++ix) + { + struct cleanup *cleanup_child; + cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child"); + print_varobj (child, print_values, 1 /* print expression */); + do_cleanups (cleanup_child); + } + do_cleanups (cleanup_children); } - do_cleanups (cleanup_children); + + ui_out_field_int (uiout, "has_more", varobj_has_more (var, to)); } void @@ -538,16 +570,24 @@ mi_cmd_var_evaluate_expression (char *command, char **argv, int argc) var = varobj_get_handle (argv[optind]); if (formatFound) - ui_out_field_string (uiout, "value", varobj_get_formatted_value (var, format)); + { + char *val = varobj_get_formatted_value (var, format); + ui_out_field_string (uiout, "value", val); + xfree (val); + } else - ui_out_field_string (uiout, "value", varobj_get_value (var)); + { + char *val = varobj_get_value (var); + ui_out_field_string (uiout, "value", val); + xfree (val); + } } void mi_cmd_var_assign (char *command, char **argv, int argc) { struct varobj *var; - char *expression; + char *expression, *val; if (argc != 2) error (_("mi_cmd_var_assign: Usage: NAME EXPRESSION.")); @@ -563,7 +603,9 @@ mi_cmd_var_assign (char *command, char **argv, int argc) if (!varobj_set_value (var, expression)) error (_("mi_cmd_var_assign: Could not assign expression to variable object")); - ui_out_field_string (uiout, "value", varobj_get_value (var)); + val = varobj_get_value (var); + ui_out_field_string (uiout, "value", val); + xfree (val); } /* Type used for parameters passing to mi_cmd_var_update_iter. */ @@ -644,7 +686,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 */); @@ -670,6 +711,7 @@ varobj_update_one (struct varobj *var, enum print_values print_values, for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i) { char *display_hint; + int from, to; if (mi_version (uiout) > 1) cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); @@ -678,8 +720,12 @@ varobj_update_one (struct varobj *var, enum print_values print_values, switch (r->status) { case VAROBJ_IN_SCOPE: - if (mi_print_value_p (varobj_get_gdb_type (r->varobj), print_values)) - ui_out_field_string (uiout, "value", varobj_get_value (r->varobj)); + if (mi_print_value_p (r->varobj, print_values)) + { + char *val = varobj_get_value (r->varobj); + ui_out_field_string (uiout, "value", val); + xfree (val); + } ui_out_field_string (uiout, "in_scope", "true"); break; case VAROBJ_NOT_IN_SCOPE: @@ -699,11 +745,11 @@ varobj_update_one (struct varobj *var, enum print_values print_values, } if (r->type_changed) - { - ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj)); - ui_out_field_int (uiout, "new_num_children", - varobj_get_num_children (r->varobj)); - } + ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj)); + + if (r->type_changed || r->children_changed) + ui_out_field_int (uiout, "new_num_children", + varobj_get_num_children (r->varobj)); display_hint = varobj_get_display_hint (var); if (display_hint) @@ -712,28 +758,56 @@ varobj_update_one (struct varobj *var, enum print_values print_values, xfree (display_hint); } - if (r->children_changed) - { - int ix; - struct varobj *child; - struct cleanup *cleanup = - make_cleanup_ui_out_list_begin_end (uiout, "children"); + varobj_get_child_range (r->varobj, &from, &to); + ui_out_field_int (uiout, "has_more", + varobj_has_more (r->varobj, to)); - VEC (varobj_p)* children = varobj_list_children (r->varobj); + if (r->new) + { + int j; + varobj_p child; + struct cleanup *cleanup; - for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix) + cleanup = make_cleanup_ui_out_list_begin_end (uiout, "new_children"); + for (j = 0; VEC_iterate (varobj_p, r->new, j, child); ++j) { struct cleanup *cleanup_child; cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); - print_varobj (child, print_values, 1 /* print expression */); + print_varobj (child, print_values, 1 /* print_expression */); do_cleanups (cleanup_child); } do_cleanups (cleanup); + VEC_free (varobj_p, r->new); + r->new = NULL; /* Paranoia. */ } - + if (mi_version (uiout) > 1) do_cleanups (cleanup); } VEC_free (varobj_update_result, changes); } + +void +mi_cmd_enable_pretty_printing (char *command, char **argv, int argc) +{ + if (argc != 0) + error (_("mi_cmd_enable_pretty_printing: no arguments allowed")); + varobj_enable_pretty_printing (); +} + +void +mi_cmd_var_set_update_range (char *command, char **argv, int argc) +{ + struct varobj *var; + int from, to; + + if (argc != 3) + error (_("mi_cmd_var_set_update_range: Usage: VAROBJ FROM TO")); + + var = varobj_get_handle (argv[0]); + from = atoi (argv[1]); + to = atoi (argv[2]); + + varobj_set_child_range (var, from, to); +} diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index dd3d803..8ba086c 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -52,6 +52,7 @@ struct mi_cmd mi_cmds[] = { "data-write-memory", { NULL, 0 }, mi_cmd_data_write_memory}, { "data-write-register-values", { NULL, 0 }, mi_cmd_data_write_register_values}, { "enable-timings", { NULL, 0 }, mi_cmd_enable_timings}, + { "enable-pretty-printing", { NULL, 0 }, mi_cmd_enable_pretty_printing}, { "environment-cd", { NULL, 0 }, mi_cmd_env_cd}, { "environment-directory", { NULL, 0 }, mi_cmd_env_dir}, { "environment-path", { NULL, 0 }, mi_cmd_env_path}, @@ -112,6 +113,7 @@ struct mi_cmd mi_cmds[] = { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children}, { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format}, { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen}, + { "var-set-update-range", { NULL, 0 }, mi_cmd_var_set_update_range }, { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer}, { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes}, { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format}, diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index 85ad0c4..dfab411 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -99,6 +99,8 @@ extern mi_cmd_argv_ftype mi_cmd_var_set_visualizer; extern mi_cmd_argv_ftype mi_cmd_var_show_attributes; extern mi_cmd_argv_ftype mi_cmd_var_show_format; extern mi_cmd_argv_ftype mi_cmd_var_update; +extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing; +extern mi_cmd_argv_ftype mi_cmd_var_set_update_range; /* Description of a single command. */ diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 6aa1d08..448d10a 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -1130,6 +1130,10 @@ 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 #if HAVE_PYTHON ui_out_field_string (uiout, NULL, "python"); @@ -1354,6 +1358,7 @@ mi_cmd_execute (struct mi_parse *parse) int i; free_all_values (); + free_all_types (); cleanup = make_cleanup (null_cleanup, NULL); if (parse->frame != -1 && parse->thread == -1) diff --git a/gdb/mipsread.c b/gdb/mipsread.c index a84003f..924c1c5 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 92db65e..4d39112 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -50,7 +50,6 @@ #include "addrmap.h" #include "arch-utils.h" #include "exec.h" -#include "observer.h" /* Prototypes for local functions */ @@ -458,12 +457,14 @@ free_objfile (struct objfile *objfile) unlink_objfile (objfile); - /* If we are going to free the runtime common objfile, mark it - as unallocated. */ + /* If we are going to free any existing OBJFILE reference, clear it. */ if (objfile == rt_common_objfile) rt_common_objfile = NULL; + if (objfile == symfile_objfile) + symfile_objfile = NULL; + /* Before the symbol table code was redone to make it easier to selectively load and remove information particular to a specific linkage unit, gdb used to do these things whenever the monolithic @@ -716,6 +717,20 @@ have_partial_symbols (void) 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 aecf8d8..9a7d635 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -212,6 +212,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 @@ -414,6 +419,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 the main symbol table was loaded from (e.g. the argument to the "symbol-file" or "file" command). */ @@ -554,6 +568,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) + /* Traverse all minimal symbols in all objfiles. */ #define ALL_MSYMBOLS(objfile, m) \ diff --git a/gdb/parse.c b/gdb/parse.c index ef938e3..c243bd8 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -63,6 +63,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 @@ -837,6 +838,15 @@ operator_length_standard (struct expression *expr, int endpos, args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); break; + case TYPE_INSTANCE: + oplen = 4 + longest_to_int (expr->elts[endpos - 2].longconst); + args = 1; + break; + + case TYPE_INSTANCE_LOOKUP: + oplen = 3; + break; + case OP_OBJC_MSGCALL: /* Objective C message (method) call */ oplen = 4; args = 1 + longest_to_int (expr->elts[endpos - 2].longconst); @@ -1355,6 +1365,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 cbda9c3..a07e6f2 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -189,6 +189,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 *); @@ -267,6 +274,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); @@ -299,4 +320,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 47b74ad..22fb2fc 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 5d8b936..fb0a455 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" @@ -900,6 +899,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)) { @@ -1396,6 +1400,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. @@ -1798,50 +1818,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 - && 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 @@ -1853,18 +1829,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; + } } @@ -2749,4 +2727,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..39f8246 --- /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.frame.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.frame.type () == gdb.DUMMY_FRAME: + stream.write (" \n") + elif self.frame.type () == gdb.SIGTRAMP_FRAME: + stream.write (" \n") + else: + sal = self.frame.find_sal () + pc = self.frame.pc () + name = self.frame.name () + if not name: + name = "??" + if pc != sal.pc or not sal.symtab: + stream.write (" 0x%08x in" % pc) + stream.write (" " + name + " (") + + func = self.frame.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.frame.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/python-block.c b/gdb/python/python-block.c new file mode 100644 index 0000000..8019e9d --- /dev/null +++ b/gdb/python/python-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/python-breakpoint.c b/gdb/python/python-breakpoint.c new file mode 100644 index 0000000..afa9526 --- /dev/null +++ b/gdb/python/python-breakpoint.c @@ -0,0 +1,665 @@ +/* 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" + + +/* 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; + PyGILState_STATE state; + + 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; + + state = PyGILState_Ensure (); + + 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 (); + + PyGILState_Release (state); +} + +/* Callback that is used when a breakpoint is deleted. This will + invalidate the corresponding Python object. */ +static void +gdbpy_breakpoint_deleted (int num) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + if (BPPY_VALID_P (num)) + { + bppy_breakpoints[num]->bp = NULL; + Py_DECREF (bppy_breakpoints[num]); + bppy_breakpoints[num] = NULL; + --bppy_live; + } + PyGILState_Release (state); +} + + + +/* 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/python-cmd.c b/gdb/python/python-cmd.c index 528aca6..04b3fd1 100644 --- a/gdb/python/python-cmd.c +++ b/gdb/python/python-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/python-frame.c b/gdb/python/python-frame.c index 279415c..5d8ce0a 100644 --- a/gdb/python/python-frame.c +++ b/gdb/python/python-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/python-hooks.c b/gdb/python/python-hooks.c new file mode 100644 index 0000000..a3140bc --- /dev/null +++ b/gdb/python/python-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/python-inferior.c b/gdb/python/python-inferior.c new file mode 100644 index 0000000..5e90cc2 --- /dev/null +++ b/gdb/python/python-inferior.c @@ -0,0 +1,926 @@ +/* Python interface to inferiors. + + 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 "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 *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; + } + + cleanup = ensure_python_env (get_current_arch (), 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 = inferior_list; + + 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) +{ + PyGILState_STATE state; + struct inflist_entry **inf_entry, *inf_tmp; + struct threadlist_entry *th_entry, *th_tmp; + + /* Find inferior_object for the given PID. */ + for (inf_entry = &inferior_list; *inf_entry != NULL; + inf_entry = &(*inf_entry)->next) + if ((*inf_entry)->inf_obj->inferior->pid == pid) + break; + + if (!*inf_entry) + return; + + state = PyGILState_Ensure (); + + 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--; + + PyGILState_Release (state); +} + +/* 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 = 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 = 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) +{ + PyGILState_STATE state; + thread_object *thread_obj; + inferior_object *inf_obj; + struct threadlist_entry *entry; + + state = PyGILState_Ensure (); + + thread_obj = create_thread_object (tp); + if (!thread_obj) + { + warning (_("Can't create Python InferiorThread object.")); + gdbpy_print_stack (); + PyGILState_Release (state); + 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++; + + PyGILState_Release (state); +} + +static void +delete_thread_object (struct thread_info *tp, int ignore) +{ + PyGILState_STATE state; + 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; + + state = PyGILState_Ensure (); + + tmp = *entry; + tmp->thread_obj->thread = NULL; + + *entry = (*entry)->next; + inf_obj->nthreads--; + + Py_DECREF (tmp->thread_obj); + xfree (tmp); + + + PyGILState_Release (state); +} + +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 = 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); + + inferior_list = NULL; + ninferiors = 0; + + observer_attach_new_inferior (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/python-infthread.c b/gdb/python/python-infthread.c new file mode 100644 index 0000000..21e4eab --- /dev/null +++ b/gdb/python/python-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/python-internal.h b/gdb/python/python-internal.h index 67a78af..47662d9 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -61,33 +61,76 @@ 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_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_parameters (void); +void gdbpy_initialize_thread (void); +void gdbpy_initialize_inferior (void); struct cleanup *make_cleanup_py_decref (PyObject *py); @@ -97,6 +140,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) \ @@ -107,6 +156,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); @@ -118,17 +180,22 @@ char *python_string_to_host_string (PyObject *obj); PyObject *target_string_to_unicode (const gdb_byte *str, int length); int gdbpy_is_string (PyObject *obj); +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-membuf.c b/gdb/python/python-membuf.c new file mode 100644 index 0000000..7bc294c --- /dev/null +++ b/gdb/python/python-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/python-param.c b/gdb/python/python-param.c new file mode 100644 index 0000000..1f591a8 --- /dev/null +++ b/gdb/python/python-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/python-prettyprint.c b/gdb/python/python-prettyprint.c index 5d696c8..a6348ba 100644 --- a/gdb/python/python-prettyprint.c +++ b/gdb/python/python-prettyprint.c @@ -121,6 +121,7 @@ find_pretty_printer (PyObject *value) return function; } + /* Pretty-print a single value, via the printer object PRINTER. If the function returns a string, a PyObject containing the string is returned. Otherwise, if the function returns a value, @@ -141,10 +142,15 @@ pretty_print_one_value (PyObject *printer, struct value **out_value) if (! gdbpy_is_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; } } } @@ -556,14 +562,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/python-symbol.c b/gdb/python/python-symbol.c new file mode 100644 index 0000000..03d43c1 --- /dev/null +++ b/gdb/python/python-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/python-symtab.c b/gdb/python/python-symtab.c new file mode 100644 index 0000000..830e586 --- /dev/null +++ b/gdb/python/python-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/python-type.c b/gdb/python/python-type.c index f23248c..b41d868 100644 --- a/gdb/python/python-type.c +++ b/gdb/python/python-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. */ @@ -169,6 +177,11 @@ convert_field (struct type *type, int field) if (PyObject_SetAttrString (result, "artificial", arg) < 0) goto failarg; + arg = field < TYPE_N_BASECLASSES (type) ? Py_True : Py_False; + Py_INCREF (arg); + if (PyObject_SetAttrString (result, "is_base_class", arg) < 0) + goto failarg; + arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field)); if (!arg) goto fail; @@ -361,7 +374,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; @@ -375,7 +388,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) { @@ -389,7 +402,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; @@ -404,7 +418,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; @@ -422,7 +436,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; @@ -436,10 +450,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)); @@ -482,7 +509,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; @@ -524,8 +551,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 clean_up_objfile_types (struct objfile *objfile, void *datum) { @@ -543,12 +621,13 @@ clean_up_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; } @@ -559,41 +638,25 @@ clean_up_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. */ @@ -604,7 +667,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; } @@ -623,14 +689,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; @@ -664,6 +744,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/python-utils.c b/gdb/python/python-utils.c index 49c0437..84a476e 100644 --- a/gdb/python/python-utils.c +++ b/gdb/python/python-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/python-value.c b/gdb/python/python-value.c index c4217d5..b993515 100644 --- a/gdb/python/python-value.c +++ b/gdb/python/python-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) @@ -693,7 +698,10 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) { value_other = convert_value_from_python (other); if (value_other == NULL) - return NULL; + { + result = -1; + break; + } switch (op) { case Py_LT: @@ -720,11 +728,16 @@ valpy_richcompare (PyObject *self, PyObject *other, int op) /* Can't happen. */ PyErr_SetString (PyExc_NotImplementedError, "Invalid operation on gdb.Value."); - return NULL; + result = -1; + break; } } GDB_PY_HANDLE_EXCEPTION (except); + /* In this case, the Python exception has already been set. */ + if (result < 0) + return NULL; + if (result == 1) Py_RETURN_TRUE; @@ -883,7 +896,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)) @@ -942,6 +982,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) { @@ -952,6 +1011,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.c b/gdb/python/python.c index 254bd28..5a2a9ae 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. */ @@ -319,6 +327,233 @@ 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 (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) +{ + char *expr_str; + struct value *result = NULL; + volatile struct gdb_exception except; + + if (!PyArg_ParseTuple (args, "s", &expr_str)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + result = parse_and_eval (expr_str); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return value_to_value_object (result); +} + + + +/* 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) +{ + PyGILState_STATE state; + char buffer[100]; + int r; + + state = PyGILState_Ensure (); + + /* 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); + } + + PyGILState_Release (state); +} + +/* 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. */ @@ -357,6 +592,69 @@ 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; + PyGILState_STATE state; + + /* We never free this, since we plan to exit at the end. */ + state = PyGILState_Ensure (); + + 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) +{ + PyGILState_STATE state; + + state = PyGILState_Ensure (); + + PyRun_SimpleFile (stream, file); + + fclose (stream); + PyGILState_Release (state); +} + + + /* 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. */ @@ -501,6 +799,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 */ @@ -592,13 +897,27 @@ 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_thread (); + gdbpy_initialize_inferior (); + gdbpy_initialize_events (); PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers = []"); @@ -634,6 +953,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. */ @@ -653,9 +981,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." }, @@ -676,6 +1009,37 @@ 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 a string as an expression, evaluate it, and return the result." }, + + { "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 e970180..bbb6184 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 de34894..07518b0 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/scm-valprint.c b/gdb/scm-valprint.c index cc3319a..d0d4702 100644 --- a/gdb/scm-valprint.c +++ b/gdb/scm-valprint.c @@ -62,9 +62,9 @@ scm_inferior_print (struct type *type, LONGEST value, struct ui_file *stream, { /* XXX: Should we cache these symbols? */ gdb_output_sym = - lookup_symbol_global ("gdb_output", NULL, NULL, VAR_DOMAIN); + lookup_symbol_global ("gdb_output", NULL, VAR_DOMAIN); gdb_output_len_sym = - lookup_symbol_global ("gdb_output_length", NULL, NULL, VAR_DOMAIN); + lookup_symbol_global ("gdb_output_length", NULL, VAR_DOMAIN); if ((gdb_output_sym == NULL) || (gdb_output_len_sym == NULL)) ret = -1; diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index 8b96a6f..9428d92 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -389,7 +389,6 @@ darwin_relocate_section_addresses (struct so_list *so, static struct symbol * darwin_lookup_lib_symbol (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain) { return NULL; diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index 19e3212..9f06fa9 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -334,16 +334,13 @@ spu_bfd_open (char *pathname) static struct symbol * spu_lookup_lib_symbol (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain) { if (bfd_get_arch (objfile->obfd) == bfd_arch_spu) - return lookup_global_symbol_from_objfile (objfile, name, linkage_name, - domain); + return lookup_global_symbol_from_objfile (objfile, name, domain); if (svr4_so_ops.lookup_lib_global_symbol != NULL) - return svr4_so_ops.lookup_lib_global_symbol (objfile, name, linkage_name, - domain); + return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain); return NULL; } diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 6cfaa85..68aadc0 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1908,15 +1908,13 @@ struct target_so_ops svr4_so_ops; static struct symbol * elf_lookup_lib_symbol (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain) { if (objfile->obfd == NULL || scan_dyntag (DT_SYMBOLIC, objfile->obfd, NULL) != 1) return NULL; - return lookup_global_symbol_from_objfile - (objfile, name, linkage_name, domain); + return lookup_global_symbol_from_objfile (objfile, name, domain); } extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */ diff --git a/gdb/solib.c b/gdb/solib.c index aad2d59..def02f8 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1066,13 +1066,12 @@ show_auto_solib_add (struct ui_file *file, int from_tty, struct symbol * solib_global_lookup (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain) { struct target_so_ops *ops = solib_ops (target_gdbarch); if (ops->lookup_lib_global_symbol != NULL) - return ops->lookup_lib_global_symbol (objfile, name, linkage_name, domain); + return ops->lookup_lib_global_symbol (objfile, name, domain); return NULL; } diff --git a/gdb/solist.h b/gdb/solist.h index 63a6ba0..005e8f7 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -114,7 +114,6 @@ struct target_so_ops /* Hook for looking up global symbols in a library-specific way. */ struct symbol * (*lookup_lib_global_symbol) (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain); /* Given two so_list objects, one from the GDB thread list @@ -146,7 +145,6 @@ extern struct target_so_ops *current_target_so_ops; /* Handler for library-specific global symbol lookup in solib.c. */ struct symbol *solib_global_lookup (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain); #endif diff --git a/gdb/somread.c b/gdb/somread.c index 36a2b28..4d5bda9 100644 --- a/gdb/somread.c +++ b/gdb/somread.c @@ -435,6 +435,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/spu-tdep.c b/gdb/spu-tdep.c index 7e7ab9c..a014b7a 100644 --- a/gdb/spu-tdep.c +++ b/gdb/spu-tdep.c @@ -1839,7 +1839,7 @@ spu_catch_start (struct objfile *objfile) struct symbol *sym; struct symtab_and_line sal; - sym = lookup_block_symbol (block, "main", NULL, VAR_DOMAIN); + sym = lookup_block_symbol (block, "main", VAR_DOMAIN); if (sym) { fixup_symbol_section (sym, objfile); diff --git a/gdb/stabsread.c b/gdb/stabsread.c index e62bb15..ad6568e 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -322,7 +322,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) if (typenums[0] == -1) { - return (alloc_type (objfile)); + return (alloc_type (objfile, NULL)); } type_addr = dbx_lookup_type (typenums, objfile); @@ -332,7 +332,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile) We will fill it in later if we find out how. */ if (*type_addr == 0) { - *type_addr = alloc_type (objfile); + *type_addr = alloc_type (objfile, NULL); } return (*type_addr); diff --git a/gdb/stack.c b/gdb/stack.c index 1c37801..594eb16 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1308,24 +1308,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)) { @@ -1473,6 +1473,8 @@ print_block_frame_locals (struct block *b, struct frame_info *frame, case LOC_COMPUTED: if (SYMBOL_IS_ARGUMENT (sym)) break; + if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN) + break; values_printed = 1; print_variable_and_value (NULL, sym, frame, stream, 4 * num_tabs); break; diff --git a/gdb/symfile.c b/gdb/symfile.c index 5151966..acca537 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -928,6 +928,17 @@ new_symfile_objfile (struct objfile *objfile, int add_flags) clear_complaints (&symfile_complaints, 0, add_flags & SYMFILE_VERBOSE); } +/* A helper function which returns true if OBJFILE has any debug + symbols, and false otherwise. */ +static int +has_any_debug_symbols (struct objfile *objfile) +{ + return (objfile->psymtabs || objfile->quick_addrmap + || (objfile->separate_debug_objfile + && (objfile->separate_debug_objfile->psymtabs + || objfile->separate_debug_objfile->quick_addrmap))); +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -965,13 +976,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); if (addrs) @@ -1007,6 +1021,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) && print_symbol_loading) { printf_unfiltered (_("expanding to full symbols...")); @@ -1025,7 +1041,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, /* 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->psymtabs == NULL) + if (!has_any_debug_symbols (objfile)) debugfile = find_separate_debug_file (objfile); if (debugfile) { @@ -1049,8 +1065,11 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, xfree (debugfile); } - if (!have_partial_symbols () && !have_full_symbols () - && print_symbol_loading) + /* has_any_debug_symbols is not fully compatible with the former calls which + would just be needlessly expensive here. */ + if ((from_tty || info_verbose) && print_symbol_loading + && (add_flags & SYMFILE_MAINLINE) + && !has_any_debug_symbols (objfile)) { wrap_here (""); printf_unfiltered (_("(no debugging symbols found)")); @@ -1166,7 +1185,9 @@ symbol_file_clear (int from_tty) descriptors as well. */ no_shared_libraries (NULL, from_tty); - symfile_objfile = NULL; + /* free_objfile should have cleared it. */ + gdb_assert (symfile_objfile == NULL); + if (from_tty) printf_unfiltered (_("No symbol file now.\n")); } @@ -2436,13 +2457,15 @@ reread_symbols (void) zero is OK since dbxread.c also does what it needs to do if objfile->global_psymbols.size is 0. */ (*objfile->sf->sym_read) (objfile, 0); - if (!have_partial_symbols () && !have_full_symbols ()) + if (!has_any_debug_symbols (objfile)) { wrap_here (""); printf_unfiltered (_("(no debugging symbols found)\n")); wrap_here (""); } + objfile->flags &= ~OBJF_SYMTABS_READ; + /* We're done reading the symbol file; finish off complaints. */ clear_complaints (&symfile_complaints, 0, 1); @@ -2740,7 +2763,7 @@ allocate_symtab (char *filename, struct objfile *objfile) } struct partial_symtab * -allocate_psymtab (char *filename, struct objfile *objfile) +allocate_psymtab (const char *filename, struct objfile *objfile) { struct partial_symtab *psymtab; @@ -3054,7 +3077,8 @@ again2: struct partial_symtab * start_psymtab_common (struct objfile *objfile, - struct section_offsets *section_offsets, char *filename, + struct section_offsets *section_offsets, + const char *filename, CORE_ADDR textlow, struct partial_symbol **global_syms, struct partial_symbol **static_syms) { diff --git a/gdb/symfile.h b/gdb/symfile.h index bba242c..58bd2d8 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -140,6 +140,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. */ @@ -266,7 +272,7 @@ extern void free_section_addr_info (struct section_addr_info *); extern struct partial_symtab *start_psymtab_common (struct objfile *, struct section_offsets *, - char *, CORE_ADDR, + const char *, CORE_ADDR, struct partial_symbol **, struct partial_symbol **); @@ -316,7 +322,7 @@ extern int auto_solib_limit; extern void set_initial_language (void); -extern struct partial_symtab *allocate_psymtab (char *, struct objfile *); +extern struct partial_symtab *allocate_psymtab (const char *, struct objfile *); extern void discard_psymtab (struct partial_symtab *); @@ -385,7 +391,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 *, int); extern void dwarf2_build_frame_info (struct objfile *); diff --git a/gdb/symmisc.c b/gdb/symmisc.c index eb35369..dfd8c8c 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -1128,7 +1128,7 @@ maintenance_check_symtabs (char *ignore, int from_tty) while (length--) { sym = lookup_block_symbol (b, SYMBOL_LINKAGE_NAME (*psym), - NULL, SYMBOL_DOMAIN (*psym)); + SYMBOL_DOMAIN (*psym)); if (!sym) { printf_filtered ("Static symbol `"); @@ -1145,7 +1145,7 @@ maintenance_check_symtabs (char *ignore, int from_tty) while (length--) { sym = lookup_block_symbol (b, SYMBOL_LINKAGE_NAME (*psym), - NULL, SYMBOL_DOMAIN (*psym)); + SYMBOL_DOMAIN (*psym)); if (!sym) { printf_filtered ("Global symbol `"); diff --git a/gdb/symtab.c b/gdb/symtab.c index c88156a..75b907f 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -42,6 +42,7 @@ #include "ada-lang.h" #include "p-lang.h" #include "addrmap.h" +#include "cp-support.h" #include "hashtab.h" @@ -85,7 +86,6 @@ static int find_line_common (struct linetable *, int, int *); char *operator_chars (char *p, char **end); static struct symbol *lookup_symbol_aux (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain, enum language language, @@ -93,20 +93,19 @@ static struct symbol *lookup_symbol_aux (const char *name, static struct symbol *lookup_symbol_aux_local (const char *name, - const char *linkage_name, const struct block *block, - const domain_enum domain); + const domain_enum domain, + enum language language, + int *is_a_field_of_this); static struct symbol *lookup_symbol_aux_symtabs (int block_index, const char *name, - const char *linkage_name, const domain_enum domain); static struct symbol *lookup_symbol_aux_psymtabs (int block_index, const char *name, - const char *linkage_name, const domain_enum domain); static int file_matches (char *, char **, int); @@ -271,7 +270,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 +413,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; } @@ -474,7 +474,7 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol, || gsymbol->language == language_auto) { demangled = - cplus_demangle (mangled, DMGL_PARAMS | DMGL_ANSI); + cplus_demangle (mangled, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE); if (demangled != NULL) { gsymbol->language = language_cplus; @@ -633,6 +633,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; @@ -658,6 +659,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; @@ -868,7 +870,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; @@ -901,6 +909,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 @@ -1168,6 +1177,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. @@ -1194,10 +1219,14 @@ lookup_symbol_in_language (const char *name, const struct block *block, { char *demangled_name = NULL; const char *modified_name = NULL; - const char *mangled_name = NULL; struct symbol *returnval; struct cleanup *cleanup = make_cleanup (null_cleanup, 0); + if(strncmp(name, "::", 2) == 0){/* this must be a global name */ + name = name+2; + block = NULL; + } + modified_name = name; /* If we are using C++ or Java, demangle the name before doing a lookup, so @@ -1207,7 +1236,6 @@ lookup_symbol_in_language (const char *name, const struct block *block, demangled_name = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS); if (demangled_name) { - mangled_name = name; modified_name = demangled_name; make_cleanup (xfree, demangled_name); } @@ -1229,7 +1257,6 @@ lookup_symbol_in_language (const char *name, const struct block *block, DMGL_ANSI | DMGL_PARAMS | DMGL_JAVA); if (demangled_name) { - mangled_name = name; modified_name = demangled_name; make_cleanup (xfree, demangled_name); } @@ -1248,8 +1275,8 @@ lookup_symbol_in_language (const char *name, const struct block *block, modified_name = copy; } - returnval = lookup_symbol_aux (modified_name, mangled_name, block, - domain, lang, is_a_field_of_this); + returnval = lookup_symbol_aux (modified_name, block, domain, lang, + is_a_field_of_this); do_cleanups (cleanup); return returnval; @@ -1273,9 +1300,9 @@ lookup_symbol (const char *name, const struct block *block, well. */ static struct symbol * -lookup_symbol_aux (const char *name, const char *linkage_name, - const struct block *block, const domain_enum domain, - enum language language, int *is_a_field_of_this) +lookup_symbol_aux (const char *name, const struct block *block, + const domain_enum domain, enum language language, + int *is_a_field_of_this) { struct symbol *sym; const struct language_defn *langdef; @@ -1291,55 +1318,19 @@ lookup_symbol_aux (const char *name, const char *linkage_name, /* Search specified block and its superiors. Don't search STATIC_BLOCK or GLOBAL_BLOCK. */ - sym = lookup_symbol_aux_local (name, linkage_name, block, domain); + sym = lookup_symbol_aux_local (name, block, domain, language, is_a_field_of_this); if (sym != NULL) return sym; - /* If requested to do so by the caller and if appropriate for LANGUAGE, - check to see if NAME is a field of `this'. */ - - langdef = language_def (language); - - if (langdef->la_name_of_this != NULL && is_a_field_of_this != NULL - && block != NULL) - { - struct symbol *sym = NULL; - /* 'this' is only defined in the function's block, so find the - enclosing function block. */ - for (; block && !BLOCK_FUNCTION (block); - block = BLOCK_SUPERBLOCK (block)); - - if (block && !dict_empty (BLOCK_DICT (block))) - sym = lookup_block_symbol (block, langdef->la_name_of_this, - NULL, VAR_DOMAIN); - if (sym) - { - struct type *t = sym->type; - - /* I'm not really sure that type of this can ever - be typedefed; just be safe. */ - CHECK_TYPEDEF (t); - if (TYPE_CODE (t) == TYPE_CODE_PTR - || TYPE_CODE (t) == TYPE_CODE_REF) - t = TYPE_TARGET_TYPE (t); - - if (TYPE_CODE (t) != TYPE_CODE_STRUCT - && TYPE_CODE (t) != TYPE_CODE_UNION) - error (_("Internal error: `%s' is not an aggregate"), - langdef->la_name_of_this); - - if (check_field (t, name)) - { - *is_a_field_of_this = 1; - return NULL; - } - } - } + /* this symbol was found to be a member variable + do not perform the global search. */ + if (is_a_field_of_this && *is_a_field_of_this) + return NULL; /* Now do whatever is appropriate for LANGUAGE to look up static and global variables. */ - - sym = langdef->la_lookup_symbol_nonlocal (name, linkage_name, block, domain); + langdef = language_def (language); + sym = langdef->la_lookup_symbol_nonlocal (name, block, domain); if (sym != NULL) return sym; @@ -1349,11 +1340,11 @@ lookup_symbol_aux (const char *name, const char *linkage_name, desired name as a file-level static, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, linkage_name, domain); + sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, domain); if (sym != NULL) return sym; - sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, linkage_name, domain); + sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, domain); if (sym != NULL) return sym; @@ -1364,30 +1355,81 @@ lookup_symbol_aux (const char *name, const char *linkage_name, Don't search STATIC_BLOCK or GLOBAL_BLOCK. */ static struct symbol * -lookup_symbol_aux_local (const char *name, const char *linkage_name, - const struct block *block, - const domain_enum domain) +lookup_symbol_aux_local (const char *name, const struct block *block, + const domain_enum domain, enum language language, + int *is_a_field_of_this) { struct symbol *sym; - const struct block *static_block = block_static_block (block); + const struct block *global_block = block_global_block (block); + const struct block *block_iterator = block; + const struct language_defn *langdef; + + langdef = language_def (language); /* Check if either no block is specified or it's a global block. */ - if (static_block == NULL) + if (global_block == NULL) return NULL; - while (block != static_block) + while (block_iterator != global_block) { - sym = lookup_symbol_aux_block (name, linkage_name, block, domain); + + sym = lookup_symbol_aux_block (name, block_iterator, domain); + if (sym != NULL) return sym; - - if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block)) - break; - block = BLOCK_SUPERBLOCK (block); + + if (language == language_cplus ) + { + sym = cp_lookup_symbol_imports (block_scope (block_iterator), name, + block_iterator, domain, 1, 1); + + if (sym != NULL) + return sym; + } + + if (langdef->la_name_of_this != NULL && is_a_field_of_this != NULL + && BLOCK_FUNCTION (block_iterator)) + { + if (!dict_empty (BLOCK_DICT (block_iterator))) + { + sym = lookup_block_symbol (block_iterator, + langdef->la_name_of_this, + VAR_DOMAIN); + + + if (sym) + { + struct type *t = sym->type; + + /* I'm not really sure that type of this can ever + be typedefed; just be safe. */ + CHECK_TYPEDEF (t); + if (TYPE_CODE (t) == TYPE_CODE_PTR + || TYPE_CODE (t) == TYPE_CODE_REF) + t = TYPE_TARGET_TYPE (t); + + if (TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error (_("Internal error: `%s' is not an aggregate"), + langdef->la_name_of_this); + + if (check_field (t, name)) + { + *is_a_field_of_this = 1; + return NULL; + } + } + } + } + + if (BLOCK_FUNCTION (block_iterator) != NULL && block_inlined_p (block_iterator)) + break; + + block_iterator = BLOCK_SUPERBLOCK (block_iterator); } - /* We've reached the edge of the function without finding a result. */ + /* We've reached the global block without finding a result. */ return NULL; } @@ -1416,13 +1458,12 @@ lookup_objfile_from_block (const struct block *block) block_found appropriately. */ struct symbol * -lookup_symbol_aux_block (const char *name, const char *linkage_name, - const struct block *block, +lookup_symbol_aux_block (const char *name, const struct block *block, const domain_enum domain) { struct symbol *sym; - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); if (sym) { block_found = block; @@ -1438,7 +1479,6 @@ lookup_symbol_aux_block (const char *name, const char *linkage_name, struct symbol * lookup_global_symbol_from_objfile (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain) { struct symbol *sym; @@ -1452,7 +1492,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile, { bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); if (sym) { block_found = block; @@ -1461,23 +1501,23 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile, } /* Now go through psymtabs. */ + require_partial_symbols ((struct objfile *) objfile); ALL_OBJFILE_PSYMTABS (objfile, ps) { if (!ps->readin - && lookup_partial_symbol (ps, name, linkage_name, - 1, domain)) + && lookup_partial_symbol (ps, name, 1, domain)) { s = PSYMTAB_TO_SYMTAB (ps); bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); return fixup_symbol_section (sym, (struct objfile *)objfile); } } if (objfile->separate_debug_objfile) return lookup_global_symbol_from_objfile (objfile->separate_debug_objfile, - name, linkage_name, domain); + name, domain); return NULL; } @@ -1488,8 +1528,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile, static symbols. */ static struct symbol * -lookup_symbol_aux_symtabs (int block_index, - const char *name, const char *linkage_name, +lookup_symbol_aux_symtabs (int block_index, const char *name, const domain_enum domain) { struct symbol *sym; @@ -1502,7 +1541,7 @@ lookup_symbol_aux_symtabs (int block_index, { bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, block_index); - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); if (sym) { block_found = block; @@ -1520,7 +1559,6 @@ lookup_symbol_aux_symtabs (int block_index, static struct symbol * lookup_symbol_aux_psymtabs (int block_index, const char *name, - const char *linkage_name, const domain_enum domain) { struct symbol *sym; @@ -1531,16 +1569,15 @@ 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, - psymtab_index, domain)) + && lookup_partial_symbol (ps, name, psymtab_index, domain)) { s = PSYMTAB_TO_SYMTAB (ps); bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, block_index); - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); if (!sym) { /* This shouldn't be necessary, but as a last resort try @@ -1557,7 +1594,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name, block = BLOCKVECTOR_BLOCK (bv, block_index == GLOBAL_BLOCK ? STATIC_BLOCK : GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, linkage_name, domain); + sym = lookup_block_symbol (block, name, domain); if (!sym) error (_("Internal: %s symbol `%s' found in %s psymtab but not in symtab.\n%s may be an inlined function, or may be a template function\n(if a template, try specifying an instantiation: %s)."), block_index == GLOBAL_BLOCK ? "global" : "static", @@ -1576,7 +1613,6 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name, struct symbol * basic_lookup_symbol_nonlocal (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain) { @@ -1610,11 +1646,11 @@ basic_lookup_symbol_nonlocal (const char *name, than that one, so I don't think we should worry about that for now. */ - sym = lookup_symbol_static (name, linkage_name, block, domain); + sym = lookup_symbol_static (name, block, domain); if (sym != NULL) return sym; - return lookup_symbol_global (name, linkage_name, block, domain); + return lookup_symbol_global (name, block, domain); } /* Lookup a symbol in the static block associated to BLOCK, if there @@ -1622,14 +1658,13 @@ basic_lookup_symbol_nonlocal (const char *name, struct symbol * lookup_symbol_static (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain) { const struct block *static_block = block_static_block (block); if (static_block != NULL) - return lookup_symbol_aux_block (name, linkage_name, static_block, domain); + return lookup_symbol_aux_block (name, static_block, domain); else return NULL; } @@ -1639,7 +1674,6 @@ lookup_symbol_static (const char *name, struct symbol * lookup_symbol_global (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain) { @@ -1649,15 +1683,15 @@ lookup_symbol_global (const char *name, /* Call library-specific lookup procedure. */ objfile = lookup_objfile_from_block (block); if (objfile != NULL) - sym = solib_global_lookup (objfile, name, linkage_name, domain); + sym = solib_global_lookup (objfile, name, domain); if (sym != NULL) return sym; - sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, linkage_name, domain); + sym = lookup_symbol_aux_symtabs (GLOBAL_BLOCK, name, domain); if (sym != NULL) return sym; - return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, linkage_name, domain); + return lookup_symbol_aux_psymtabs (GLOBAL_BLOCK, name, domain); } int @@ -1681,14 +1715,11 @@ symbol_matches_domain (enum language symbol_language, } /* Look, in partial_symtab PST, for symbol whose natural name is NAME. - If LINKAGE_NAME is non-NULL, check in addition that the symbol's - linkage name matches it. Check the global symbols if GLOBAL, the - static symbols if not */ + Check the global symbols if GLOBAL, the static symbols if not. */ struct partial_symbol * lookup_partial_symbol (struct partial_symtab *pst, const char *name, - const char *linkage_name, int global, - domain_enum domain) + int global, domain_enum domain) { struct partial_symbol *temp; struct partial_symbol **start, **psym; @@ -1740,9 +1771,7 @@ lookup_partial_symbol (struct partial_symtab *pst, const char *name, internal_error (__FILE__, __LINE__, _("failed internal consistency check")); while (top <= real_top - && (linkage_name != NULL - ? strcmp (SYMBOL_LINKAGE_NAME (*top), linkage_name) == 0 - : SYMBOL_MATCHES_SEARCH_NAME (*top,name))) + && SYMBOL_MATCHES_SEARCH_NAME (*top, name)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (*top), SYMBOL_DOMAIN (*top), domain)) @@ -1759,15 +1788,9 @@ lookup_partial_symbol (struct partial_symtab *pst, const char *name, for (psym = start; psym < start + length; psym++) { if (symbol_matches_domain (SYMBOL_LANGUAGE (*psym), - SYMBOL_DOMAIN (*psym), domain)) - { - if (linkage_name != NULL - ? strcmp (SYMBOL_LINKAGE_NAME (*psym), linkage_name) == 0 - : SYMBOL_MATCHES_SEARCH_NAME (*psym, name)) - { - return (*psym); - } - } + SYMBOL_DOMAIN (*psym), domain) + && SYMBOL_MATCHES_SEARCH_NAME (*psym, name)) + return (*psym); } } @@ -1809,22 +1832,25 @@ basic_lookup_transparent_type (const char *name) { bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) { return SYMBOL_TYPE (sym); } } - 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)) + if (!ps->readin && lookup_partial_symbol (ps, name, 1, STRUCT_DOMAIN)) { s = PSYMTAB_TO_SYMTAB (ps); bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (!sym) { /* This shouldn't be necessary, but as a last resort @@ -1833,7 +1859,7 @@ basic_lookup_transparent_type (const char *name) * the psymtab gets it wrong in some cases. */ block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (!sym) error (_("Internal: global symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ @@ -1857,21 +1883,26 @@ basic_lookup_transparent_type (const char *name) { bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) { return SYMBOL_TYPE (sym); } } - 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)) + if (!ps->readin && lookup_partial_symbol (ps, name, 0, STRUCT_DOMAIN)) { s = PSYMTAB_TO_SYMTAB (ps); bv = BLOCKVECTOR (s); block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (!sym) { /* This shouldn't be necessary, but as a last resort @@ -1880,7 +1911,7 @@ basic_lookup_transparent_type (const char *name) * the psymtab gets it wrong in some cases. */ block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, NULL, STRUCT_DOMAIN); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); if (!sym) error (_("Internal: static symbol `%s' found in %s psymtab but not in symtab.\n\ %s may be an inlined function, or may be a template function\n\ @@ -1905,9 +1936,23 @@ 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 (), 1, VAR_DOMAIN)) + { + return pst; + } + } + } + + ALL_PSYMTABS_REQUIRED (objfile, pst) { - if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN)) + if (lookup_partial_symbol (pst, main_name (), 1, VAR_DOMAIN)) { return (pst); } @@ -1925,14 +1970,10 @@ find_main_psymtab (void) search on the symbols. Each symbol which is marked as being a ObjC/C++ symbol (language_cplus or language_objc set) has both the encoded and non-encoded names tested for a match. - - If LINKAGE_NAME is non-NULL, verify that any symbol we find has this - particular mangled name. */ struct symbol * lookup_block_symbol (const struct block *block, const char *name, - const char *linkage_name, const domain_enum domain) { struct dict_iterator iter; @@ -1945,9 +1986,7 @@ lookup_block_symbol (const struct block *block, const char *name, sym = dict_iter_name_next (name, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), - SYMBOL_DOMAIN (sym), domain) - && (linkage_name != NULL - ? strcmp (SYMBOL_LINKAGE_NAME (sym), linkage_name) == 0 : 1)) + SYMBOL_DOMAIN (sym), domain)) return sym; } return NULL; @@ -1967,9 +2006,7 @@ lookup_block_symbol (const struct block *block, const char *name, sym = dict_iter_name_next (name, &iter)) { if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), - SYMBOL_DOMAIN (sym), domain) - && (linkage_name != NULL - ? strcmp (SYMBOL_LINKAGE_NAME (sym), linkage_name) == 0 : 1)) + SYMBOL_DOMAIN (sym), domain)) { sym_found = sym; if (!SYMBOL_IS_ARGUMENT (sym)) @@ -3172,7 +3209,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 740d4e0..461ff95 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -171,9 +171,6 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); #define SYMBOL_SECTION(symbol) (symbol)->ginfo.section #define SYMBOL_OBJ_SECTION(symbol) (symbol)->ginfo.obj_section -#define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ - (symbol)->ginfo.language_specific.cplus_specific.demangled_name - /* Initializes the language dependent portion of a symbol depending upon the language for the symbol. */ #define SYMBOL_INIT_LANGUAGE_SPECIFIC(symbol,language) \ @@ -394,7 +391,13 @@ typedef enum domain_enum_tag FUNCTIONS_DOMAIN, /* All defined types */ - TYPES_DOMAIN + TYPES_DOMAIN, + + /* Fortran common blocks. Their naming must be separate from VAR_DOMAIN. */ + COMMON_BLOCK_DOMAIN, + + /* Fortran module. Their naming must be separate. */ + MODULE_DOMAIN } domain_enum; @@ -990,7 +993,6 @@ extern struct symbol *lookup_symbol (const char *, const struct block *, that can't think of anything better to do. */ extern struct symbol *basic_lookup_symbol_nonlocal (const char *, - const char *, const struct block *, const domain_enum); @@ -1001,7 +1003,6 @@ extern struct symbol *basic_lookup_symbol_nonlocal (const char *, is one; do nothing if BLOCK is NULL or a global block. */ extern struct symbol *lookup_symbol_static (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain); @@ -1009,7 +1010,6 @@ extern struct symbol *lookup_symbol_static (const char *name, necessary). */ extern struct symbol *lookup_symbol_global (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain); @@ -1018,21 +1018,18 @@ extern struct symbol *lookup_symbol_global (const char *name, will fix up the symbol if necessary. */ extern struct symbol *lookup_symbol_aux_block (const char *name, - const char *linkage_name, const struct block *block, const domain_enum domain); /* Lookup a partial symbol. */ extern struct partial_symbol *lookup_partial_symbol (struct partial_symtab *, - const char *, const char *, int, domain_enum); /* lookup a symbol by name, within a specified block */ extern struct symbol *lookup_block_symbol (const struct block *, const char *, - const char *, const domain_enum); /* lookup a [struct, union, enum] by name, within a specified block */ @@ -1062,6 +1059,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 *); @@ -1356,7 +1355,6 @@ extern /*const */ char *main_name (void); /* Check global symbols in objfile. */ struct symbol *lookup_global_symbol_from_objfile (const struct objfile *objfile, const char *name, - const char *linkage_name, const domain_enum domain); extern struct symtabs_and_lines diff --git a/gdb/target.c b/gdb/target.c index 7ee444f..631e5f8 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 *); @@ -584,6 +586,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); @@ -694,6 +697,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); @@ -3095,6 +3101,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) { @@ -3342,6 +3361,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 2c743e9..dbbce12 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -376,6 +376,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; @@ -1120,6 +1121,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) @@ -1157,6 +1167,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); + /* Command logging facility. */ #define target_log_command(p) \ @@ -1276,6 +1300,14 @@ extern struct target_ops *find_target_beneath (struct target_ops *); extern char *target_get_osdata (const char *type); +/* Read OS data object of type TYPE from the target, and return it in + XML format. The result is NUL-terminated and returned as a string, + allocated using xmalloc. If an error occurs or the transfer is + unsupported, NULL is returned. Empty objects are returned as + allocated but empty strings. */ + +extern char *target_get_osdata (const char *type); + /* Stuff that should be shared among the various remote targets. */ diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.exp b/gdb/testsuite/gdb.arch/powerpc-power7.exp new file mode 100644 index 0000000..ae301db --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-power7.exp @@ -0,0 +1,175 @@ +# 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. + +# Test PowerPC Power7 instructions disassembly. + +if {![istarget "powerpc*-*-*"]} then { + verbose "Skipping PowerPC Power7 instructions disassembly." + return +} + +set testfile "powerpc-power7" +set srcfile ${testfile}.s +set objfile ${objdir}/${subdir}/${testfile}.o + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objfile}" object {debug}] != "" } { + untested "PowerPC Power7 instructions disassembly" + return -1 +} + + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${objfile} + + +# Disassemble the function. + +set test "disass func" +gdb_test_multiple $test $test { + -re "\r\nDump of assembler code for function func:(\r\n.*\r\n)End of assembler dump.\r\n$gdb_prompt $" { + set func $expect_out(1,string) + pass $test + } +} + +proc instr_to_patt {offset instr} { + # 0x0000000000000018 : stxvd2x vs43,r4,r5 + return ".*\r\n[string map {0x 0x0*} $offset] :\[ \t\]*[string map [list { } "\[ \t\]+" . {\.}] $instr]\[ \t\]*\r\n.*" +} + +# KFAIL strings would not exist if -Many would print the same as -Mpower7. +# That means the power7 form should be the preferred one. +# http://sourceware.org/ml/gdb-patches/2009-03/threads.html#00020 + +proc func_check {offset instr {kfail ""}} { + global func + + set test "Found $offset: $instr" + if [regexp -nocase -line [instr_to_patt $offset $instr] $func] { + pass $test + } elseif {$kfail != "" && [regexp -nocase -line [instr_to_patt $offset $kfail] $func]} { + kfail gdb/NNNN $test + } else { + fail $test + } +} + +func_check 0x0 "lxvd2x vs3,r4,r5" +func_check 0x4 "lxvd2ux vs3,r4,r5" +func_check 0x8 "lxvd2x vs43,r4,r5" +func_check 0xc "lxvd2ux vs43,r4,r5" +func_check 0x10 "stxvd2x vs3,r4,r5" +func_check 0x14 "stxvd2ux vs3,r4,r5" +func_check 0x18 "stxvd2x vs43,r4,r5" +func_check 0x1c "stxvd2ux vs43,r4,r5" +func_check 0x20 "xxmrghd vs3,vs4,vs5" +func_check 0x24 "xxmrghd vs43,vs44,vs45" +func_check 0x28 "xxmrgld vs3,vs4,vs5" +func_check 0x2c "xxmrgld vs43,vs44,vs45" +func_check 0x30 "xxmrghd vs3,vs4,vs5" +func_check 0x34 "xxmrghd vs43,vs44,vs45" +func_check 0x38 "xxmrgld vs3,vs4,vs5" +func_check 0x3c "xxmrgld vs43,vs44,vs45" +func_check 0x40 "xxpermdi vs3,vs4,vs5,1" +func_check 0x44 "xxpermdi vs43,vs44,vs45,1" +func_check 0x48 "xxpermdi vs3,vs4,vs5,2" +func_check 0x4c "xxpermdi vs43,vs44,vs45,2" +func_check 0x50 "xvmovdp vs3,vs4" +func_check 0x54 "xvmovdp vs43,vs44" +func_check 0x58 "xvmovdp vs3,vs4" +func_check 0x5c "xvmovdp vs43,vs44" +func_check 0x60 "xvcpsgndp vs3,vs4,vs5" +func_check 0x64 "xvcpsgndp vs43,vs44,vs45" +func_check 0x68 "wait" +func_check 0x6c "wait" +func_check 0x70 "waitrsv" +func_check 0x74 "waitrsv" +func_check 0x78 "waitimpl" +func_check 0x7c "waitimpl" +func_check 0x80 "doze" +func_check 0x84 "nap" +func_check 0x88 "sleep" +func_check 0x8c "rvwinkle" +func_check 0x90 "prtyw r3,r4" +func_check 0x94 "prtyd r13,r14" +func_check 0x98 "mfcfar r10" "mfspr r10,28" +func_check 0x9c "mtcfar r11" "mtspr 28,r11" +func_check 0xa0 "cmpb r3,r4,r5" +func_check 0xa4 "lwzcix r10,r11,r12" +func_check 0xa8 "dadd f16,f17,f18" +func_check 0xac "daddq f20,f22,f24" +func_check 0xb0 "dss 3" +func_check 0xb4 "dssall" +func_check 0xb8 "dst r5,r4,1" +func_check 0xbc "dstt r8,r7,0" +func_check 0xc0 "dstst r5,r6,3" +func_check 0xc4 "dststt r4,r5,2" +func_check 0xc8 "divwe r10,r11,r12" +func_check 0xcc "divwe. r11,r12,r13" +func_check 0xd0 "divweo r12,r13,r14" +func_check 0xd4 "divweo. r13,r14,r15" +func_check 0xd8 "divweu r10,r11,r12" +func_check 0xdc "divweu. r11,r12,r13" +func_check 0xe0 "divweuo r12,r13,r14" +func_check 0xe4 "divweuo. r13,r14,r15" +func_check 0xe8 "bpermd r7,r17,r27" +func_check 0xec "popcntw r10,r20" +func_check 0xf0 "popcntd r10,r20" +func_check 0xf4 "ldbrx r20,r21,r22" +func_check 0xf8 "stdbrx r20,r21,r22" +func_check 0xfc "lfiwzx f10,0,r10" +func_check 0x100 "lfiwzx f10,r9,r10" +func_check 0x104 "fcfids f4,f5" +func_check 0x108 "fcfids. f4,f5" +func_check 0x10c "fcfidus f4,f5" +func_check 0x110 "fcfidus. f4,f5" +func_check 0x114 "fctiwu f4,f5" +func_check 0x118 "fctiwu. f4,f5" +func_check 0x11c "fctiwuz f4,f5" +func_check 0x120 "fctiwuz. f4,f5" +func_check 0x124 "fctidu f4,f5" +func_check 0x128 "fctidu. f4,f5" +func_check 0x12c "fctiduz f4,f5" +func_check 0x130 "fctiduz. f4,f5" +func_check 0x134 "fcfidu f4,f5" +func_check 0x138 "fcfidu. f4,f5" +func_check 0x13c "ftdiv cr0,f10,f11" +func_check 0x140 "ftdiv cr7,f10,f11" +func_check 0x144 "ftsqrt cr0,f10" +func_check 0x148 "ftsqrt cr7,f10" +func_check 0x14c "dcbtt r8,r9" "dcbt 16,r8,r9" +func_check 0x150 "dcbtstt r8,r9" "dcbtst 16,r8,r9" +func_check 0x154 "dcffix f10,f12" +func_check 0x158 "dcffix. f20,f22" +func_check 0x15c "lbarx r10,r11,r12" +func_check 0x160 "lbarx r10,r11,r12" +func_check 0x164 "lbarx r10,r11,r12,1" +func_check 0x168 "lharx r20,r21,r22" +func_check 0x16c "lharx r20,r21,r22" +func_check 0x170 "lharx r20,r21,r22,1" +func_check 0x174 "stbcx. r10,r11,r12" +func_check 0x178 "sthcx. r10,r11,r12" +func_check 0x17c "fre f14,f15" +func_check 0x180 "fre. f14,f15" +func_check 0x184 "fres f14,f15" +func_check 0x188 "fres. f14,f15" +func_check 0x18c "frsqrte f14,f15" +func_check 0x190 "frsqrte. f14,f15" +func_check 0x194 "frsqrtes f14,f15" +func_check 0x198 "frsqrtes. f14,f15" +func_check 0x19c "isel r2,r3,r4,28" diff --git a/gdb/testsuite/gdb.arch/powerpc-power7.s b/gdb/testsuite/gdb.arch/powerpc-power7.s new file mode 100644 index 0000000..98b2e79 --- /dev/null +++ b/gdb/testsuite/gdb.arch/powerpc-power7.s @@ -0,0 +1,107 @@ + .text + .globl func +func: + .long 0x7c642e98 /* 0: lxvd2x vs3,r4,r5 */ + .long 0x7c642ed8 /* 4: lxvd2ux vs3,r4,r5 */ + .long 0x7d642e99 /* 8: lxvd2x vs43,r4,r5 */ + .long 0x7d642ed9 /* c: lxvd2ux vs43,r4,r5 */ + .long 0x7c642f98 /* 10: stxvd2x vs3,r4,r5 */ + .long 0x7c642fd8 /* 14: stxvd2ux vs3,r4,r5 */ + .long 0x7d642f99 /* 18: stxvd2x vs43,r4,r5 */ + .long 0x7d642fd9 /* 1c: stxvd2ux vs43,r4,r5 */ + .long 0xf0642850 /* 20: xxmrghd vs3,vs4,vs5 */ + .long 0xf16c6857 /* 24: xxmrghd vs43,vs44,vs45 */ + .long 0xf0642b50 /* 28: xxmrgld vs3,vs4,vs5 */ + .long 0xf16c6b57 /* 2c: xxmrgld vs43,vs44,vs45 */ + .long 0xf0642850 /* 30: xxmrghd vs3,vs4,vs5 */ + .long 0xf16c6857 /* 34: xxmrghd vs43,vs44,vs45 */ + .long 0xf0642b50 /* 38: xxmrgld vs3,vs4,vs5 */ + .long 0xf16c6b57 /* 3c: xxmrgld vs43,vs44,vs45 */ + .long 0xf0642950 /* 40: xxpermdi vs3,vs4,vs5,1 */ + .long 0xf16c6957 /* 44: xxpermdi vs43,vs44,vs45,1 */ + .long 0xf0642a50 /* 48: xxpermdi vs3,vs4,vs5,2 */ + .long 0xf16c6a57 /* 4c: xxpermdi vs43,vs44,vs45,2 */ + .long 0xf0642780 /* 50: xvmovdp vs3,vs4 */ + .long 0xf16c6787 /* 54: xvmovdp vs43,vs44 */ + .long 0xf0642780 /* 58: xvmovdp vs3,vs4 */ + .long 0xf16c6787 /* 5c: xvmovdp vs43,vs44 */ + .long 0xf0642f80 /* 60: xvcpsgndp vs3,vs4,vs5 */ + .long 0xf16c6f87 /* 64: xvcpsgndp vs43,vs44,vs45 */ + .long 0x7c00007c /* 68: wait */ + .long 0x7c00007c /* 6c: wait */ + .long 0x7c20007c /* 70: waitrsv */ + .long 0x7c20007c /* 74: waitrsv */ + .long 0x7c40007c /* 78: waitimpl */ + .long 0x7c40007c /* 7c: waitimpl */ + .long 0x4c000324 /* 80: doze */ + .long 0x4c000364 /* 84: nap */ + .long 0x4c0003a4 /* 88: sleep */ + .long 0x4c0003e4 /* 8c: rvwinkle */ + .long 0x7c830134 /* 90: prtyw r3,r4 */ + .long 0x7dcd0174 /* 94: prtyd r13,r14 */ + .long 0x7d5c02a6 /* 98: mfcfar r10 */ + .long 0x7d7c03a6 /* 9c: mtcfar r11 */ + .long 0x7c832bf8 /* a0: cmpb r3,r4,r5 */ + .long 0x7d4b662a /* a4: lwzcix r10,r11,r12 */ + .long 0xee119004 /* a8: dadd f16,f17,f18 */ + .long 0xfe96c004 /* ac: daddq f20,f22,f24 */ + .long 0x7c60066c /* b0: dss 3 */ + .long 0x7e00066c /* b4: dssall */ + .long 0x7c2522ac /* b8: dst r5,r4,1 */ + .long 0x7e083aac /* bc: dstt r8,r7,0 */ + .long 0x7c6532ec /* c0: dstst r5,r6,3 */ + .long 0x7e442aec /* c4: dststt r4,r5,2 */ + .long 0x7d4b6356 /* c8: divwe r10,r11,r12 */ + .long 0x7d6c6b57 /* cc: divwe. r11,r12,r13 */ + .long 0x7d8d7756 /* d0: divweo r12,r13,r14 */ + .long 0x7dae7f57 /* d4: divweo. r13,r14,r15 */ + .long 0x7d4b6316 /* d8: divweu r10,r11,r12 */ + .long 0x7d6c6b17 /* dc: divweu. r11,r12,r13 */ + .long 0x7d8d7716 /* e0: divweuo r12,r13,r14 */ + .long 0x7dae7f17 /* e4: divweuo. r13,r14,r15 */ + .long 0x7e27d9f8 /* e8: bpermd r7,r17,r27 */ + .long 0x7e8a02f4 /* ec: popcntw r10,r20 */ + .long 0x7e8a03f4 /* f0: popcntd r10,r20 */ + .long 0x7e95b428 /* f4: ldbrx r20,r21,r22 */ + .long 0x7e95b528 /* f8: stdbrx r20,r21,r22 */ + .long 0x7d4056ee /* fc: lfiwzx f10,0,r10 */ + .long 0x7d4956ee /* 100: lfiwzx f10,r9,r10 */ + .long 0xec802e9c /* 104: fcfids f4,f5 */ + .long 0xec802e9d /* 108: fcfids. f4,f5 */ + .long 0xec802f9c /* 10c: fcfidus f4,f5 */ + .long 0xec802f9d /* 110: fcfidus. f4,f5 */ + .long 0xfc80291c /* 114: fctiwu f4,f5 */ + .long 0xfc80291d /* 118: fctiwu. f4,f5 */ + .long 0xfc80291e /* 11c: fctiwuz f4,f5 */ + .long 0xfc80291f /* 120: fctiwuz. f4,f5 */ + .long 0xfc802f5c /* 124: fctidu f4,f5 */ + .long 0xfc802f5d /* 128: fctidu. f4,f5 */ + .long 0xfc802f5e /* 12c: fctiduz f4,f5 */ + .long 0xfc802f5f /* 130: fctiduz. f4,f5 */ + .long 0xfc802f9c /* 134: fcfidu f4,f5 */ + .long 0xfc802f9d /* 138: fcfidu. f4,f5 */ + .long 0xfc0a5900 /* 13c: ftdiv cr0,f10,f11 */ + .long 0xff8a5900 /* 140: ftdiv cr7,f10,f11 */ + .long 0xfc005140 /* 144: ftsqrt cr0,f10 */ + .long 0xff805140 /* 148: ftsqrt cr7,f10 */ + .long 0x7e084a2c /* 14c: dcbtt r8,r9 */ + .long 0x7e0849ec /* 150: dcbtstt r8,r9 */ + .long 0xed406644 /* 154: dcffix f10,f12 */ + .long 0xee80b645 /* 158: dcffix. f20,f22 */ + .long 0x7d4b6068 /* 15c: lbarx r10,r11,r12 */ + .long 0x7d4b6068 /* 160: lbarx r10,r11,r12 */ + .long 0x7d4b6069 /* 164: lbarx r10,r11,r12,1 */ + .long 0x7e95b0e8 /* 168: lharx r20,r21,r22 */ + .long 0x7e95b0e8 /* 16c: lharx r20,r21,r22 */ + .long 0x7e95b0e9 /* 170: lharx r20,r21,r22,1 */ + .long 0x7d4b656d /* 174: stbcx. r10,r11,r12 */ + .long 0x7d4b65ad /* 178: sthcx. r10,r11,r12 */ + .long 0xfdc07830 /* 17c: fre f14,f15 */ + .long 0xfdc07831 /* 180: fre. f14,f15 */ + .long 0xedc07830 /* 184: fres f14,f15 */ + .long 0xedc07831 /* 188: fres. f14,f15 */ + .long 0xfdc07834 /* 18c: frsqrte f14,f15 */ + .long 0xfdc07835 /* 190: frsqrte. f14,f15 */ + .long 0xedc07834 /* 194: frsqrtes f14,f15 */ + .long 0xedc07835 /* 198: frsqrtes. f14,f15 */ + .long 0x7c43271e /* 19c: isel r2,r3,r4,28 */ 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 98d4d35..f98a656 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 71ce4aa..af0e5f8 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 d76cc36..496ff18 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/lineno-makeup-func.c b/gdb/testsuite/gdb.base/lineno-makeup-func.c new file mode 100644 index 0000000..1a0220e --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup-func.c @@ -0,0 +1,21 @@ +/* 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 . */ + +void +func (void) +{ +} diff --git a/gdb/testsuite/gdb.base/lineno-makeup.c b/gdb/testsuite/gdb.base/lineno-makeup.c new file mode 100644 index 0000000..bb20e98 --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup.c @@ -0,0 +1,35 @@ +/* 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 . */ + +/* DW_AT_low_pc-DW_AT_high_pc should cover the function without line number + information (.debug_line) so we cannot use an external object file. + + It must not be just a label as it would alias on the next function even for + correct GDB. Therefore some stub data must be placed there. + + We need to provide a real stub function body as at least s390 + (s390_analyze_prologue) would skip the whole body till reaching `main'. */ + +extern void func (void); +asm ("func: .incbin \"gdb.base/lineno-makeup-func.bin\""); + +int +main (void) +{ + func (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/lineno-makeup.exp b/gdb/testsuite/gdb.base/lineno-makeup.exp new file mode 100644 index 0000000..0c75b84 --- /dev/null +++ b/gdb/testsuite/gdb.base/lineno-makeup.exp @@ -0,0 +1,78 @@ +# 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 "lineno-makeup" +set srcfuncfile ${testfile}-func.c +set srcfile ${testfile}.c +set objfuncfile ${objdir}/${subdir}/${testfile}-func.o +set binfuncfile ${objdir}/${subdir}/${testfile}-func.bin +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfuncfile}" "${objfuncfile}" object {}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +set objcopy [catch "exec objcopy -O binary --only-section .text ${objfuncfile} ${binfuncfile}" output] +verbose -log "objcopy=$objcopy: $output" +if { $objcopy != 0 } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} +set binfuncfilesize [file size $binfuncfile] +verbose -log "file size $binfuncfile = $binfuncfilesize" + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set b_addr "" +set test "break func" +gdb_test_multiple $test $test { + -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+)\r\n$gdb_prompt $" { + set b_addr $expect_out(1,string) + pass $test + } + -re "Breakpoint \[0-9\]+ at (0x\[0-9a-f\]+): .*\r\n$gdb_prompt $" { + set b_addr $expect_out(1,string) + fail $test + } +} +verbose -log "b_addr=<$b_addr>" + +set p_addr "" +set test "print func" +gdb_test_multiple $test $test { + -re "\\$\[0-9\]+ = {} (0x\[0-9a-f\]+) \r\n$gdb_prompt $" { + set p_addr $expect_out(1,string) + pass $test + } +} +verbose -log "p_addr=<$p_addr>" + +set test "break address belongs to func" +if {$b_addr == $p_addr} { + pass "$test (exact match)" +} else { + set skip [expr $b_addr - $p_addr] + if {$skip > 0 && $skip < $binfuncfilesize} { + pass "$test (prologue skip by $skip bytes)" + } else { + fail $test + } +} diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp index 55c4d31..df25d3c 100644 --- a/gdb/testsuite/gdb.base/macscp.exp +++ b/gdb/testsuite/gdb.base/macscp.exp @@ -33,6 +33,14 @@ if [test_compiler_info gcc*] { lappend options additional_flags=-g3 } +# Workaround ccache making lineno non-zero for command-line definitions. +if {[find_gcc] == "gcc" && [file executable "/usr/bin/gcc"]} { + set result [catch "exec which gcc" output] + if {$result == 0 && [string first "/ccache/" $output] >= -1} { + lappend options "compiler=/usr/bin/gcc" + } +} + # Generate the intermediate object file. This is required by Darwin to # have access to the .debug_macinfo section. if {[gdb_compile "${srcdir}/${subdir}/macscp1.c" "${objfile}" \ diff --git a/gdb/testsuite/gdb.base/radix.exp b/gdb/testsuite/gdb.base/radix.exp index 750fd23..dfdb929 100644 --- a/gdb/testsuite/gdb.base/radix.exp +++ b/gdb/testsuite/gdb.base/radix.exp @@ -162,13 +162,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/solib-overlap-lib.c b/gdb/testsuite/gdb.base/solib-overlap-lib.c new file mode 100644 index 0000000..d4aec0d --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-overlap-lib.c @@ -0,0 +1,27 @@ +/* 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 . + + Contributed by Jan Kratochvil . */ + +void +libsym (void) +{ +} + +#ifdef SYMB +void +libsymb (void) +{ +} +#endif diff --git a/gdb/testsuite/gdb.base/solib-overlap-main.c b/gdb/testsuite/gdb.base/solib-overlap-main.c new file mode 100644 index 0000000..1e91dd2 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-overlap-main.c @@ -0,0 +1,25 @@ +/* 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 . + + Contributed by Jan Kratochvil . */ + +#include + +int +main (void) +{ + sleep (60); + + return 1; +} diff --git a/gdb/testsuite/gdb.base/solib-overlap.exp b/gdb/testsuite/gdb.base/solib-overlap.exp new file mode 100644 index 0000000..d644d9b --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-overlap.exp @@ -0,0 +1,139 @@ +# 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 . +# +# Contributed by Jan Kratochvil . + +# Test GDB can cope with two libraries loaded with overlapping VMA ranges. +# Prelink libraries first so they can be loaded and their native address. +# In such case `struct linkmap'.l_addr will be zero. Provide different +# unprelinked library files on the disk which have zero-based VMAs. These +# different files should have their .dynamic section at a different offset in +# page size so that we get for +# warning: .dynamic section for "..." is not at the expected address +# the reason +# (wrong library or version mismatch?) +# and not: +# difference appears to be caused by prelink, adjusting expectations +# In such case both disk libraries will be loaded at VMAs starting at zero. + +if [skip_shlib_tests] { + return 0 +} + +# Are we on a target board? It is required for attaching to a process. +if [is_remote target] { + return 0 +} + +if [get_compiler_info binfile-unused] { + return -1; +} + +# Library file. +set libname "solib-overlap-lib" +set srcfile_lib ${srcdir}/${subdir}/${libname}.c +# Binary file. +set testfile "solib-overlap-main" +set srcfile ${srcdir}/${subdir}/${testfile}.c + +# Base addresses for `prelink -r' which should be compatible with both -m32 and +# -m64 targets. If it clashes with system prelinked libraries it would give +# false PASS. +# Prelink first lib1 at 0x40000000 and lib2 at 0x41000000. +# During second pass try lib1 at 0x50000000 and lib2 at 0x51000000. +foreach prelink_lib1 {0x40000000 0x50000000} { + set prelink_lib2 [format "0x%x" [expr $prelink_lib1 + 0x01000000]] + + set old_prefix $pf_prefix + lappend pf_prefix "$prelink_lib1:" + + # Library file. + set binfile_lib1 ${objdir}/${subdir}/${libname}1-${prelink_lib1}.so + set binfile_lib2 ${objdir}/${subdir}/${libname}2-${prelink_lib1}.so + set lib_flags {debug} + # Binary file. + set binfile_base ${testfile}-${prelink_lib1} + set binfile ${objdir}/${subdir}/${binfile_base} + set bin_flags [list debug shlib=${binfile_lib1} shlib=${binfile_lib2}] + set escapedbinfile [string_to_regexp ${binfile}] + + if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib1} $lib_flags] != "" + || [gdb_compile_shlib ${srcfile_lib} ${binfile_lib2} $lib_flags] != "" + || [gdb_compile ${srcfile} ${binfile} executable $bin_flags] != "" } { + untested "Could not compile ${binfile_lib1}, ${binfile_lib2} or ${binfile}." + return -1 + } + + if {[catch "system \"prelink -N -r ${prelink_lib1} ${binfile_lib1}\""] != 0 + || [catch "system \"prelink -N -r ${prelink_lib2} ${binfile_lib2}\""] != 0} { + # Maybe we don't have prelink. + untested "Could not prelink ${binfile_lib1} or ${binfile_lib2}." + return -1 + } + + # Start the program running and then wait for a bit, to be sure + # that it can be attached to. + + set testpid [eval exec $binfile &] + sleep 2 + if { [istarget "*-*-cygwin*"] } { + # testpid is the Cygwin PID, GDB uses the Windows PID, which might be + # different due to the way fork/exec works. + set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ] + } + + remote_exec build "mv -f ${binfile_lib1} ${binfile_lib1}-running" + remote_exec build "mv -f ${binfile_lib2} ${binfile_lib2}-running" + + # Provide another exported function name to cause different sizes of sections. + lappend lib_flags additional_flags=-DSYMB + + if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib1} $lib_flags] != "" + || [gdb_compile_shlib ${srcfile_lib} ${binfile_lib2} $lib_flags] != ""} { + untested "Could not recompile ${binfile_lib1} or ${binfile_lib2}." + remote_exec build "kill -9 ${testpid}" + return -1 + } + + clean_restart ${binfile_base} + # This testcase currently does not support remote targets. + # gdb_load_shlibs ${binfile_lib1} ${binfile_lib2} + + # Here we should get: + # warning: .dynamic section for ".../solib-overlap-lib1.so" is not at the expected address (wrong library or version mismatch?) + # warning: .dynamic section for ".../solib-overlap-lib2.so" is not at the expected address (wrong library or version mismatch?) + + set test attach + gdb_test_multiple "attach $testpid" $test { + -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*$gdb_prompt $" { + pass $test + } + -re "Attaching to program.*`?$escapedbinfile\.exe'?, process $testpid.*\[Switching to thread $testpid\..*\].*$gdb_prompt $" { + # Response expected on Cygwin + pass $test + } + } + + # Detach the process. + + gdb_test "detach" "Detaching from program: .*$escapedbinfile, process $testpid" + + # Wait a bit for gdb to finish detaching + + sleep 5 + + remote_exec build "kill -9 ${testpid}" + + set pf_prefix $old_prefix +} diff --git a/gdb/testsuite/gdb.base/valgrind-attach.c b/gdb/testsuite/gdb.base/valgrind-attach.c new file mode 100644 index 0000000..84b57db --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.c @@ -0,0 +1,28 @@ +/* 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 . */ + +#include + +int +main (void) +{ + int *a = malloc (1); + + a[10] = 0; /* crash-here */ + + return 0; +} diff --git a/gdb/testsuite/gdb.base/valgrind-attach.exp b/gdb/testsuite/gdb.base/valgrind-attach.exp new file mode 100644 index 0000000..1f9b26e --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.exp @@ -0,0 +1,94 @@ +# 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 valgrind-attach +set shfile ${testfile}.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 +} + +gdb_exit +gdb_stop_suppressing_tests; + +set VALGRIND "valgrind" + +# Syntax for ${shfile} is: +set VALGRIND_SPAWN "sh ${srcdir}/${subdir}/${shfile} $binfile $VALGRIND $GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]" + +set test "spawn valgrind" +verbose "Spawning $VALGRIND_SPAWN" + +if [info exists gdb_spawn_id] { + fail $test + return -1 +} + +if ![is_remote host] { + if { [which $VALGRIND] == 0 } then { + untested "Couldn't find $VALGRIND" + return -1 + } +} +set res [remote_spawn host "$VALGRIND_SPAWN"] +if { $res < 0 || $res == "" } { + perror "Spawning $VALGRIND_SPAWN failed." + return -1 +} +set gdb_spawn_id -1; + +gdb_expect { + -re "---- Attach to debugger \\? --- \\\[Return/N/n/Y/y/C/c\\\] ---- $" { + pass $test + } + eof { + perror "(eof) $VALGRIND never initialized" + remote_close host + return -1 + } + timeout { + perror "(timeout) $VALGRIND never initialized" + remote_close host + return -1 + } +} +send_gdb "y\n" + +set test "spawn gdb" +set test2 "crash line caught" +gdb_expect { + -re "starting debugger with cmd:.* in main .* crash-here .*\[\r\n\]$gdb_prompt $" { + pass $test + pass $test2 + } + -re "starting debugger with cmd:.*\[\r\n\]$gdb_prompt $" { + pass $test + fail $test2 + } + eof { + perror "(eof) $GDB never initialized" + remote_close host + return -1 + } + timeout { + perror "(timeout) $GDB never initialized" + remote_close host + return -1 + } +} + +remote_close host diff --git a/gdb/testsuite/gdb.base/valgrind-attach.sh b/gdb/testsuite/gdb.base/valgrind-attach.sh new file mode 100755 index 0000000..f02c6f7 --- /dev/null +++ b/gdb/testsuite/gdb.base/valgrind-attach.sh @@ -0,0 +1,20 @@ +#! /bin/sh + +# 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 . + +BINFILE="$1"; shift +VALGRIND="$1"; shift +"$VALGRIND" --db-attach=yes --db-command="$* %f %p" "$BINFILE" 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.base/watchpoint-hw.c b/gdb/testsuite/gdb.base/watchpoint-hw.c index 8da9af5..e2de53a 100644 --- a/gdb/testsuite/gdb.base/watchpoint-hw.c +++ b/gdb/testsuite/gdb.base/watchpoint-hw.c @@ -20,5 +20,11 @@ int watchee; int main (void) { + volatile int dummy; + + dummy = watchee; + dummy = 1; + dummy = 2; /* break-at-exit */ + return 0; } diff --git a/gdb/testsuite/gdb.base/watchpoint-hw.exp b/gdb/testsuite/gdb.base/watchpoint-hw.exp index a2bb731..d74d6c7 100644 --- a/gdb/testsuite/gdb.base/watchpoint-hw.exp +++ b/gdb/testsuite/gdb.base/watchpoint-hw.exp @@ -21,19 +21,12 @@ if {(![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] return } -set testfile watchpoint-hw -set srcfile ${testfile}.c -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { - untested "Couldn't compile test program" +set test watchpoint-hw +set srcfile ${test}.c +if { [prepare_for_testing ${test}.exp ${test} ${srcfile}] } { return -1 } -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - # Create the watchpoint before the inferior gets started. Now the native CPU # target is still not active and its `to_can_use_hw_breakpoint' is not # installed, therefore only a software watchpoint gets created. @@ -43,10 +36,40 @@ gdb_test "watch watchee" "atchpoint 1: watchee" # `runto_main' or `runto main' would delete the watchpoint created above. if { [gdb_start_cmd] < 0 } { - untested start + untested ${test}.exp return -1 } gdb_test "" "main .* at .*" "start" # Check it is really a `hw'-watchpoint. gdb_test "info watchpoints" "1 *hw watchpoint .* watchee" + +# Before the inferior gets started we would get: +# Target does not support this type of hardware watchpoint. +gdb_test "delete 1" +gdb_test "rwatch watchee" + +set breakline [gdb_get_line_number "break-at-exit"] +gdb_breakpoint $breakline + +gdb_test "continue" "Continuing.\r\nHardware read watchpoint 3: watchee\r\n\r\nValue = 0\r\n.*" + +# Here should be no repeated notification of the read watchpoint. +gdb_test "continue" \ + "Continuing\\.\[ \r\n\]+Breakpoint \[0-9\]+, .*break-at-exit.*" \ + "continue to break-at-exit after rwatch" + +clean_restart ${test} + +if ![runto_main] { + untested ${test}.exp + return -1 +} + +gdb_test "hbreak ${srcfile}:${breakline}" \ + "Hardware assisted breakpoint 2 at 0x\[0-9a-f\]+: file .*${srcfile}, line ${breakline}\\." \ + "hbreak" + +gdb_test "continue" \ + "Continuing\\.\[ \r\n\]+Breakpoint \[0-9\]+, .*break-at-exit.*" \ + "continue to break-at-exit after hbreak" diff --git a/gdb/testsuite/gdb.cp/cp-relocate.exp b/gdb/testsuite/gdb.cp/cp-relocate.exp index 4095ccf..03c07d5 100644 --- a/gdb/testsuite/gdb.cp/cp-relocate.exp +++ b/gdb/testsuite/gdb.cp/cp-relocate.exp @@ -30,7 +30,7 @@ proc get_func_address { func } { global gdb_prompt hex set rfunc [string_to_regexp $func] - gdb_test_multiple "print '${func}'" "get address of ${func}" { + gdb_test_multiple "print ${func}" "get address of ${func}" { -re "\\\$\[0-9\]+ = \\{.*\\} (0|($hex) <${rfunc}>)\[\r\n\]+${gdb_prompt} $" { # $1 = {int ()} 0x24 # But if the function is at zero, the name may be omitted. @@ -130,7 +130,7 @@ gdb_test "add-symbol-file ${binfile} 0 -s ${func1_sec} 0x10000 -s ${func2_sec} 0 "y" # Make sure the function addresses were updated. -gdb_test "break *'$func1_name'" \ +gdb_test "break *$func1_name" \ "Breakpoint $decimal at 0x1....: file .*" -gdb_test "break *'$func2_name'" \ +gdb_test "break *$func2_name" \ "Breakpoint $decimal at 0x2....: file .*" diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.cc b/gdb/testsuite/gdb.cp/cplusfuncs.cc index 7f033d6..1a50a32 100644 --- a/gdb/testsuite/gdb.cp/cplusfuncs.cc +++ b/gdb/testsuite/gdb.cp/cplusfuncs.cc @@ -191,6 +191,12 @@ char * dm_type_char_star (char * p) { return p; } int dm_type_foo_ref (foo & foo) { return foo.ifoo; } int * dm_type_int_star (int * p) { return p; } long * dm_type_long_star (long * p) { return p; } +int dm_type_short (short i) { return i; } +int dm_type_long (long i) { return i; } int dm_type_unsigned_int (unsigned int i) { return i; } +int dm_type_unsigned_short (unsigned short i) { return i; } +int dm_type_unsigned_long (unsigned long i) { return i; } int dm_type_void (void) { return 0; } void * dm_type_void_star (void * p) { return p; } +typedef int myint; +int dm_type_typedef (myint i) { return i; } diff --git a/gdb/testsuite/gdb.cp/cplusfuncs.exp b/gdb/testsuite/gdb.cp/cplusfuncs.exp index 5e08768..8c8e038 100644 --- a/gdb/testsuite/gdb.cp/cplusfuncs.exp +++ b/gdb/testsuite/gdb.cp/cplusfuncs.exp @@ -66,9 +66,25 @@ set dm_type_unsigned_int "unsigned" set dm_type_void "" set dm_type_void_star "void*" +# Some other vagaries of GDB's type printing machinery. The integer types +# may have unsigned before or after their length, and may have "int" +# appended. The char* conversion operator may have name "char*" even if +# the type is "char *", because the name comes from the debug information +# and the type from GDB. Function types may not see through typedefs. + +set dm_type_short "short" +set dm_type_long "long" +set dm_type_unsigned_short "unsigned short" +set dm_type_unsigned_long "unsigned long" +set dm_operator_char_star "char*" +set dm_operator_char_star_quoted "char\\*" +set dm_type_typedef 0 + proc probe_demangler { } { global gdb_prompt global dm_operator_comma + global dm_operator_char_star + global dm_operator_char_star_quoted global dm_type_char_star global dm_type_char_star_quoted global dm_type_foo_ref @@ -77,6 +93,11 @@ proc probe_demangler { } { global dm_type_unsigned_int global dm_type_void global dm_type_void_star + global dm_type_short + global dm_type_unsigned_short + global dm_type_long + global dm_type_unsigned_long + global dm_type_typedef send_gdb "print &'foo::operator,(foo&)'\n" gdb_expect { @@ -97,6 +118,26 @@ proc probe_demangler { } { } } + send_gdb "print &'foo::operator char*()'\n" + gdb_expect { + -re ".*foo::operator char \\*\\(void\\).*\r\n$gdb_prompt $" { + # v2 demangler or GDB type printer + set dm_operator_char_star "char *" + set dm_operator_char_star_quoted "char \\*" + pass "detect dm_operator_char_star" + } + -re ".*foo::operator char\\*\\(\\).*\r\n$gdb_prompt $" { + # v3 demangler + pass "detect dm_operator_char_star" + } + -re ".*$gdb_prompt $" { + fail "detect dm_operator_char_star" + } + timeout { + fail "detect dm_operator_char_star" + } + } + send_gdb "print &'dm_type_char_star'\n" gdb_expect { -re ".*dm_type_char_star\\(char \\*\\).*\r\n$gdb_prompt $" { @@ -166,6 +207,11 @@ proc probe_demangler { } { # v3 demangler pass "detect dm_type_long_star" } + -re ".*dm_type_long_star\\(long int \\*\\).*\r\n$gdb_prompt $" { + # GCC v3 and GDB's type printer + set dm_type_long_star "long int *" + pass "detect dm_type_long_star" + } -re ".*$gdb_prompt $" { fail "detect dm_type_long_star" } @@ -230,6 +276,101 @@ proc probe_demangler { } { fail "detect dm_type_void_star (timeout)" } } + + send_gdb "print &'dm_type_short'\n" + gdb_expect { + -re ".*dm_type_short\\(short\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_short" + } + -re ".*dm_type_short\\(short int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_short "short int" + pass "detect dm_type_short" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_short" + } + timeout { + fail "detect dm_type_short (timeout)" + } + } + + send_gdb "print &'dm_type_unsigned_short'\n" + gdb_expect { + -re ".*dm_type_unsigned_short\\(unsigned short\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_unsigned_short" + } + -re ".*dm_type_unsigned_short\\(short unsigned int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_unsigned_short "short unsigned int" + pass "detect dm_type_unsigned_short" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_unsigned_short" + } + timeout { + fail "detect dm_type_unsigned_short (timeout)" + } + } + + send_gdb "print &'dm_type_long'\n" + gdb_expect { + -re ".*dm_type_long\\(long\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_long" + } + -re ".*dm_type_long\\(long int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_long "long int" + pass "detect dm_type_long" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_long" + } + timeout { + fail "detect dm_type_long (timeout)" + } + } + + send_gdb "print &'dm_type_unsigned_long'\n" + gdb_expect { + -re ".*dm_type_unsigned_long\\(unsigned long\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_unsigned_long" + } + -re ".*dm_type_unsigned_long\\(long unsigned int\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_unsigned_long "long unsigned int" + pass "detect dm_type_unsigned_long" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_unsigned_long" + } + timeout { + fail "detect dm_type_unsigned_long (timeout)" + } + } + + send_gdb "print &'dm_type_typedef'\n" + gdb_expect { + -re ".*dm_type_typedef\\(int\\).*\r\n$gdb_prompt $" { + # v2 and v3 demanglers + pass "detect dm_type_typedef" + } + -re ".*dm_type_typedef\\(myint\\).*\r\n$gdb_prompt $" { + # GDB type printer + set dm_type_typedef 1 + pass "detect dm_type_typedef" + } + -re ".*$gdb_prompt $" { + fail "detect dm_type_typedef" + } + timeout { + fail "detect dm_type_typedef (timeout)" + } + } } # @@ -345,8 +486,9 @@ proc print_addr { name } { proc test_lookup_operator_functions {} { global dm_operator_comma + global dm_operator_char_star global dm_type_char_star - global dm_type_char_star_quoted + global dm_operator_char_star_quoted global dm_type_foo_ref global dm_type_void global dm_type_void_star @@ -404,8 +546,8 @@ proc test_lookup_operator_functions {} { info_func "operator int(" "int foo::operator int($dm_type_void);" info_func "operator()(" "void foo::operator()($dm_type_foo_ref);" - info_func "operator $dm_type_char_star_quoted\(" \ - "char *foo::operator $dm_type_char_star\($dm_type_void);" + info_func "operator $dm_operator_char_star_quoted\(" \ + "char *foo::operator $dm_operator_char_star\($dm_type_void);" } @@ -420,6 +562,7 @@ proc test_paddr_operator_functions {} { global dm_type_unsigned_int global dm_type_void global dm_type_void_star + global dm_operator_char_star print_addr "foo::operator*($dm_type_foo_ref)" print_addr "foo::operator%($dm_type_foo_ref)" @@ -470,7 +613,7 @@ proc test_paddr_operator_functions {} { } print_addr "foo::operator int($dm_type_void)" - print_addr "foo::operator $dm_type_char_star\($dm_type_void)" + print_addr "foo::operator $dm_operator_char_star\($dm_type_void)" } # @@ -480,17 +623,21 @@ proc test_paddr_operator_functions {} { proc test_paddr_overloaded_functions {} { global dm_type_unsigned_int global dm_type_void + global dm_type_short + global dm_type_unsigned_short + global dm_type_long + global dm_type_unsigned_long print_addr "overload1arg($dm_type_void)" print_addr "overload1arg(char)" print_addr "overload1arg(signed char)" print_addr "overload1arg(unsigned char)" - print_addr "overload1arg(short)" - print_addr "overload1arg(unsigned short)" + print_addr "overload1arg($dm_type_short)" + print_addr "overload1arg($dm_type_unsigned_short)" print_addr "overload1arg(int)" print_addr "overload1arg($dm_type_unsigned_int)" - print_addr "overload1arg(long)" - print_addr "overload1arg(unsigned long)" + print_addr "overload1arg($dm_type_long)" + print_addr "overload1arg($dm_type_unsigned_long)" print_addr "overload1arg(float)" print_addr "overload1arg(double)" @@ -513,17 +660,31 @@ proc test_paddr_hairy_functions {} { global dm_type_char_star global dm_type_int_star global dm_type_long_star + global dm_type_typedef print_addr_2 "hairyfunc1" "hairyfunc1(int)" - print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" - print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" - print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" - - # gdb-gnats bug gdb/19: - # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" - print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" - print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" - print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" + + if {$dm_type_typedef == 0} { + print_addr_2 "hairyfunc2" "hairyfunc2(int (*)($dm_type_char_star))" + print_addr_2 "hairyfunc3" "hairyfunc3(int (*)(short (*)($dm_type_long_star)))" + print_addr_2 "hairyfunc4" "hairyfunc4(int (*)(short (*)($dm_type_char_star)))" + + # gdb-gnats bug gdb/19: + # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" + print_addr_2_kfail "hairyfunc5" "hairyfunc5(int (*(*)($dm_type_char_star))(long))" "hairyfunc5(int (*)(long) (*)(char*))" "gdb/19" + print_addr_2_kfail "hairyfunc6" "hairyfunc6(int (*(*)($dm_type_int_star))(long))" "hairyfunc6(int (*)(long) (*)(int*))" "gdb/19" + print_addr_2_kfail "hairyfunc7" "hairyfunc7(int (*(*)(int (*)($dm_type_char_star)))(long))" "hairyfunc7(int (*)(long) (*)(int (*)(char*)))" "gdb/19" + } else { + print_addr_2 "hairyfunc2" "hairyfunc2(PFPc_i)" + print_addr_2 "hairyfunc3" "hairyfunc3(PFPFPl_s_i)" + print_addr_2 "hairyfunc4" "hairyfunc4(PFPFPc_s_i)" + + # gdb-gnats bug gdb/19: + # "gdb v3 demangler fails on hairyfunc5 hairyfunc6 hairyfunc7" + print_addr_2 "hairyfunc5" "hairyfunc5(PFPc_PFl_i)" + print_addr_2 "hairyfunc6" "hairyfunc6(PFPi_PFl_i)" + print_addr_2 "hairyfunc7" "hairyfunc7(PFPFPc_i_PFl_i)" + } } proc do_tests {} { diff --git a/gdb/testsuite/gdb.cp/expand-sals.exp b/gdb/testsuite/gdb.cp/expand-sals.exp index 3c302c3..cd0496d 100644 --- a/gdb/testsuite/gdb.cp/expand-sals.exp +++ b/gdb/testsuite/gdb.cp/expand-sals.exp @@ -48,7 +48,7 @@ gdb_continue_to_breakpoint "caller" ".*caller-line.*" # Test GDB caught this return call and not the next one through B::B() gdb_test "bt" \ - "#0 \[^\r\n\]* A \[^\r\n\]*\r\n#1 \[^\r\n\]* main \[^\r\n\]*" \ + "#0 \[^\r\n\]* (A::)?A \[^\r\n\]*\r\n#1 \[^\r\n\]* main \[^\r\n\]*" \ "bt from A" gdb_continue_to_breakpoint "next caller func" ".*func-line.*" diff --git a/gdb/testsuite/gdb.cp/member-ptr.cc b/gdb/testsuite/gdb.cp/member-ptr.cc index 1dff70a..648b2af 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.cc +++ b/gdb/testsuite/gdb.cp/member-ptr.cc @@ -138,6 +138,7 @@ class Diamond : public Padding, public Left, public Right { public: virtual int vget_base (); + int (*func_ptr) (int); }; int Diamond::vget_base () @@ -145,6 +146,12 @@ int Diamond::vget_base () return this->Left::x + 2000; } +int +func (int x) +{ + return 19 + x; +} + int main () { A a; @@ -162,6 +169,7 @@ int main () int (Diamond::*right_vpmf) (); int (Base::*base_vpmf) (); int Diamond::*diamond_pmi; + int (* Diamond::*diamond_pfunc_ptr) (int); PMI null_pmi; PMF null_pmf; @@ -179,6 +187,7 @@ int main () diamond.Left::x = 77; diamond.Right::x = 88; + diamond.func_ptr = func; /* Some valid pointer to members from a base class. */ left_pmf = (int (Diamond::*) ()) (int (Left::*) ()) (&Base::get_x); @@ -193,11 +202,19 @@ int main () /* A pointer to data member from a base class. */ diamond_pmi = (int Diamond::*) (int Left::*) &Base::x; + /* A pointer to data member, where the member is itself a pointer to + a function. */ + diamond_pfunc_ptr = (int (* Diamond::*) (int)) &Diamond::func_ptr; + null_pmi = NULL; null_pmf = NULL; pmi = NULL; /* Breakpoint 1 here. */ + // Invalid (uses diamond_pfunc_ptr as a function): + // diamond.*diamond_pfunc_ptr (20); + (diamond.*diamond_pfunc_ptr) (20); + k = (a.*pmf)(3); pmi = &A::jj; diff --git a/gdb/testsuite/gdb.cp/member-ptr.exp b/gdb/testsuite/gdb.cp/member-ptr.exp index b69d4ad..83dd0d5 100644 --- a/gdb/testsuite/gdb.cp/member-ptr.exp +++ b/gdb/testsuite/gdb.cp/member-ptr.exp @@ -390,6 +390,33 @@ gdb_test_multiple "print ((int) pmi) == ((char *) &a.j - (char *) & a)" $name { } } +# Check pointers to data members, which are themselves pointers to +# functions. These behave like data members, not like pointers to +# member functions. + +gdb_test "ptype diamond_pfunc_ptr" \ + "type = int \\(\\*Diamond::\\*\\)\\(int\\)" + +gdb_test "ptype diamond.*diamond_pfunc_ptr" \ + "type = int \\(\\*\\)\\(int\\)" + +# This one is invalid; () binds more tightly than .*, so it tries to +# call the member pointer as a normal pointer-to-function. + +gdb_test "print diamond.*diamond_pfunc_ptr (20)" \ + "Invalid data type for function to be called." + +# With parentheses, it is valid. + +gdb_test "print (diamond.*diamond_pfunc_ptr) (20)" \ + "$vhn = 39" + +# Make sure that we do not interpret this as either a member pointer +# call or a member function call. + +gdb_test "print diamond.func_ptr (20)" \ + "$vhn = 39" + # ========================== # pointer to member function # ========================== @@ -420,7 +447,7 @@ gdb_test_multiple "ptype pmf" $name { set name "print pmf" gdb_test_multiple "print pmf" $name { - -re "$vhn = $hex \r\n$gdb_prompt $" { + -re "$vhn = \\(int \\(A::\\*\\)\\(A \\*, int\\)\\) $hex \r\n$gdb_prompt $" { pass $name } -re "$vhn = .*not supported with HP aCC.*\r\n$gdb_prompt $" { @@ -608,6 +635,9 @@ gdb_test_multiple "print (a.*pmf)(3)" $name { } } +gdb_test "ptype a.*pmf" "type = int \\(A \\*, int\\)" +gdb_test "ptype (a.*pmf)(3)" "type = int" + # Print out a pointer to data member which requires looking into # a base class. gdb_test "print diamond_pmi" "$vhn = &Base::x" @@ -658,5 +688,5 @@ gdb_test "print null_pmi = &A::j" "$vhn = &A::j" gdb_test "print null_pmi = 0" "$vhn = NULL" gdb_test "print null_pmf" "$vhn = NULL" -gdb_test "print null_pmf = &A::foo" "$vhn = $hex " +gdb_test "print null_pmf = &A::foo" "$vhn = \\(int \\(A::\\*\\)\\(A \\*, int\\)\\) $hex " gdb_test "print null_pmf = 0" "$vhn = NULL" diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc new file mode 100644 index 0000000..6b180d6 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.cc @@ -0,0 +1,20 @@ +namespace A { + int x = 11; + namespace{ + int xx = 22; + } +} + +using namespace A; + +namespace{ + int xxx = 33; +}; + +int main() +{ + x; + xx; + xxx; + return 0; +} diff --git a/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp new file mode 100644 index 0000000..e4bb9f8 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-multiple-imports.exp @@ -0,0 +1,49 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-multiple-imports +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ +# test printing of namespace imported within +# the function. + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_test "print x" "\\$\[0-9\].* = 11" +gdb_test "print xx" "\\$\[0-9\].* = 22" +gdb_test "print xxx" "\\$\[0-9\].* = 33" diff --git a/gdb/testsuite/gdb.cp/namespace-nested-imports.cc b/gdb/testsuite/gdb.cp/namespace-nested-imports.cc new file mode 100644 index 0000000..9723f87 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-nested-imports.cc @@ -0,0 +1,36 @@ +namespace A +{ + namespace B + { + int ab = 11; + } +} + +namespace C +{ + namespace D + { + using namespace A::B; + + int + second() + { + ab; + return 0; + } + } + + int + first() + { + //ab; + return D::second(); + } +} + +int +main() +{ + //ab; + return C::first(); +} diff --git a/gdb/testsuite/gdb.cp/namespace-nested-imports.exp b/gdb/testsuite/gdb.cp/namespace-nested-imports.exp new file mode 100644 index 0000000..d279fb5 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-nested-imports.exp @@ -0,0 +1,57 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-nested-imports +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +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 ab" "No symbol .* in current context." + +############################################ +gdb_breakpoint C::first +gdb_continue_to_breakpoint "C::first" + +gdb_test "print ab" "No symbol .* in current context." +gdb_test "print C::D::ab" "= 11" + +############################################ +gdb_breakpoint C::D::second +gdb_continue_to_breakpoint "C::D::second" + +gdb_test "print ab" "= 11" diff --git a/gdb/testsuite/gdb.cp/namespace-no-imports.cc b/gdb/testsuite/gdb.cp/namespace-no-imports.cc new file mode 100644 index 0000000..d1c68ab --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-no-imports.cc @@ -0,0 +1,37 @@ + +namespace A +{ + int _a = 11; + + namespace B{ + + int ab = 22; + + namespace C{ + + int abc = 33; + + int second(){ + return 0; + } + + } + + int first(){ + _a; + ab; + C::abc; + return C::second(); + } + } +} + + +int +main() +{ + A::_a; + A::B::ab; + A::B::C::abc; + return A::B::first(); +} diff --git a/gdb/testsuite/gdb.cp/namespace-no-imports.exp b/gdb/testsuite/gdb.cp/namespace-no-imports.exp new file mode 100644 index 0000000..e508103 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-no-imports.exp @@ -0,0 +1,76 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-no-imports +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +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 A::_a" "= 11" +gdb_test "print A::B::ab" "= 22" +gdb_test "print A::B::C::abc" "= 33" + +gdb_test "print _a" "No symbol .* in current context." +gdb_test "print ab" "No symbol .* in current context." +gdb_test "print abc" "No symbol .* in current context." + +############################################ +gdb_breakpoint A::B::first +gdb_continue_to_breakpoint "A::B::first" + +gdb_test "print A::_a" "= 11" +gdb_test "print A::B::ab" "= 22" +gdb_test "print A::B::C::abc" "= 33" + +gdb_test "print _a" "= 11" +gdb_test "print ab" "= 22" +gdb_test "print C::abc" "= 33" + +gdb_test "print abc" "No symbol .* in current context." + +############################################ +gdb_breakpoint A::B::C::second +gdb_continue_to_breakpoint "A::B::C::second" + +gdb_test "print A::_a" "= 11" +gdb_test "print A::B::ab" "= 22" +gdb_test "print A::B::C::abc" "= 33" + +gdb_test "print _a" "= 11" +gdb_test "print ab" "= 22" +gdb_test "print abc" "= 33" diff --git a/gdb/testsuite/gdb.cp/namespace-recursive.cc b/gdb/testsuite/gdb.cp/namespace-recursive.cc new file mode 100644 index 0000000..84605a6 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-recursive.cc @@ -0,0 +1,30 @@ +namespace A{ + int ax = 9; +} + +namespace B{ + using namespace A; +} + +namespace C{ + using namespace B; +} + +//--------------- +namespace D{ + using namespace D; + int dx = 99; +} +using namespace C; + +//--------------- +namespace{ + namespace{ + int xx = 999; + } +} + +int main(){ + using namespace D; + return ax + dx + xx; +} diff --git a/gdb/testsuite/gdb.cp/namespace-recursive.exp b/gdb/testsuite/gdb.cp/namespace-recursive.exp new file mode 100644 index 0000000..ebc898f --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-recursive.exp @@ -0,0 +1,66 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-recursive +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +if [get_compiler_info ${binfile}] { + return -1; +} + + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +############################################ +# test printing from namespace imported into +# imported namespace + +gdb_test "print ax" "= 9" + +############################################ +# test that gdb can print without falling +# into search loop + +gdb_test "print dx" "= 99" + +############################################ +# test printing from namespace imported into +# imported namespace where imports are implicit +# anonymous namespace imports. + +gdb_test "print xx" "= 999" + diff --git a/gdb/testsuite/gdb.cp/namespace-stress.cc b/gdb/testsuite/gdb.cp/namespace-stress.cc new file mode 100644 index 0000000..f34083e --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-stress.cc @@ -0,0 +1,60 @@ + +namespace A{ int x; } +namespace B{ int x; } +namespace C{ int x; } +namespace D{ int x; } +namespace E{ int x; } +namespace F{ int x; } +namespace G{ int x; } +namespace H{ int x; } +namespace I{ int x; } +namespace J{ int x; } +namespace K{ int x; } +namespace L{ int x; } +namespace M{ int x; } +namespace N{ int x; } +namespace O{ int x; } +namespace P{ int x; } +namespace Q{ int x; } +namespace R{ int x; } +namespace S{ int x; } +namespace T{ int x; } +namespace U{ int x; } +namespace V{ int x; } +namespace W{ int x; } +namespace X{ int x; } +namespace Y{ int x; } +namespace Z{ int x; } + + +int main(){ + + using namespace A; + using namespace B; + using namespace C; + using namespace D; + using namespace E; + using namespace F; + using namespace G; + using namespace H; + using namespace I; + using namespace J; + using namespace K; + using namespace L; + using namespace M; + using namespace N; + using namespace O; + using namespace P; + using namespace Q; + using namespace R; + using namespace S; + using namespace T; + using namespace U; + using namespace V; + using namespace W; + using namespace X; + using namespace Y; + using namespace Z; + + return 0; +} \ No newline at end of file diff --git a/gdb/testsuite/gdb.cp/namespace-stress.exp b/gdb/testsuite/gdb.cp/namespace-stress.exp new file mode 100644 index 0000000..1806523 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-stress.exp @@ -0,0 +1,50 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile namespace-stress +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +if [get_compiler_info ${binfile}] { + return -1; +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +############################################ +# Test that the search can fail efficiently + +gdb_test "print y" "No symbol \"y\" in current context." diff --git a/gdb/testsuite/gdb.cp/namespace-using.cc b/gdb/testsuite/gdb.cp/namespace-using.cc index 4786fd5..8ff5622 100644 --- a/gdb/testsuite/gdb.cp/namespace-using.cc +++ b/gdb/testsuite/gdb.cp/namespace-using.cc @@ -1,26 +1,129 @@ +namespace M +{ + int x = 911; +} + +namespace N +{ + int x = 912; +} + +int marker10 () +{ + using namespace M; + int y = x + 1; // marker10 stop + using namespace N; + return y; +} + +namespace J +{ + int jx = 44; +} + +namespace K +{ + int + marker9 () + { + //x; + return marker10 (); + } +} + +namespace L +{ + using namespace J; + int + marker8 () + { + jx; + return K::marker9 (); + } +} + +namespace G +{ + namespace H + { + int ghx = 6; + } +} + +namespace I +{ + int + marker7 () + { + using namespace G::H; + ghx; + return L::marker8 (); + } +} + +namespace E +{ + namespace F + { + int efx = 5; + } +} + +using namespace E::F; +int +marker6 () +{ + efx; + return I::marker7 (); +} + namespace A { int _a = 1; int x = 2; } -int marker4(){ - using A::x; - return 0; +namespace C +{ + int cc = 3; +} + +namespace D +{ + int dx = 4; +} + +using namespace C; +int +marker5 () +{ + cc; + return marker6 (); +} + +int +marker4 () +{ + using D::dx; + return marker5 (); } -int marker3(){ - return marker4(); +int +marker3 () +{ + return marker4 (); } -int marker2() +int +marker2 () { namespace B = A; B::_a; - return marker3(); + return marker3 (); } -int marker1() +int +marker1 () { int total = 0; { @@ -29,17 +132,18 @@ int marker1() using namespace A; int c = 2; { - int d = 3; - total = _a + b + c + d + marker2(); // marker1 stop + int d = 3; + total = _a + b + c + d + marker2 (); // marker1 stop } } } return total; } -int main() +int +main () { using namespace A; _a; - return marker1(); + return marker1 (); } diff --git a/gdb/testsuite/gdb.cp/namespace-using.exp b/gdb/testsuite/gdb.cp/namespace-using.exp index f24973f..c015ef7 100644 --- a/gdb/testsuite/gdb.cp/namespace-using.exp +++ b/gdb/testsuite/gdb.cp/namespace-using.exp @@ -28,6 +28,11 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb return -1 } +if [get_compiler_info ${binfile}] { + return -1; +} + + # Get things started. gdb_exit @@ -46,15 +51,61 @@ if ![runto_main] then { gdb_test "print _a" "= 1" +# Test that names are not printed when they +# are not imported + +gdb_breakpoint marker3 +gdb_continue_to_breakpoint "marker3" + +#send_gdb "break marker3\n" +#send_gdb "continue\n" + +gdb_test "print _a" "No symbol \"_a\" in current context." "Print _a without import" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + ############################################ # test printing of namespace imported into # a scope containing the pc. +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + gdb_breakpoint [gdb_get_line_number "marker1 stop"] gdb_continue_to_breakpoint "marker1 stop" gdb_test "print _a" "= 1" "print _a in a nested scope" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ +# test printing of namespace imported into +# file scope. + + +if ![runto marker5] then { + perror "couldn't run to breakpoint marker5" + continue +} + +gdb_test "print cc" "= 3" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + + ############################################ # Test printing of namespace aliases @@ -64,16 +115,32 @@ if ![runto marker2] then { continue } -gdb_test "print B::a" "= 1" +gdb_test "print B::_a" "= 1" + +gdb_test "print _a" "No symbol \"_a\" in current context." "print _a in namespace alias scope" +gdb_test "print x" "No symbol \"x\" in current context." "print x in namespace alias scope" + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + ############################################ # Test that names are not printed when they # are not imported -gdb_breakpoint "marker3" -gdb_continue_to_breakpoint "marker3" +if {![runto marker3]} { + perror "couldn't run to breakpoint marker3" +} -gdb_test "print _a" "No symbol \"_a\" in current context." "Print a without import" +# gcc-4-3 puts import statements for aliases in +# the global scope instead of the corresponding +# function scope. These wrong import statements throw +# this test off. This is fixed in gcc-4-4. +if [test_compiler_info gcc-4-3-*] then { setup_xfail *-*-* } + +gdb_test "print _a" "No symbol \"_a\" in current context." "Print _a without import" ############################################ # Test printing of individually imported elements @@ -84,4 +151,57 @@ if ![runto marker4] then { continue } -gdb_test "print x" "= 2" +gdb_test "print dx" "= 4" + +############################################ +# Test printing of namespace aliases + +if ![runto marker5] then { + perror "couldn't run to marker5" + continue +} + +gdb_test "print efx" "= 5" + +############################################ +# Test printing of variables imported from +# nested namespaces + +if ![runto I::marker7] then { + perror "couldn't run to breakpoint I::marker7" + continue +} + +gdb_test "print ghx" "= 6" + +############################################ +# Test that variables are not printed in a namespace +# that is sibling to the namespace containing an import + +if ![runto L::marker8] then { + perror "couldn't run to breakpoint L::marker8" + continue +} + +gdb_test "print jx" "= 44" + +gdb_breakpoint "K::marker9" +gdb_continue_to_breakpoint "K::marker9" + +gdb_test "print jx" "No symbol \"jx\" in current context." + +############################################ +# Test that variables are only printed after the line +# containing the import + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +gdb_breakpoint [gdb_get_line_number "marker10 stop"] +gdb_continue_to_breakpoint "marker10 stop" + +# Assert that M::x is printed and not N::x +gdb_test "print x" "= 911" "print x (from M::x)" + diff --git a/gdb/testsuite/gdb.cp/namespace.exp b/gdb/testsuite/gdb.cp/namespace.exp index 76b1b82..2042db2 100644 --- a/gdb/testsuite/gdb.cp/namespace.exp +++ b/gdb/testsuite/gdb.cp/namespace.exp @@ -24,6 +24,7 @@ # for namespaces. # Note: As of 2000-06-03, they passed under g++ - djb +load_lib "cp-support.exp" if $tracelevel then { strace $tracelevel @@ -259,11 +260,16 @@ gdb_test "ptype E" "type = namespace C::D::E" gdb_test "ptype CClass" "type = (class C::CClass \{\r\n public:|struct C::CClass \{)\r\n int x;\r\n\}" gdb_test "ptype CClass::NestedClass" "type = (class C::CClass::NestedClass \{\r\n public:|struct C::CClass::NestedClass \{)\r\n int y;\r\n\}" gdb_test "ptype NestedClass" "No symbol \"NestedClass\" in current context." -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::CClass" "type = class C::CClass \{\r\n public:\r\n int x;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::CClass::NestedClass" "type = class C::CClass::NestedClass \{\r\n public:\r\n int y;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" +cp_test_ptype_class \ + "ptype ::C::CClass" "" "class" "C::CClass" \ + { + { field public "int x;" } + } +cp_test_ptype_class \ + "ptype ::C::CClass::NestedClass" "" "class" "C::CClass::NestedClass" \ + { + { field public "int y;" } + } gdb_test "ptype ::C::NestedClass" "No symbol \"NestedClass\" in namespace \"C\"." gdb_test "ptype C::CClass" "No symbol \"CClass\" in namespace \"C::C\"." gdb_test "ptype C::CClass::NestedClass" "No type \"CClass\" within class or namespace \"C::C\"." @@ -273,8 +279,11 @@ gdb_test "ptype C::NestedClass" "No symbol \"NestedClass\" in namespace \"C::C\" gdb_test "print cOtherFile" "\\$\[0-9\].* = 316" gdb_test "ptype OtherFileClass" "type = (class C::OtherFileClass \{\r\n public:|struct C::OtherFileClass \{)\r\n int z;\r\n\}" -setup_kfail "gdb/1448" "*-*-*" -gdb_test "ptype ::C::OtherFileClass" "type = class C::OtherFileClass \{\r\n public:\r\n int z;\r\n\}" +cp_test_ptype_class \ + "ptype ::C::OtherFileClass" "" "class" "C::OtherFileClass" \ + { + { field public "int z;" } + } gdb_test "ptype C::OtherFileClass" "No symbol \"OtherFileClass\" in namespace \"C::C\"." # Some anonymous namespace tests. diff --git a/gdb/testsuite/gdb.cp/overload.exp b/gdb/testsuite/gdb.cp/overload.exp index 24025a2..a72932e 100644 --- a/gdb/testsuite/gdb.cp/overload.exp +++ b/gdb/testsuite/gdb.cp/overload.exp @@ -74,12 +74,12 @@ set re_methods "${re_methods}${ws}int overload1arg\\((void|)\\);" set re_methods "${re_methods}${ws}int overload1arg\\(char\\);" set re_methods "${re_methods}${ws}int overload1arg\\(signed char\\);" set re_methods "${re_methods}${ws}int overload1arg\\(unsigned char\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(short\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(unsigned short\\);" +set re_methods "${re_methods}${ws}int overload1arg\\(short( int)?\\);" +set re_methods "${re_methods}${ws}int overload1arg\\((unsigned short|short unsigned)( int)?\\);" set re_methods "${re_methods}${ws}int overload1arg\\(int\\);" set re_methods "${re_methods}${ws}int overload1arg\\(unsigned int\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(long\\);" -set re_methods "${re_methods}${ws}int overload1arg\\(unsigned long\\);" +set re_methods "${re_methods}${ws}int overload1arg\\(long( int)?\\);" +set re_methods "${re_methods}${ws}int overload1arg\\((unsigned long|long unsigned)( int)?\\);" set re_methods "${re_methods}${ws}int overload1arg\\(float\\);" set re_methods "${re_methods}${ws}int overload1arg\\(double\\);" set re_methods "${re_methods}${ws}int overloadfnarg\\((void|)\\);" diff --git a/gdb/testsuite/gdb.cp/ovldbreak.exp b/gdb/testsuite/gdb.cp/ovldbreak.exp index 8a6b795..9997a45 100644 --- a/gdb/testsuite/gdb.cp/ovldbreak.exp +++ b/gdb/testsuite/gdb.cp/ovldbreak.exp @@ -127,10 +127,24 @@ proc set_bp_overloaded {name expectedmenu mychoice bpnumber linenumber} { } # This is the expected menu for overload1arg. -# Note the arg type variations on lines 6 and 13. +# Note the arg type variations for void and integer types. # This accommodates different versions of g++. -set menu_overload1arg "\\\[0\\\] cancel\r\n\\\[1\\\] all\r\n\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n\\\[4\\\] foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r\n\\\[5\\\] foo::overload1arg\\(long\\) at.*$srcfile:118\r\n\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n\\\[8\\\] foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r\n\\\[9\\\] foo::overload1arg\\(short\\) at.*$srcfile:114\r\n\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n> $" +set menu_overload1arg "\\\[0\\\] cancel\r\n" +append menu_overload1arg "\\\[1\\\] all\r\n" +append menu_overload1arg "\\\[2\\\] foo::overload1arg\\(double\\) at.*$srcfile:121\r\n" +append menu_overload1arg "\\\[3\\\] foo::overload1arg\\(float\\) at.*$srcfile:120\r\n" +append menu_overload1arg "\\\[4\\\] foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r\n" +append menu_overload1arg "\\\[5\\\] foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r\n" +append menu_overload1arg "\\\[6\\\] foo::overload1arg\\((unsigned int|unsigned)\\) at.*$srcfile:117\r\n" +append menu_overload1arg "\\\[7\\\] foo::overload1arg\\(int\\) at.*$srcfile:116\r\n" +append menu_overload1arg "\\\[8\\\] foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r\n" +append menu_overload1arg "\\\[9\\\] foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r\n" +append menu_overload1arg "\\\[10\\\] foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r\n" +append menu_overload1arg "\\\[11\\\] foo::overload1arg\\(signed char\\) at.*$srcfile:112\r\n" +append menu_overload1arg "\\\[12\\\] foo::overload1arg\\(char\\) at.*$srcfile:111\r\n" +append menu_overload1arg "\\\[13\\\] foo::overload1arg\\((void|)\\) at.*$srcfile:110\r\n" +append menu_overload1arg "> $" # Set multiple-symbols to "ask", to allow us to test the use # of the multiple-choice menu when breaking on an overloaded method. @@ -157,17 +171,17 @@ set_bp_overloaded "foo::overload1arg" "$menu_overload1arg" 13 13 110 gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\((|void)\\))? at.*$srcfile:49\r \[\t \]+breakpoint already hit 1 time\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ @@ -215,17 +229,17 @@ gdb_expect { gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main at.*$srcfile:49\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in main(\\((|void)\\))? at.*$srcfile:49\r \[\t \]+breakpoint already hit 1 time\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((void|)\\) at.*$srcfile:110" \ @@ -296,12 +310,12 @@ gdb_test "info break" \ "Num Type\[\t \]+Disp Enb Address\[\t \]+What.* \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(double\\) at.*$srcfile:121\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(float\\) at.*$srcfile:120\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned long\\) at.*$srcfile:119\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long\\) at.*$srcfile:118\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned long|long unsigned)( int)?\\) at.*$srcfile:119\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(long( int)?\\) at.*$srcfile:118\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned|unsigned int)\\) at.*$srcfile:117\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(int\\) at.*$srcfile:116\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned short\\) at.*$srcfile:115\r -\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short\\) at.*$srcfile:114\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\((unsigned short|short unsigned)( int)?\\) at.*$srcfile:115\r +\[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(short( int)?\\) at.*$srcfile:114\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(unsigned char\\) at.*$srcfile:113\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(signed char\\) at.*$srcfile:112\r \[0-9\]+\[\t \]+breakpoint keep y\[\t \]+$hex\[\t \]+in foo::overload1arg\\(char\\) at.*$srcfile:111\r diff --git a/gdb/testsuite/gdb.cp/shadowing.cc b/gdb/testsuite/gdb.cp/shadowing.cc new file mode 100644 index 0000000..6d9c2f1 --- /dev/null +++ b/gdb/testsuite/gdb.cp/shadowing.cc @@ -0,0 +1,48 @@ +namespace A +{ + int x = 11; +} + +int x = 22; +int y = 0; + +class B +{ +public: + int x; + + int + func() + { + x = 33; + y+=x; // marker1 + + { + int x = 44; + y+=x; // marker2 + + { + int x = 55; + y+=x; // marker3 + + { + int z = x; //prevent gcc from optimizing away this scope + using namespace A; + y+=x; // marker4 + + using A::x; + y+=x; // marker5 + + return this->x; + } + } + } + } +}; + +int +main() +{ + B theB; + return theB.func(); +} diff --git a/gdb/testsuite/gdb.cp/shadowing.exp b/gdb/testsuite/gdb.cp/shadowing.exp new file mode 100644 index 0000000..6922eed --- /dev/null +++ b/gdb/testsuite/gdb.cp/shadowing.exp @@ -0,0 +1,91 @@ +# 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 $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile shadowing +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +if [get_compiler_info ${binfile}] { + return -1; +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +############################################ +# Test printing of class variable is not shadowed +# by global variable + +gdb_breakpoint [gdb_get_line_number "marker1"] +gdb_continue_to_breakpoint "marker1" + +gdb_test "print x" "= 33" "Print class x shadowing global x" + + +############################################ +# Test printing local variable is not shadowed +# by class variable + +gdb_breakpoint [gdb_get_line_number "marker2"] +gdb_continue_to_breakpoint "marker2" + +gdb_test "print x" "= 44" "Print local x shadowing class x" + +############################################ +# Test inner scope x is printed not outer scope + +gdb_breakpoint [gdb_get_line_number "marker3"] +gdb_continue_to_breakpoint "marker3" + +gdb_test "print x" "= 55" "Print inner scope x" + +############################################ +# Test printing local variable is not shadowed +# by namespace variable + +gdb_breakpoint [gdb_get_line_number "marker4"] +gdb_continue_to_breakpoint "marker4" + +gdb_test "print x" "= 55" "Print local x not namespace x" + +############################################ +# Test imported namespace element is printed + +gdb_breakpoint [gdb_get_line_number "marker5"] +gdb_continue_to_breakpoint "marker5" + +if [test_compiler_info gcc-4-3-*] then { setup_xfail *-*-* } + +gdb_test "print x" "= 11" "Print imported namespace x" diff --git a/gdb/testsuite/gdb.dwarf2/callframecfa.S b/gdb/testsuite/gdb.dwarf2/callframecfa.S new file mode 100644 index 0000000..6d0421a --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/callframecfa.S @@ -0,0 +1,309 @@ +/* + 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 was compiled from a trivial program just to test the + DW_OP_call_frame_cfa operator: + + int func (int arg) { + return arg + 23; + } + + int main(int argc, char *argv[]) { + func (77); + } +*/ + + .file "q.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl func + .type func, @function +func: +.LFB0: + .file 1 "q.c" + .loc 1 2 0 + .cfi_startproc + pushl %ebp + .cfi_def_cfa_offset 8 + movl %esp, %ebp + .cfi_offset 5, -8 + .cfi_def_cfa_register 5 + .loc 1 3 0 + movl 8(%ebp), %eax + addl $23, %eax + .loc 1 4 0 + popl %ebp + .cfi_restore 5 + .cfi_def_cfa 4, 4 + ret + .cfi_endproc +.LFE0: + .size func, .-func +.globl _start + .type _start, @function +_start: +.LFB1: + .loc 1 6 0 + .cfi_startproc + pushl %ebp + .cfi_def_cfa_offset 8 + movl %esp, %ebp + .cfi_offset 5, -8 + .cfi_def_cfa_register 5 + subl $4, %esp + .loc 1 7 0 + movl $77, (%esp) + call func + .loc 1 8 0 + leave + .cfi_restore 5 + .cfi_def_cfa 4, 4 + ret + .cfi_endproc +.LFE1: + .size _start, .-_start +.Letext0: + .section .debug_info + .long 0x9e + .value 0x3 + .long .Ldebug_abbrev0 + .byte 0x4 + .uleb128 0x1 + .long .LASF5 + .byte 0x1 + .string "q.c" + .long .LASF6 + .long .Ltext0 + .long .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .long .LASF0 + .byte 0x1 + .byte 0x1 + .byte 0x1 + .long 0x4f + .long .LFB0 + .long .LFE0 + .byte 0x1 + .byte 0x9c + .long 0x4f + .uleb128 0x3 + .string "arg" + .byte 0x1 + .byte 0x1 + .long 0x4f + .byte 0x2 + .byte 0x91 + .sleb128 0 + .byte 0x0 + .uleb128 0x4 + .byte 0x4 + .byte 0x5 + .string "int" + .uleb128 0x2 + .byte 0x1 + .long .LASF1 + .byte 0x1 + .byte 0x6 + .byte 0x1 + .long 0x4f + .long .LFB1 + .long .LFE1 + .byte 0x1 + .byte 0x9c + .long 0x8e + .uleb128 0x5 + .long .LASF2 + .byte 0x1 + .byte 0x6 + .long 0x4f + .byte 0x2 + .byte 0x91 + .sleb128 0 + .uleb128 0x5 + .long .LASF3 + .byte 0x1 + .byte 0x6 + .long 0x8e + .byte 0x2 + .byte 0x91 + .sleb128 4 + .byte 0x0 + .uleb128 0x6 + .byte 0x4 + .long 0x94 + .uleb128 0x6 + .byte 0x4 + .long 0x9a + .uleb128 0x7 + .byte 0x1 + .byte 0x6 + .long .LASF4 + .byte 0x0 + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .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 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0xa + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .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 0x4 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .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 0x6 + .uleb128 0xf + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .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 0x20 + .value 0x2 + .long .Ldebug_info0 + .long 0xa2 + .long 0x25 + .string "func" + .long 0x56 + .string "main" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x1c + .value 0x2 + .long .Ldebug_info0 + .byte 0x4 + .byte 0x0 + .value 0x0 + .value 0x0 + .long .Ltext0 + .long .Letext0-.Ltext0 + .long 0x0 + .long 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF5: + .string "GNU C 4.5.0 20090810 (experimental) [trunk revision 150633]" +.LASF2: + .string "argc" +.LASF6: + .string "/tmp" +.LASF0: + .string "func" +.LASF3: + .string "argv" +.LASF1: + .string "main" +.LASF4: + .string "char" + .ident "GCC: (GNU) 4.5.0 20090810 (experimental) [trunk revision 150633]" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.dwarf2/callframecfa.exp b/gdb/testsuite/gdb.dwarf2/callframecfa.exp new file mode 100644 index 0000000..00d67fc --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/callframecfa.exp @@ -0,0 +1,55 @@ +# 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_OP_call_frame_cfa. + +# 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 +} +# This test can only be run on x86 targets. +if {![istarget i?86-*]} { + return 0 +} + +set testfile "callframecfa" +set srcfile ${testfile}.S +set binfile ${objdir}/${subdir}/${testfile}.x + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ + [list {additional_flags=-nostdlib}]] != "" } { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +gdb_test "break *func" "Breakpoint 1.*" "set breakpoint for call-frame-cfa" +gdb_test "run" "" "run for call-frame-cfa" +gdb_test "display arg" "arg = 77" "set display for call-frame-cfa" + +# We know how many instructions are in the function. Note that we +# can't handle the "ret" instruction due to the epilogue unwinder. +for {set i 1} {$i < 5} {incr i} { + gdb_test "si" "arg = 77" "step $i for call-frame-cfa" +} 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/common-block.exp b/gdb/testsuite/gdb.fortran/common-block.exp new file mode 100644 index 0000000..888f6c3 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/common-block.exp @@ -0,0 +1,101 @@ +# 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 . + +set testfile "common-block" +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 "stop-here-out"] +gdb_continue_to_breakpoint "stop-here-out" + +# Common block naming with source name /foo/: +# .symtab DW_TAG_common_block's DW_AT_name +# Intel Fortran foo_ foo_ +# GNU Fortran foo_ foo +#set suffix "_" +set suffix "" + +set int4 {(integer\(kind=4\)|INTEGER\(4\))} +set real4 {(real\(kind=4\)|REAL\(4\))} +set real8 {(real\(kind=8\)|REAL\(8\))} + +gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." +gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." +gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." +gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." + +gdb_test "info locals" "ix_x = 11\r\niy_y = 22\r\niz_z = 33\r\nix = 1\r\niy = 2\r\niz = 3" "info locals out" +gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix_x = 11\r\niy_y = 22\r\niz_z = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix = 1\r\niy = 2\r\niz = 3" "info common out" + +gdb_test "ptype ix" "type = $int4" "ptype ix out" +gdb_test "ptype iy" "type = $real4" "ptype iy out" +gdb_test "ptype iz" "type = $real8" "ptype iz out" +gdb_test "ptype ix_x" "type = $int4" "ptype ix_x out" +gdb_test "ptype iy_y" "type = $real4" "ptype iy_y out" +gdb_test "ptype iz_z" "type = $real8" "ptype iz_z out" + +gdb_test "p ix" " = 1 *" "p ix out" +gdb_test "p iy" " = 2 *" "p iy out" +gdb_test "p iz" " = 3 *" "p iz out" +gdb_test "p ix_x" " = 11 *" "p ix_x out" +gdb_test "p iy_y" " = 22 *" "p iy_y out" +gdb_test "p iz_z" " = 33 *" "p iz_z out" + +gdb_breakpoint [gdb_get_line_number "stop-here-in"] +gdb_continue_to_breakpoint "stop-here-in" + +gdb_test "whatis foo$suffix" "No symbol \"foo$suffix\" in current context." "whatis foo$suffix in" +gdb_test "ptype foo$suffix" "No symbol \"foo$suffix\" in current context." "ptype foo$suffix in" +gdb_test "p foo$suffix" "No symbol \"foo$suffix\" in current context." "p foo$suffix in" +gdb_test "whatis fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "whatis fo_o$suffix in" +gdb_test "ptype fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "ptype fo_o$suffix in" +gdb_test "p fo_o$suffix" "No symbol \"fo_o$suffix\" in current context." "p fo_o$suffix in" + +gdb_test "info locals" "ix = 11\r\niy2 = 22\r\niz = 33\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3\r\niy = 5\r\niz_z = 55" "info locals in" +gdb_test "info common" "Contents of F77 COMMON block 'fo_o':\r\nix = 11\r\niy2 = 22\r\niz = 33\r\n\r\nContents of F77 COMMON block 'foo':\r\nix_x = 1\r\niy_y = 2\r\niz_z2 = 3" "info common in" + +gdb_test "ptype ix" "type = $int4" "ptype ix in" +gdb_test "ptype iy2" "type = $real4" "ptype iy2 in" +gdb_test "ptype iz" "type = $real8" "ptype iz in" +gdb_test "ptype ix_x" "type = $int4" "ptype ix_x in" +gdb_test "ptype iy_y" "type = $real4" "ptype iy_y in" +gdb_test "ptype iz_z2" "type = $real8" "ptype iz_z2 in" + +gdb_test "p ix" " = 11 *" "p ix in" +gdb_test "p iy2" " = 22 *" "p iy2 in" +gdb_test "p iz" " = 33 *" "p iz in" +gdb_test "p ix_x" " = 1 *" "p ix_x in" +gdb_test "p iy_y" " = 2 *" "p iy_y in" +gdb_test "p iz_z2" " = 3 *" "p iz_z2 in" diff --git a/gdb/testsuite/gdb.fortran/common-block.f90 b/gdb/testsuite/gdb.fortran/common-block.f90 new file mode 100644 index 0000000..b614e8a --- /dev/null +++ b/gdb/testsuite/gdb.fortran/common-block.f90 @@ -0,0 +1,67 @@ +! 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 in + + INTEGER*4 ix + REAL*4 iy2 + REAL*8 iz + + INTEGER*4 ix_x + REAL*4 iy_y + REAL*8 iz_z2 + + common /fo_o/ix,iy2,iz + common /foo/ix_x,iy_y,iz_z2 + + iy = 5 + iz_z = 55 + + if (ix .ne. 11 .or. iy2 .ne. 22.0 .or. iz .ne. 33.0) call abort + if (ix_x .ne. 1 .or. iy_y .ne. 2.0 .or. iz_z2 .ne. 3.0) call abort + + ix = 0 ! stop-here-in + +end subroutine in + +program common_test + + INTEGER*4 ix + REAL*4 iy + REAL*8 iz + + INTEGER*4 ix_x + REAL*4 iy_y + REAL*8 iz_z + + common /foo/ix,iy,iz + common /fo_o/ix_x,iy_y,iz_z + + ix = 1 + iy = 2.0 + iz = 3.0 + + ix_x = 11 + iy_y = 22.0 + iz_z = 33.0 + + call in ! stop-here-out + +end program common_test 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/logical.exp b/gdb/testsuite/gdb.fortran/logical.exp new file mode 100644 index 0000000..ef76f43 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/logical.exp @@ -0,0 +1,44 @@ +# 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 . + +set testfile "logical" +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 "stop-here"] +gdb_continue_to_breakpoint "stop-here" +gdb_test "p l" " = \\.TRUE\\." +gdb_test "p l1" " = \\.TRUE\\." +gdb_test "p l2" " = \\.TRUE\\." +gdb_test "p l4" " = \\.TRUE\\." +gdb_test "p l8" " = \\.TRUE\\." diff --git a/gdb/testsuite/gdb.fortran/logical.f90 b/gdb/testsuite/gdb.fortran/logical.f90 new file mode 100644 index 0000000..4229304 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/logical.f90 @@ -0,0 +1,33 @@ +! 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 . + +program test + logical :: l + logical (kind=1) :: l1 + logical (kind=2) :: l2 + logical (kind=4) :: l4 + logical (kind=8) :: l8 + l = .TRUE. + l1 = .TRUE. + l2 = .TRUE. + l4 = .TRUE. + l8 = .TRUE. + l = .FALSE. ! stop-here +end diff --git a/gdb/testsuite/gdb.fortran/module.exp b/gdb/testsuite/gdb.fortran/module.exp index 342ccee..c836c3c 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 501ccc8..118931d 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 495ae45..d08d7a4 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.mi/gdb701.exp b/gdb/testsuite/gdb.mi/gdb701.exp index d4acdc2..244c731 100644 --- a/gdb/testsuite/gdb.mi/gdb701.exp +++ b/gdb/testsuite/gdb.mi/gdb701.exp @@ -54,7 +54,7 @@ mi_gdb_test "-var-list-children fooPtr" \ foreach i [list x y z] { mi_gdb_test "-var-list-children fooPtr.$i" \ - "(&\".*\"\r\n)*\\^done,numchild=\"0\"" \ + "(&\".*\"\r\n)*\\^done,numchild=\"0\",has_more=\"0\"" \ "list children of fooPtr.$i" } diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp index 619727d..8d06c0e 100644 --- a/gdb/testsuite/gdb.mi/mi-break.exp +++ b/gdb/testsuite/gdb.mi/mi-break.exp @@ -175,7 +175,7 @@ proc test_error {} { # containing function call, the internal breakpoint created to handle # function call would be reported, messing up MI output. mi_gdb_test "-var-create V * return_1()" \ - "\\^done,name=\"V\",numchild=\"0\",value=\"1\",type=\"int\"" \ + "\\^done,name=\"V\",numchild=\"0\",value=\"1\",type=\"int\",has_more=\"0\"" \ "create varobj for function call" mi_gdb_test "-var-update *" \ diff --git a/gdb/testsuite/gdb.mi/mi-var-block.exp b/gdb/testsuite/gdb.mi/mi-var-block.exp index 8806848..93ded26 100644 --- a/gdb/testsuite/gdb.mi/mi-var-block.exp +++ b/gdb/testsuite/gdb.mi/mi-var-block.exp @@ -74,7 +74,7 @@ mi_step_to "do_block_tests" "" "var-cmd.c" \ # Test: c_variable-3.4 # Desc: check foo, cb changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"foo\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"cb\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"foo\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"cb\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: cb foo changed" # step to "foo = 321;" diff --git a/gdb/testsuite/gdb.mi/mi-var-child.exp b/gdb/testsuite/gdb.mi/mi-var-child.exp index 1f4bdc6..eb6c456 100644 --- a/gdb/testsuite/gdb.mi/mi-var-child.exp +++ b/gdb/testsuite/gdb.mi/mi-var-child.exp @@ -680,7 +680,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.2 # Desc: check that integer changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.integer\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.integer" # Step over: @@ -693,7 +693,7 @@ mi_execute_to "exec-step 3" "end-stepping-range" do_children_tests {} ".*${srcfi # Test: c_variable-5.3 # Desc: check that char_ptr changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.char_ptr" # Step over "struct_declarations.int_ptr_ptr = &foo;" @@ -703,7 +703,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.4 # Desc: check that int_ptr_ptr and children changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr.\\*\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr.\\*\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr.\\*\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr.\\*\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars int_ptr_ptr and children changed" # Step over "weird->long_array[0] = 1234;" @@ -713,7 +713,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.5 # Desc: check that long_array[0] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.0\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.0\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.0 changed" # Step over "struct_declarations.long_array[1] = 2345;" @@ -723,7 +723,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.6 # Desc: check that long_array[1] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.1\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.1\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.1 changed" # Step over "weird->long_array[2] = 3456;" @@ -733,7 +733,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.7 # Desc: check that long_array[2] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.2\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.2\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.2 changed" # Step over: @@ -752,7 +752,7 @@ mi_execute_to "exec-step 7" "end-stepping-range" do_children_tests {} ".*${srcfi # Test: c_variable-5.8 # Desc: check that long_array[3-9] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.3\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.4\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.5\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.6\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.7\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.8\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.9\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.3\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.4\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.5\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.6\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.7\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.8\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.9\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.3-9 changed" @@ -763,7 +763,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.9 # Desc: check that func_ptr changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.func_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.func_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.func_ptr changed" # Step over "struct_declarations.long_array[10] = 3456"; @@ -771,7 +771,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ [expr $line_dct_nothing + 2] "step \$line_dct_nothing + 2" mi_gdb_test "-var-update --no-values *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.10\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.10\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.10 changed, don't print values." # Step over "struct_declarations.long_array[11] = 5678"; @@ -780,7 +780,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ $line_dct_a0_0 "step \$line_dct_a0_0" mi_gdb_test "-var-update --all-values *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.11\",value=\"5678\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.11\",value=\"5678\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.11 changed, print values." mi_list_varobj_children {struct_declarations.long_array --all-values} { @@ -1121,7 +1121,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.47 # Desc: check that psnp->char_ptr (and [0].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr.\\*\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr.\\*\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->char_ptr (and 0.char_ptr) changed" # Step over "snp1.char_ptr = &c3;" @@ -1131,7 +1131,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.48 # Desc: check that psnp->next->char_ptr (and [1].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr.\\*\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr.\\*\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->char_ptr (and 1.char_ptr) changed" @@ -1142,7 +1142,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.49 # Desc: check that psnp->next->next->char_ptr (and [2].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->next->char_ptr (and 2.char_ptr) changed" @@ -1153,7 +1153,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.50 # Desc: check that psnp->long_ptr (and [0].long_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr.\\*\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr.\\*\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->long_ptr (and 0.long_ptr) changed" @@ -1181,7 +1181,7 @@ mi_step_to do_children_tests {} ".*${srcfile}" \ # Test: c_variable-5.52 # Desc: check that psnp->next->next->long_ptr (and [2].long_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.long_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->next->long_ptr (and 2.long_ptr) changed" mi_prepare_inline_tests $srcfile diff --git a/gdb/testsuite/gdb.mi/mi-var-cmd.exp b/gdb/testsuite/gdb.mi/mi-var-cmd.exp index ad2e55c..6efb333 100644 --- a/gdb/testsuite/gdb.mi/mi-var-cmd.exp +++ b/gdb/testsuite/gdb.mi/mi-var-cmd.exp @@ -146,7 +146,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" $line_dlt_linteger "step at do_local # Test: c_variable-2.2 # Desc: check whether only linteger changed values mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: linteger changed" # Step over "lpinteger = &linteger;" @@ -155,7 +155,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 1] "step # Test: c_variable-2.3 # Desc: check whether only lpinteger changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpinteger changed" # Step over "lcharacter = 'a';" @@ -164,7 +164,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 2] "step # Test: c_variable-2.4 # Desc: check whether only lcharacter changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lcharacter changed" # Step over "lpcharacter = &lcharacter;" @@ -173,7 +173,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 3] "step # Test: c_variable-2.5 # Desc: check whether only lpcharacter changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpcharacter changed" @@ -195,7 +195,7 @@ mi_execute_to "exec-step 9" "end-stepping-range" "do_locals_tests" "" \ # Desc: check whether llong, lplong, lfloat, lpfloat, ldouble, lpdouble, lsimple.integer, # lsimple.unsigned_character lsimple.integer lsimple.character changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpdouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lplong\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpdouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lplong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: many changed" # Step over: @@ -212,7 +212,7 @@ mi_execute_to "exec-step 4" "end-stepping-range" "do_locals_tests" "" \ # Test: c_variable-2.7 # Desc: check whether (lsimple.signed_character, lsimple.char_ptr) lpsimple, func changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"func\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpsimple\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"func\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpsimple\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: func and lpsimple changed" # Step over @@ -234,7 +234,7 @@ mi_execute_to "exec-step 8" "end-stepping-range" "do_locals_tests" "" \ # Note: this test also checks that lpsimple->integer and lsimple.integer have # changed (they are the same) mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lsimple and others changed" @@ -257,7 +257,7 @@ mi_gdb_test "-var-assign linteger 3333" \ # change. set lpchar_update "\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\}," mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[($lpchar_update)?\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[($lpchar_update)?\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: linteger changed after assign" mi_gdb_test "-var-assign linteger 3333" \ @@ -277,7 +277,7 @@ mi_gdb_test "-var-assign lpinteger \"&linteger + 3\"" \ "assign to lpinteger" mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpinteger changed after assign" mi_gdb_test "-var-update *" \ @@ -377,7 +377,7 @@ mi_gdb_test "-var-update *" \ "assign same value to func (update)" mi_gdb_test "-var-create array_ptr * array_ptr" \ - "\\^done,name=\"array_ptr\",numchild=\"1\",value=\"$hex\",type=\"int \\*\"" \ + "\\^done,name=\"array_ptr\",numchild=\"1\",value=\"$hex\",type=\"int \\*\",has_more=\"0\"" \ "create global variable array_ptr" mi_gdb_test "-var-assign array_ptr array2" \ @@ -385,7 +385,7 @@ mi_gdb_test "-var-assign array_ptr array2" \ "assign array to pointer" mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"array_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"array_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "assign array to pointer (update)" mi_gdb_test "-var-assign array_ptr array2" \ @@ -439,7 +439,7 @@ mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\ # Test: c_variable-2.13 # Desc: change subroutine1 local i mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"i\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"i\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: i changed" mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\}" \ @@ -448,7 +448,7 @@ mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\ # Test: c_variable-2.14 # Desc: change do_locals_tests local llong mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: llong changed" set line_dlt_call_subroutine1 [gdb_get_line_number "subroutine1 (linteger, &llong);"] @@ -458,7 +458,7 @@ mi_next_to "do_locals_tests" "" "var-cmd.c" \ # Test: c_variable-2.15 # Desc: check for out of scope subroutine1 locals mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"l\",in_scope=\"false\"\,type_changed=\"false\"},\{name=\"i\",in_scope=\"false\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"l\",in_scope=\"false\"\,type_changed=\"false\",has_more=\"0\"},\{name=\"i\",in_scope=\"false\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: all now out of scope" # Done with locals/globals tests. Erase all variables @@ -550,14 +550,14 @@ mi_gdb_test "-var-create selected_a @ a" \ mi_continue_to incr_a mi_gdb_test "-var-update selected_a" \ - "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"char\",new_num_children=\"0\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"char\",new_num_children=\"0\",has_more=\"0\"\}\\\]" \ "update selected_a in incr_a" mi_next "step a line in incr_a" mi_next "return from incr_a to do_special_tests" mi_gdb_test "-var-update selected_a" \ - "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"int\",new_num_children=\"0\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"int\",new_num_children=\"0\",has_more=\"0\"\}\\\]" \ "update selected_a in do_special_tests" mi_gdb_test "-file-exec-and-symbols ${binfile}" "\\^done" \ @@ -596,7 +596,7 @@ mi_check_varobj_value F 7 "check F inside callee" # A varobj we fail to read during -var-update should be considered # out of scope. mi_gdb_test "-var-create null_ptr * **0" \ - {\^done,name="null_ptr",numchild="0",value=".*",type="int"} \ + {\^done,name="null_ptr",numchild="0",value=".*",type="int",has_more="0"} \ "create null_ptr" # Allow this to succeed, if address zero is readable, although it @@ -644,7 +644,7 @@ mi_check_varobj_value "L" "{...}" "in-and-out-of-scope: check initial value" mi_runto main mi_gdb_test "-var-update L" \ - {\^done,changelist=\[{name="L",in_scope="false",type_changed="false"}\]} \ + {\^done,changelist=\[{name="L",in_scope="false",type_changed="false",has_more="0"}\]} \ "in-and-out-of-scope: out of scope now" mi_gdb_test "-var-update L" \ @@ -654,7 +654,7 @@ mi_gdb_test "-var-update L" \ mi_continue_to do_locals_tests mi_gdb_test "-var-update L" \ - {\^done,changelist=\[{name="L",in_scope="true",type_changed="false"}\]} \ + {\^done,changelist=\[{name="L",in_scope="true",type_changed="false",has_more="0"}\]} \ "in-and-out-of-scope: in scope now" mi_gdb_test "-var-update L" \ diff --git a/gdb/testsuite/gdb.mi/mi-var-display.exp b/gdb/testsuite/gdb.mi/mi-var-display.exp index 4b02e50..faa9172 100644 --- a/gdb/testsuite/gdb.mi/mi-var-display.exp +++ b/gdb/testsuite/gdb.mi/mi-var-display.exp @@ -558,7 +558,7 @@ mi_gdb_test "-var-info-num-children e" \ # Test: c_variable-7.55 # Desc: children of e mi_gdb_test "-var-list-children e" \ - "\\^done,numchild=\"0\"" \ + "\\^done,numchild=\"0\",has_more=\"0\"" \ "get children of e" # Test: c_variable-7.60 @@ -600,7 +600,7 @@ mi_gdb_test "-var-info-num-children anone" \ # Test: c_variable-7.75 # Desc: children of anone mi_gdb_test "-var-list-children anone" \ - "\\^done,numchild=\"0\"" \ + "\\^done,numchild=\"0\",has_more=\"0\"" \ "get children of anone" diff --git a/gdb/testsuite/gdb.mi/mi-var-invalidate.exp b/gdb/testsuite/gdb.mi/mi-var-invalidate.exp index 05d46fa..4b95674 100644 --- a/gdb/testsuite/gdb.mi/mi-var-invalidate.exp +++ b/gdb/testsuite/gdb.mi/mi-var-invalidate.exp @@ -72,7 +72,7 @@ mi_runto main # Check local variable is "invalid". mi_gdb_test "-var-update linteger" \ - "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"invalid\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"invalid\",has_more=\"0\"\}\\\]" \ "linteger not anymore in scope due to binary changes" mi_gdb_test "-var-info-type linteger" \ @@ -97,7 +97,7 @@ mi_delete_breakpoints mi_gdb_load ${binfile2} # Check local variable are "invalid" mi_gdb_test "-var-update linteger" \ - "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"invalid\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"invalid\",has_more=\"0\"\}\\\]" \ "linteger not valid anymore due to binary changes" mi_gdb_test "-var-info-type linteger" \ @@ -106,7 +106,7 @@ mi_gdb_test "-var-info-type linteger" \ # Check global variable are still correct. mi_gdb_test "-var-update global_simple" \ - "\\^done,changelist=\\\[\{name=\"global_simple\",in_scope=\"invalid\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"global_simple\",in_scope=\"invalid\",has_more=\"0\"\}\\\]" \ "global_simple not anymore in scope due to binary changes" mi_gdb_test "-var-info-type global_simple" \ diff --git a/gdb/testsuite/gdb.mi/mi2-var-block.exp b/gdb/testsuite/gdb.mi/mi2-var-block.exp index 6bcfea3..9b3d08f 100644 --- a/gdb/testsuite/gdb.mi/mi2-var-block.exp +++ b/gdb/testsuite/gdb.mi/mi2-var-block.exp @@ -74,7 +74,7 @@ mi_step_to "do_block_tests" "" "var-cmd.c" \ # Test: c_variable-3.4 # Desc: check foo, cb changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"foo\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"cb\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"foo\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"cb\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: cb foo changed" # step to "foo = 321;" diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp index 161b34f..0f9b4d4 100644 --- a/gdb/testsuite/gdb.mi/mi2-var-child.exp +++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp @@ -1,4 +1,4 @@ -# Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation +# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2009 Free Software Foundation # 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 @@ -680,7 +680,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.2 # Desc: check that integer changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.integer\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.integer" # Step over: @@ -693,7 +693,7 @@ mi_execute_to "exec-step 3" "end-stepping-range" do_children_tests {} {.*var-cmd # Test: c_variable-5.3 # Desc: check that char_ptr changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.char_ptr" # Step over "struct_declarations.int_ptr_ptr = &foo;" @@ -703,7 +703,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.4 # Desc: check that int_ptr_ptr and children changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr.\\*\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr.\\*\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"weird->int_ptr_ptr.\\*weird->int_ptr_ptr.\\*\\*weird->int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.int_ptr_ptr.\\*int_ptr_ptr.\\*\\*int_ptr_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars int_ptr_ptr and children changed" # Step over "weird->long_array[0] = 1234;" @@ -713,7 +713,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.5 # Desc: check that long_array[0] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.0\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.0\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.0 changed" # Step over "struct_declarations.long_array[1] = 2345;" @@ -723,7 +723,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.6 # Desc: check that long_array[1] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.1\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.1\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.1 changed" # Step over "weird->long_array[2] = 3456;" @@ -733,7 +733,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.7 # Desc: check that long_array[2] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.2\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.2\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.2 changed" # Step over: @@ -752,7 +752,7 @@ mi_execute_to "exec-step 7" "end-stepping-range" do_children_tests {} {.*var-cmd # Test: c_variable-5.8 # Desc: check that long_array[3-9] changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.3\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.4\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.5\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.6\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.7\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.8\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"struct_declarations.long_array.9\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.long_array.3\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.4\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.5\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.6\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.7\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.8\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"struct_declarations.long_array.9\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.long_array.3-9 changed" @@ -764,7 +764,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.9 # Desc: check that func_ptr changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"struct_declarations.func_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"struct_declarations.func_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars struct_declarations.func_ptr changed" # Delete all variables @@ -1075,7 +1075,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.47 # Desc: check that psnp->char_ptr (and [0].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr.\\*\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->char_ptr.\\*psnp->char_ptr.\\*\\*psnp->char_ptr.\\*\\*\\*psnp->char_ptr.\\*\\*\\*\\*psnp->char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->char_ptr (and 0.char_ptr) changed" # Step over "snp1.char_ptr = &c3;" @@ -1085,7 +1085,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.48 # Desc: check that psnp->next->char_ptr (and [1].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr.\\*\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->ptrs.0.next.char_ptr.\\*char_ptr.\\*\\*char_ptr.\\*\\*\\*char_ptr.\\*\\*\\*\\*char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->char_ptr (and 1.char_ptr) changed" @@ -1096,7 +1096,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.49 # Desc: check that psnp->next->next->char_ptr (and [2].char_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.char_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.char_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->next->char_ptr (and 2.char_ptr) changed" @@ -1107,7 +1107,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.50 # Desc: check that psnp->long_ptr (and [0].long_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr.\\*\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"psnp->long_ptr.\\*psnp->long_ptr.\\*\\*psnp->long_ptr.\\*\\*\\*psnp->long_ptr.\\*\\*\\*\\*psnp->long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->long_ptr (and 0.long_ptr) changed" @@ -1120,7 +1120,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Why does this have a FIXME? setup_xfail *-*-* mi_gdb_test "-var-update *" \ - "FIXME\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.long_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "FIXME\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->long_ptr (and 1.long_ptr) changed" clear_xfail *-*-* @@ -1135,7 +1135,7 @@ mi_step_to do_children_tests {} {.*var-cmd.c} \ # Test: c_variable-5.52 # Desc: check that psnp->next->next->long_ptr (and [2].long_ptr) changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.long_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"psnp->ptrs.0.next.next.long_ptr\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars psnp->next->next->long_ptr (and 2.long_ptr) changed" diff --git a/gdb/testsuite/gdb.mi/mi2-var-cmd.exp b/gdb/testsuite/gdb.mi/mi2-var-cmd.exp index 96d42a1..e900d14 100644 --- a/gdb/testsuite/gdb.mi/mi2-var-cmd.exp +++ b/gdb/testsuite/gdb.mi/mi2-var-cmd.exp @@ -146,7 +146,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" $line_dlt_linteger "step at do_local # Test: c_variable-2.2 # Desc: check whether only linteger changed values mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: linteger changed" # Step over "lpinteger = &linteger;" @@ -155,7 +155,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 1] "step # Test: c_variable-2.3 # Desc: check whether only lpinteger changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpinteger changed" # Step over "lcharacter = 'a';" @@ -164,7 +164,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 2] "step # Test: c_variable-2.4 # Desc: check whether only lcharacter changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lcharacter changed" # Step over "lpcharacter = &lcharacter;" @@ -173,7 +173,7 @@ mi_step_to "do_locals_tests" "" "var-cmd.c" [expr $line_dlt_linteger + 3] "step # Test: c_variable-2.5 # Desc: check whether only lpcharacter changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpcharacter changed" @@ -195,7 +195,7 @@ mi_execute_to "exec-step 9" "end-stepping-range" "do_locals_tests" "" \ # Desc: check whether llong, lplong, lfloat, lpfloat, ldouble, lpdouble, lsimple.integer, # lsimple.unsigned_character lsimple.integer lsimple.character changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpdouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lplong\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpdouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lplong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: many changed" # Step over: @@ -212,7 +212,7 @@ mi_execute_to "exec-step 4" "end-stepping-range" "do_locals_tests" "" \ # Test: c_variable-2.7 # Desc: check whether (lsimple.signed_character, lsimple.char_ptr) lpsimple, func changed mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"func\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpsimple\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"func\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpsimple\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: func and lpsimple changed" # Step over @@ -234,7 +234,7 @@ mi_execute_to "exec-step 8" "end-stepping-range" "do_locals_tests" "" \ # Note: this test also checks that lpsimple->integer and lsimple.integer have # changed (they are the same) mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\"\},\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lsimple.integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple->integer\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lsimple.character\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"ldouble\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lfloat\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"lcharacter\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\},\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lsimple and others changed" @@ -257,7 +257,7 @@ mi_gdb_test "-var-assign linteger 3333" \ # change. set lpchar_update "\{name=\"lpcharacter\",in_scope=\"true\",type_changed=\"false\"\}," mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[($lpchar_update)?\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[($lpchar_update)?\{name=\"linteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: linteger changed after assign" mi_gdb_test "-var-assign linteger 3333" \ @@ -277,7 +277,7 @@ mi_gdb_test "-var-assign lpinteger \"&linteger + 3\"" \ "assign to lpinteger" mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"lpinteger\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: lpinteger changed after assign" mi_gdb_test "-var-update *" \ @@ -402,7 +402,7 @@ mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\ # Test: c_variable-2.13 # Desc: change subroutine1 local i mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"i\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"i\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: i changed" mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\}" \ @@ -411,7 +411,7 @@ mi_step_to "subroutine1" "\{name=\"i\",value=\".*\"\},\{name=\"l\",value=\".*\"\ # Test: c_variable-2.14 # Desc: change do_locals_tests local llong mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"llong\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"llong\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: llong changed" set line_dlt_call_subroutine1 [gdb_get_line_number "subroutine1 (linteger, &llong);"] @@ -421,7 +421,7 @@ mi_next_to "do_locals_tests" "" "var-cmd.c" \ # Test: c_variable-2.15 # Desc: check for out of scope subroutine1 locals mi_gdb_test "-var-update *" \ - "\\^done,changelist=\\\[\{name=\"l\",in_scope=\"false\"\,type_changed=\"false\"},\{name=\"i\",in_scope=\"false\",type_changed=\"false\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"l\",in_scope=\"false\"\,type_changed=\"false\",has_more=\"0\"},\{name=\"i\",in_scope=\"false\",type_changed=\"false\",has_more=\"0\"\}\\\]" \ "update all vars: all now out of scope" # Done with locals/globals tests. Erase all variables @@ -513,14 +513,14 @@ mi_gdb_test "-var-create selected_a @ a" \ mi_continue_to incr_a mi_gdb_test "-var-update selected_a" \ - "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"char\",new_num_children=\"0\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"char\",new_num_children=\"0\"\,has_more=\"0\"}\\\]" \ "update selected_a in incr_a" mi_next "step a line in incr_a" mi_next "return from incr_a to do_special_tests" mi_gdb_test "-var-update selected_a" \ - "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"int\",new_num_children=\"0\"\}\\\]" \ + "\\^done,changelist=\\\[\{name=\"selected_a\",in_scope=\"true\",type_changed=\"true\",new_type=\"int\",new_num_children=\"0\",has_more=\"0\"\}\\\]" \ "update selected_a in do_special_tests" mi_gdb_test "-file-exec-and-symbols ${binfile}" "\\^done" \ diff --git a/gdb/testsuite/gdb.mi/mi2-var-display.exp b/gdb/testsuite/gdb.mi/mi2-var-display.exp index d6ce673..17e208a 100644 --- a/gdb/testsuite/gdb.mi/mi2-var-display.exp +++ b/gdb/testsuite/gdb.mi/mi2-var-display.exp @@ -557,7 +557,7 @@ mi_gdb_test "-var-info-num-children e" \ # Test: c_variable-7.55 # Desc: children of e mi_gdb_test "-var-list-children e" \ - "\\^done,numchild=\"0\"" \ + "\\^done,numchild=\"0\",has_more=\"0\"" \ "get children of e" # Test: c_variable-7.60 @@ -599,7 +599,7 @@ mi_gdb_test "-var-info-num-children anone" \ # Test: c_variable-7.75 # Desc: children of anone mi_gdb_test "-var-list-children anone" \ - "\\^done,numchild=\"0\"" \ + "\\^done,numchild=\"0\",has_more=\"0\"" \ "get children of anone" 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/Makefile.in b/gdb/testsuite/gdb.python/Makefile.in index 79be9e7..c49f713 100644 --- a/gdb/testsuite/gdb.python/Makefile.in +++ b/gdb/testsuite/gdb.python/Makefile.in @@ -1,7 +1,7 @@ VPATH = @srcdir@ srcdir = @srcdir@ -EXECUTABLES = python-value +EXECUTABLES = python-value python-prettyprint python-template all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.python/python-cmd.exp b/gdb/testsuite/gdb.python/python-cmd.exp index f6ef938..1032a2d 100644 --- a/gdb/testsuite/gdb.python/python-cmd.exp +++ b/gdb/testsuite/gdb.python/python-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/python-frame.exp b/gdb/testsuite/gdb.python/python-frame.exp index 82b526e..82ae814 100644 --- a/gdb/testsuite/gdb.python/python-frame.exp +++ b/gdb/testsuite/gdb.python/python-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 "python-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/python-function.exp b/gdb/testsuite/gdb.python/python-function.exp index 7feca2b..4ae519f 100644 --- a/gdb/testsuite/gdb.python/python-function.exp +++ b/gdb/testsuite/gdb.python/python-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/python-inferior.c b/gdb/testsuite/gdb.python/python-inferior.c new file mode 100644 index 0000000..0b48299 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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/python-inferior.exp b/gdb/testsuite/gdb.python/python-inferior.exp new file mode 100644 index 0000000..ea413c6 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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 "python-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/python-infthread.c b/gdb/testsuite/gdb.python/python-infthread.c new file mode 100644 index 0000000..22eb9f2 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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/python-infthread.exp b/gdb/testsuite/gdb.python/python-infthread.exp new file mode 100644 index 0000000..d444554 --- /dev/null +++ b/gdb/testsuite/gdb.python/python-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 "python-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/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp index 3258810..7791775 100644 --- a/gdb/testsuite/gdb.python/python-mi.exp +++ b/gdb/testsuite/gdb.python/python-mi.exp @@ -48,23 +48,53 @@ mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" "" mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \ "step to breakpoint" -mi_create_floating_varobj container c "create container varobj" +mi_create_dynamic_varobj container c \ + "create container varobj, no pretty-printing" + +mi_list_varobj_children container { + { container.name name 1 string } + { container.len len 0 int } + { container.elements elements 1 "int ." } +} "examine container children=0, no pretty-printing" + +mi_delete_varobj container "delete varobj" + +mi_gdb_test "-enable-pretty-printing" "" + +mi_create_varobj_checked string string_1 \ + "struct string_repr" \ + "create string_1 varobj" + +mi_gdb_test "-data-evaluate-expression \"string_1 = string_2\"" ".*" \ + "assign string_1 from string_2" + +mi_gdb_test "-var-update string" \ + "\\^done,changelist=\\\[{name=\"string\",in_scope=\"true\",type_changed=\"false\",has_more=\"0\"}\\\]" \ + "update string varobj after assignment" + +mi_create_dynamic_varobj container c \ + "create container varobj" mi_list_varobj_children container { } "examine container children=0" mi_next "next over update 1" -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } -} "varobj update 1" +mi_varobj_update_dynamic container "varobj update 1" { + type_changed false new_num_children 1 has_more 0 +} { +} { + { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 } +} mi_next "next over update 2" -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } - { {container.\[1\]} {\[1\]} 0 int } -} "varobj update 2" +mi_varobj_update_dynamic container "varobj update 2" { + type_changed false new_num_children 2 has_more 0 +} { +} { + { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 } +} mi_gdb_test "-var-set-visualizer container None" \ "\\^done" \ @@ -78,19 +108,88 @@ mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \ "\\^done" \ "choose default visualizer" -mi_varobj_update_dynamic container { - { {container.\[0\]} {\[0\]} 0 int } - { {container.\[1\]} {\[1\]} 0 int } -} "varobj update after choosing default" +mi_varobj_update_dynamic container "varobj update after choosing default" { + type_changed false new_num_children 2 has_more 0 +} { +} { + { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 } + { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 } +} mi_gdb_test "-var-set-visualizer container ContainerPrinter" \ "\\^done" \ "choose visualizer using expression" -mi_varobj_update_dynamic container { +mi_varobj_update_dynamic container \ + "varobj update after choosing via expression" { + type_changed false new_num_children 2 has_more 0 + } { + } { + { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 } + { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 } + } + +mi_list_varobj_children_range container 1 2 2 { + { {container.\[1\]} {\[1\]} 0 int } +} "list varobj children after selecting child range" + +mi_list_varobj_children_range container -1 -1 2 { { {container.\[0\]} {\[0\]} 0 int } { {container.\[1\]} {\[1\]} 0 int } -} "varobj update after choosing via expression" +} "list varobj children after resetting child range" + +mi_next "next over update 3" + +mi_gdb_test "-var-set-update-range container 0 1" \ + "\\^done" \ + "set update range" + +# This should truncate the list. +mi_list_varobj_children container { + { {container.\[0\]} {\[0\]} 0 int } +} "list children after setting update range" + +# This should return just the items in [1,2). +mi_list_varobj_children_range container 1 2 2 { + { {container.\[1\]} {\[1\]} 0 int } +} "list selected children after setting range" + +# This should not be affected by the previous list-children request. +mi_list_varobj_children container { + { {container.\[0\]} {\[0\]} 0 int } +} "list children after listing selected range" + +mi_next "next over update 4" + + +# Regression test: examine an object that has no children, then update +# it to ensure that we don't print the children. +mi_create_dynamic_varobj container2 c2 \ + "create second container varobj" + +mi_gdb_test "-var-update container2" \ + "\\^done,changelist=.." \ + "update varobj, no children requested" + +mi_next "next over update 5" + +# Now container2 has an element -- and an update should mention that +# it has_more. But, because we did not request children, we still +# should not actually see them. +mi_varobj_update_dynamic container2 \ + "update varobj 2, no children requested" { + type_changed false has_more 1 + } {} {} + +# This should only show the first child, because the update range has +# been set. +mi_varobj_update_dynamic container \ + "update after next with restricted range" { + type_changed false new_num_children 1 has_more 1 + } { + { name {container.\[0\]} in_scope true type_changed false has_more 0 } + } { + } mi_continue_to_line \ [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \ diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c index 3cafc48..adf66b5 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.c +++ b/gdb/testsuite/gdb.python/python-prettyprint.c @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include + struct s { int a; @@ -148,6 +150,14 @@ void do_nothing(void) c = 23; /* Another MI breakpoint */ } +struct nullstr +{ + char *s; +}; + +struct string_repr string_1 = { { "one" } }; +struct string_repr string_2 = { { "two" } }; + int main () { @@ -155,11 +165,15 @@ main () struct ss ssa[2]; string x = make_string ("this is x"); zzz_type c = make_container ("container"); + zzz_type c2 = make_container ("container2"); const struct string_repr cstring = { { "const string" } }; + /* Clearing by being `static' could invoke an other GDB C++ bug. */ + struct nullstr nullstr; init_ss(&ss, 1, 2); init_ss(ssa+0, 3, 4); init_ss(ssa+1, 5, 6); + memset (&nullstr, 0, sizeof nullstr); struct ns ns; ns.null_str = "embedded\0null\0string"; @@ -193,6 +207,11 @@ main () add_item (&c, 72); #ifdef MI + add_item (&c, 1011); + c.elements[0] = 1023; + + add_item (&c2, 2222); + add_item (&c2, 3333); do_nothing (); #endif diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp index 01d4a06..b2dc85d 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.exp +++ b/gdb/testsuite/gdb.python/python-prettyprint.exp @@ -27,12 +27,9 @@ 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 } proc run_lang_tests {lang} { @@ -86,6 +83,8 @@ proc run_lang_tests {lang} { gdb_test "print c" " = container $hex \"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\." } diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py index bf009a1..c3e0dc4 100644 --- a/gdb/testsuite/gdb.python/python-prettyprint.py +++ b/gdb/testsuite/gdb.python/python-prettyprint.py @@ -92,6 +92,13 @@ class pp_vbase1: def to_string (self): return "pp class name: " + self.val.type.tag +class pp_nullstr: + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['s'].string(gdb.parameter('target-charset')) + class pp_ns: "Print a std::basic_string of some kind" @@ -109,7 +116,7 @@ def lookup_function (val): "Look-up and return a pretty-printer that can print val." # Get the type. - type = val.type; + type = val.type # If it points to a reference, get the reference. if type.code == gdb.TYPE_CODE_REF: @@ -148,6 +155,9 @@ def register_pretty_printers (): pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1 + + pretty_printers_dict[re.compile ('^struct nullstr$')] = pp_nullstr + pretty_printers_dict[re.compile ('^nullstr$')] = pp_nullstr # Note that we purposely omit the typedef names here. # Printer lookup is based on canonical name. diff --git a/gdb/testsuite/gdb.python/python-template.exp b/gdb/testsuite/gdb.python/python-template.exp index 1ace5d6..b80f56e 100644 --- a/gdb/testsuite/gdb.python/python-template.exp +++ b/gdb/testsuite/gdb.python/python-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 "python-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/python-value.exp b/gdb/testsuite/gdb.python/python-value.exp index 19cabeb..ccf438f 100644 --- a/gdb/testsuite/gdb.python/python-value.exp +++ b/gdb/testsuite/gdb.python/python-value.exp @@ -20,43 +20,6 @@ if $tracelevel then { strace $tracelevel } -set testfile "python-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 -} - -# 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 -} - -# 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 } } - } -} - proc test_value_creation {} { global gdb_prompt @@ -292,21 +255,37 @@ 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" +} + # 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 $" {} +if ![python_supported] then { + unsupported "python support is disabled" + return -1 } +set testfile "python-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 @@ -322,3 +301,4 @@ if ![runto_main] then { test_value_in_inferior test_value_after_death +test_cast_regression diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index 5223fc8..03e1eab 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/gdb.threads/watchthreads-reorder.c b/gdb/testsuite/gdb.threads/watchthreads-reorder.c new file mode 100644 index 0000000..14f42d6 --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchthreads-reorder.c @@ -0,0 +1,366 @@ +/* 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 . */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define gettid() syscall (__NR_gettid) + +/* Terminate always in the main task, it can lock up with SIGSTOPped GDB + otherwise. */ +#define TIMEOUT (gettid () == getpid() ? 10 : 15) + +static pthread_mutex_t gdbstop_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pid_t thread1_tid; +static pthread_cond_t thread1_tid_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t thread1_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pid_t thread2_tid; +static pthread_cond_t thread2_tid_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t thread2_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static volatile int thread1_rwatch; +static volatile int thread2_rwatch; + +static int unused1_rwatch; +static int unused2_rwatch; + +/* Do not use alarm as it would create a ptrace event which would hang up us if + * we are being traced by GDB which we stopped ourselves. */ + +static void timed_mutex_lock (pthread_mutex_t *mutex) +{ + int i; + struct timespec start, now; + + i = clock_gettime (CLOCK_MONOTONIC, &start); + assert (i == 0); + + do + { + i = pthread_mutex_trylock (mutex); + if (i == 0) + return; + assert (i == EBUSY); + + i = clock_gettime (CLOCK_MONOTONIC, &now); + assert (i == 0); + assert (now.tv_sec >= start.tv_sec); + } + while (now.tv_sec - start.tv_sec < TIMEOUT); + + fprintf (stderr, "Timed out waiting for internal lock!\n"); + exit (EXIT_FAILURE); +} + +static void * +thread1_func (void *unused) +{ + int i; + volatile int rwatch_store; + + thread1_tid = gettid (); + i = pthread_cond_signal (&thread1_tid_cond); + assert (i == 0); + + /* Be sure GDB is already stopped before continuing. */ + timed_mutex_lock (&gdbstop_mutex); + i = pthread_mutex_unlock (&gdbstop_mutex); + assert (i == 0); + + rwatch_store = thread1_rwatch; + + /* Be sure the "T (tracing stop)" test can proceed for both threads. */ + timed_mutex_lock (&terminate_mutex); + i = pthread_mutex_unlock (&terminate_mutex); + assert (i == 0); + + return NULL; +} + +static void * +thread2_func (void *unused) +{ + int i; + volatile int rwatch_store; + + thread2_tid = gettid (); + i = pthread_cond_signal (&thread2_tid_cond); + assert (i == 0); + + /* Be sure GDB is already stopped before continuing. */ + timed_mutex_lock (&gdbstop_mutex); + i = pthread_mutex_unlock (&gdbstop_mutex); + assert (i == 0); + + rwatch_store = thread2_rwatch; + + /* Be sure the "T (tracing stop)" test can proceed for both threads. */ + timed_mutex_lock (&terminate_mutex); + i = pthread_mutex_unlock (&terminate_mutex); + assert (i == 0); + + return NULL; +} + +static const char * +proc_string (const char *filename, const char *line) +{ + FILE *f; + static char buf[LINE_MAX]; + size_t line_len = strlen (line); + + f = fopen (filename, "r"); + if (f == NULL) + { + fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line, + strerror (errno)); + exit (EXIT_FAILURE); + } + while (errno = 0, fgets (buf, sizeof (buf), f)) + { + char *s; + + s = strchr (buf, '\n'); + assert (s != NULL); + *s = 0; + + if (strncmp (buf, line, line_len) != 0) + continue; + + if (fclose (f)) + { + fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line, + strerror (errno)); + exit (EXIT_FAILURE); + } + + return &buf[line_len]; + } + if (errno != 0) + { + fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno)); + exit (EXIT_FAILURE); + } + fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line); + exit (EXIT_FAILURE); +} + +static unsigned long +proc_ulong (const char *filename, const char *line) +{ + const char *s = proc_string (filename, line); + long retval; + char *end; + + errno = 0; + retval = strtol (s, &end, 10); + if (retval < 0 || retval >= LONG_MAX || (end && *end)) + { + fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval, + strerror (errno)); + exit (EXIT_FAILURE); + } + return retval; +} + +static void +state_wait (pid_t process, const char *wanted) +{ + char *filename; + int i; + struct timespec start, now; + const char *state; + + i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process); + assert (i > 0); + + i = clock_gettime (CLOCK_MONOTONIC, &start); + assert (i == 0); + + do + { + state = proc_string (filename, "State:\t"); + if (strcmp (state, wanted) == 0) + { + free (filename); + return; + } + + if (sched_yield ()) + { + perror ("sched_yield()"); + exit (EXIT_FAILURE); + } + + i = clock_gettime (CLOCK_MONOTONIC, &now); + assert (i == 0); + assert (now.tv_sec >= start.tv_sec); + } + while (now.tv_sec - start.tv_sec < TIMEOUT); + + fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n", + (unsigned long) process, wanted, state); + exit (EXIT_FAILURE); +} + +static volatile pid_t tracer = 0; +static pthread_t thread1, thread2; + +static void +cleanup (void) +{ + printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer); + + if (tracer) + { + int i; + int tracer_save = tracer; + + tracer = 0; + + i = kill (tracer_save, SIGCONT); + assert (i == 0); + } +} + +int +main (int argc, char **argv) +{ + int i; + int standalone = 0; + + if (argc == 2 && strcmp (argv[1], "-s") == 0) + standalone = 1; + else + assert (argc == 1); + + setbuf (stdout, NULL); + + timed_mutex_lock (&gdbstop_mutex); + + timed_mutex_lock (&terminate_mutex); + + i = pthread_create (&thread1, NULL, thread1_func, NULL); + assert (i == 0); + + i = pthread_create (&thread2, NULL, thread2_func, NULL); + assert (i == 0); + + if (!standalone) + { + tracer = proc_ulong ("/proc/self/status", "TracerPid:\t"); + if (tracer == 0) + { + fprintf (stderr, "The testcase must be run by GDB!\n"); + exit (EXIT_FAILURE); + } + if (tracer != getppid ()) + { + fprintf (stderr, "The testcase parent must be our GDB tracer!\n"); + exit (EXIT_FAILURE); + } + } + + /* SIGCONT our debugger in the case of our crash as we would deadlock + otherwise. */ + + atexit (cleanup); + + printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer); + + if (tracer) + { + i = kill (tracer, SIGSTOP); + assert (i == 0); + state_wait (tracer, "T (stopped)"); + } + + timed_mutex_lock (&thread1_tid_mutex); + timed_mutex_lock (&thread2_tid_mutex); + + /* Let the threads start. */ + i = pthread_mutex_unlock (&gdbstop_mutex); + assert (i == 0); + + printf ("Waiting till the threads initialize their TIDs.\n"); + + if (thread1_tid == 0) + { + i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex); + assert (i == 0); + + assert (thread1_tid > 0); + } + + if (thread2_tid == 0) + { + i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex); + assert (i == 0); + + assert (thread2_tid > 0); + } + + printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n", + (unsigned long) thread1_tid, (unsigned long) thread2_tid, + (unsigned long) getpid ()); + + printf ("Waiting till the threads get trapped by the watchpoints.\n"); + + if (tracer) + { + /* s390x-unknown-linux-gnu will fail with "R (running)". */ + + state_wait (thread1_tid, "T (tracing stop)"); + + state_wait (thread2_tid, "T (tracing stop)"); + } + + cleanup (); + + printf ("Joining the threads.\n"); + + i = pthread_mutex_unlock (&terminate_mutex); + assert (i == 0); + + i = pthread_join (thread1, NULL); + assert (i == 0); + + i = pthread_join (thread2, NULL); + assert (i == 0); + + printf ("Exiting.\n"); /* break-at-exit */ + + /* Just prevent compiler `warning: $B!F(BunusedX_rwatch$B!G(B defined but not used'. */ + unused1_rwatch = 1; + unused2_rwatch = 2; + + return EXIT_SUCCESS; +} diff --git a/gdb/testsuite/gdb.threads/watchthreads-reorder.exp b/gdb/testsuite/gdb.threads/watchthreads-reorder.exp new file mode 100644 index 0000000..8f65364 --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchthreads-reorder.exp @@ -0,0 +1,101 @@ +# 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 . + +# Test GDB can cope with two watchpoints being hit by different threads at the +# same time, GDB reports one of them and after "continue" to report the other +# one GDB should not be confused by differently set watchpoints that time. +# This is the goal of "reorder1". "reorder0" tests the basic functionality of +# two watchpoint being hit at the same time, without reordering them during the +# stop. The formerly broken functionality is due to the all-stop mode default +# "show breakpoint always-inserted" being "off". Formerly the remembered hit +# could be assigned during continuation of a thread with pending SIGTRAP to the +# different/new watchpoint, just based on the watchpoint/debug register number. + +if {[target_info exists gdb,no_hardware_watchpoints] + || ![istarget *-*-linux*]} { + return 0; +} + +set testfile "watchthreads-reorder" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" ${binfile} executable [list debug additional_flags=-lrt]] != "" } { + return -1 +} + +foreach reorder {0 1} { + + global pf_prefix + set prefix_test $pf_prefix + lappend pf_prefix "reorder$reorder:" + + clean_restart $testfile + + gdb_test "set can-use-hw-watchpoints 1" + + if ![runto_main] { + gdb_suppress_tests + } + + # Use "rwatch" as "watch" would report the watchpoint changed just based on its + # read memory value during a stop by unrelated event. We are interested to not + # to lose the hardware watchpoint trigger. + + gdb_test "rwatch thread1_rwatch" "Hardware read watchpoint \[0-9\]+: thread1_rwatch" + gdb_test {set $rwatch1=$bpnum} + set test "rwatch thread2_rwatch" + gdb_test_multiple $test $test { + -re "Target does not support this type of hardware watchpoint\\.\r\n$gdb_prompt $" { + # ppc64 supports at most 1 hw watchpoints. + unsupported $test + return + } + -re "Hardware read watchpoint \[0-9\]+: thread2_rwatch\r\n$gdb_prompt $" { + pass $test + } + } + gdb_test {set $rwatch2=$bpnum} + gdb_breakpoint [gdb_get_line_number "break-at-exit"] + + # The watchpoints can happen in arbitrary order depending on random: + # SEL: Found 2 SIGTRAP events, selecting #[01] + # As GDB contains no srand() on the specific host/OS it will behave always the + # same. Such order cannot be guaranteed for GDB in general. + + gdb_test "continue" \ + "Hardware read watchpoint \[0-9\]+: thread\[12\]_rwatch\r\n\r\nValue = 0\r\n0x\[0-9a-f\]+ in thread\[12\]_func .*" \ + "continue a" + + if $reorder { + gdb_test {delete $rwatch1} + gdb_test {delete $rwatch2} + + gdb_test "rwatch unused1_rwatch" "Hardware read watchpoint \[0-9\]+: unused1_rwatch" + gdb_test "rwatch unused2_rwatch" "Hardware read watchpoint \[0-9\]+: unused2_rwatch" + + gdb_test "rwatch thread1_rwatch" "Hardware read watchpoint \[0-9\]+: thread1_rwatch" + gdb_test "rwatch thread2_rwatch" "Hardware read watchpoint \[0-9\]+: thread2_rwatch" + } + + gdb_test "continue" \ + "Hardware read watchpoint \[0-9\]+: thread\[12\]_rwatch\r\n\r\nValue = 0\r\n0x\[0-9a-f\]+ in thread\[12\]_func .*" \ + "continue b" + + gdb_continue_to_breakpoint "break-at-exit" ".*break-at-exit.*" + + set pf_prefix $prefix_test +} diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp index dbd2f59..44e1b51 100644 --- a/gdb/testsuite/lib/cp-support.exp +++ b/gdb/testsuite/lib/cp-support.exp @@ -222,7 +222,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { set parse_okay 0 gdb_test_multiple "$in_command" "$in_testname // parse failed" { - -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { + -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_:\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { set parse_okay 1 set actual_key $expect_out(1,string) set actual_tag $expect_out(2,string) @@ -231,6 +231,7 @@ proc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { set actual_tail $expect_out(6,string) } } + if { ! $parse_okay } then { return } # Check the actual key. It would be nice to require that it match diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 0c93a73..d0c3493 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/mi-support.exp b/gdb/testsuite/lib/mi-support.exp index e691232..167a02c 100644 --- a/gdb/testsuite/lib/mi-support.exp +++ b/gdb/testsuite/lib/mi-support.exp @@ -1195,13 +1195,13 @@ proc mi_list_breakpoints { expected test } { # Name cannot be "-". proc mi_create_varobj { name expression testname } { mi_gdb_test "-var-create $name * $expression" \ - "\\^done,name=\"$name\",numchild=\"\[0-9\]+\",value=\".*\",type=.*" \ + "\\^done,name=\"$name\",numchild=\"\[0-9\]+\",value=\".*\",type=.*,has_more=\"0\"" \ $testname } proc mi_create_floating_varobj { name expression testname } { mi_gdb_test "-var-create $name @ $expression" \ - "\\^done,name=\"$name\",numchild=\"\[0-9\]+\",value=\".*\",type=.*" \ + "\\^done,name=\"$name\",numchild=\"\(-1\|\[0-9\]+\)\",value=\".*\",type=.*" \ $testname } @@ -1214,6 +1214,14 @@ proc mi_create_varobj_checked { name expression type testname } { $testname } +# Same as mi_create_floating_varobj, but assumes the test is creating +# a dynamic varobj that has children, so the value must be "{...}". +proc mi_create_dynamic_varobj {name expression testname} { + mi_gdb_test "-var-create $name @ $expression" \ + "\\^done,name=\"$name\",numchild=\"\(-1\|\[0-9\]+\)\",value=\"{\\.\\.\\.}\",type=.*" \ + $testname +} + # Deletes the specified NAME. proc mi_delete_varobj { name testname } { mi_gdb_test "-var-delete $name" \ @@ -1229,7 +1237,7 @@ proc mi_varobj_update { name expected testname } { set er "\\^done,changelist=\\\[" set first 1 foreach item $expected { - set v "{name=\"$item\",in_scope=\"true\",type_changed=\"false\"}" + set v "{name=\"$item\",in_scope=\"true\",type_changed=\"false\",has_more=\".\"}" if {$first == 1} { set er "$er$v" set first 0 @@ -1244,22 +1252,70 @@ proc mi_varobj_update { name expected testname } { } proc mi_varobj_update_with_type_change { name new_type new_children testname } { - set v "{name=\"$name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\"}" + set v "{name=\"$name\",in_scope=\"true\",type_changed=\"true\",new_type=\"$new_type\",new_num_children=\"$new_children\",has_more=\".\"}" set er "\\^done,changelist=\\\[$v\\\]" verbose -log "Expecting: $er" mi_gdb_test "-var-update $name" $er $testname } -# Update a dynamic varobj named NAME. CHILDREN is a list of children, -# in the same form as mi_list_varobj_children. TESTNAME is the name -# of the test. -proc mi_varobj_update_dynamic {name children testname} { - set children_exp_j [mi_child_regexp $children 0] +# A helper that turns a key/value list into a regular expression +# matching some MI output. +proc mi_varobj_update_kv_helper {list} { + set first 1 + set rx "" + foreach {key value} $list { + if {!$first} { + append rx , + } + set first 0 + if {$key == "new_children"} { + append rx "$key=\\\[$value\\\]" + } else { + append rx "$key=\"$value\"" + } + } + return $rx +} - set er "\\^done,changelist=\\\[" +# A helper for mi_varobj_update_dynamic that computes a match +# expression given a child list. +proc mi_varobj_update_dynamic_helper {children} { + set crx "" - append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\"" - append er ",children=\\\[$children_exp_j.*\\\]}\\\]" + set first 1 + foreach child $children { + if {!$first} { + append crx , + } + set first 0 + append crx "{" + append crx [mi_varobj_update_kv_helper $child] + append crx "}" + } + + return $crx +} + +# Update a dynamic varobj named NAME. CHILDREN is a list of children +# that have been updated; NEW_CHILDREN is a list of children that were +# added to the primary varobj. Each child is a list of key/value +# pairs that are expected. SELF is a key/value list holding +# information about the varobj itself. TESTNAME is the name of the +# test. +proc mi_varobj_update_dynamic {name testname self children new_children} { + if {[llength $new_children]} { + set newrx [mi_varobj_update_dynamic_helper $new_children] + lappend self new_children $newrx + } + set selfrx [mi_varobj_update_kv_helper $self] + set crx [mi_varobj_update_dynamic_helper $children] + + set er "\\^done,changelist=\\\[\{name=\"$name\",in_scope=\"true\"" + append er ",$selfrx\}" + if {"$crx" != ""} { + append er ",$crx" + } + append er "\\\]" verbose -log "Expecting: $er" mi_gdb_test "-var-update $name" $er $testname @@ -1329,14 +1385,13 @@ proc mi_child_regexp {children add_child} { # have no value. # proc mi_list_varobj_children { varname children testname } { - mi_list_varobj_children_range $varname [llength $children] $children \ + mi_list_varobj_children_range $varname "" "" [llength $children] $children \ $testname } -# Like mi_list_varobj_children, but assumes that a subrange has been -# selected with -var-set-child-range. NUMCHILDREN is the total number -# of children. -proc mi_list_varobj_children_range {varname numchildren children testname} { +# Like mi_list_varobj_children, but sets a subrange. NUMCHILDREN is +# the total number of children. +proc mi_list_varobj_children_range {varname from to numchildren children testname} { set options "" if {[llength $varname] == 2} { set options [lindex $varname 1] @@ -1352,9 +1407,18 @@ proc mi_list_varobj_children_range {varname numchildren children testname} { set expected "\\^done,numchild=\"0\"" } + if {"$to" == ""} { + append expected ",has_more=\"0\"" + } elseif {$to >= 0 && $numchildren > $to} { + append expected ",has_more=\"1\"" + } else { + append expected ",has_more=\"0\"" + } + verbose -log "Expecting: $expected" - mi_gdb_test "-var-list-children $options $varname" $expected $testname + mi_gdb_test "-var-list-children $options $varname $from $to" \ + $expected $testname } # Verifies that variable object VARNAME has NUMBER children, 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 a7ac3c8..815c82d 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),... */ @@ -497,16 +496,23 @@ thread_alive (struct thread_info *tp) return 1; } -static void +void prune_threads (void) { - struct thread_info *tp, *next; + struct thread_info *tp; + struct thread_info **prevp = &thread_list; - for (tp = thread_list; tp; tp = next) + for (tp = *prevp; tp; tp = *prevp) { - next = tp->next; + /* If the thread has died, free it and unlink it from the list. + Otherwise, advance to the next thread. */ if (!thread_alive (tp)) - delete_thread (tp->ptid); + { + *prevp = tp->next; + free_thread (tp); + } + else + prevp = &tp->next; } } diff --git a/gdb/top.c b/gdb/top.c index cb51e08..b126a8a 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -378,6 +378,7 @@ execute_command (char *p, int from_tty) } free_all_values (); + free_all_types (); /* Force cleanup of any alloca areas if using C alloca instead of a builtin alloca. */ diff --git a/gdb/typeprint.c b/gdb/typeprint.c index f090231..fc15ec1 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -35,6 +35,8 @@ #include "gdb_string.h" #include "exceptions.h" #include "valprint.h" +#include "dwarf2loc.h" + #include extern void _initialize_typeprint (void); @@ -76,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); } @@ -114,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; @@ -125,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); @@ -167,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/typeprint.h b/gdb/typeprint.h index f561310..d261c79 100644 --- a/gdb/typeprint.h +++ b/gdb/typeprint.h @@ -20,10 +20,13 @@ #ifndef TYPEPRINT_H #define TYPEPRINT_H +enum language; struct ui_file; void print_type_scalar (struct type * type, LONGEST, struct ui_file *); void c_type_print_varspec_suffix (struct type *, struct ui_file *, int, int, int); + +void c_type_print_args (struct type *, struct ui_file *, int, enum language); #endif diff --git a/gdb/ui-file.c b/gdb/ui-file.c index 527917c..07d959a 100644 --- a/gdb/ui-file.c +++ b/gdb/ui-file.c @@ -22,6 +22,7 @@ #include "defs.h" #include "ui-file.h" +#include "gdb_obstack.h" #include "gdb_string.h" #include @@ -263,7 +264,7 @@ set_ui_file_data (struct ui_file *file, void *data, } /* ui_file utility function for converting a ``struct ui_file'' into - a memory buffer''. */ + a memory buffer. */ struct accumulated_ui_file { @@ -297,6 +298,23 @@ ui_file_xstrdup (struct ui_file *file, long *length) *length = acc.length; return acc.buffer; } + +static void +do_ui_file_obsavestring (void *context, const char *buffer, long length) +{ + struct obstack *obstack = (struct obstack *) context; + obstack_grow (obstack, buffer, length); +} + +char * +ui_file_obsavestring (struct ui_file *file, struct obstack *obstack, + long *length) +{ + ui_file_put (file, do_ui_file_obsavestring, obstack); + *length = obstack_object_size (obstack); + obstack_1grow (obstack, '\0'); + return obstack_finish (obstack); +} /* A pure memory based ``struct ui_file'' that can be used an output buffer. The buffers accumulated contents are available via diff --git a/gdb/ui-file.h b/gdb/ui-file.h index bf9915c..233206c 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -19,6 +19,7 @@ #ifndef UI_FILE_H #define UI_FILE_H +struct obstack; struct ui_file; /* Create a generic ui_file object with null methods. */ @@ -77,7 +78,10 @@ extern void ui_file_put (struct ui_file *src, ui_file_put_method_ftype *write, v minus that appended NUL. */ extern char *ui_file_xstrdup (struct ui_file *file, long *length); - +/* Similar to ui_file_xstrdup, but return a new string allocated on + OBSTACK. */ +extern char *ui_file_obsavestring (struct ui_file *file, + struct obstack *obstack, long *length); extern long ui_file_read (struct ui_file *file, char *buf, long length_buf); diff --git a/gdb/utils.c b/gdb/utils.c index 16ad084..3021a43 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -2610,7 +2610,10 @@ fprintf_symbol_filtered (struct ui_file *stream, char *name, As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO". This "feature" is useful when searching for matching C++ function names (such as if the user types 'break FOO', where FOO is a mangled C++ - function). */ + function). + + As an extra-special hack, we do the same with ' ', so that + "FOO(ARGS) const" can match "FOO", too. */ int strcmp_iw (const char *string1, const char *string2) @@ -2635,7 +2638,7 @@ strcmp_iw (const char *string1, const char *string2) string2++; } } - return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0'); + return (*string1 != ' ' && *string1 != '\0' && *string1 != '(') || (*string2 != '\0' && *string2 != '('); } /* This is like strcmp except that it ignores whitespace and treats diff --git a/gdb/valarith.c b/gdb/valarith.c index a9c875d..12f6f07 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 5e5c4ed..7aedbfd 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" @@ -369,8 +370,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, @@ -565,6 +564,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; +} + /* Return a value with type TYPE located at ADDR. Call value_at only if the data needs to be fetched immediately; @@ -652,11 +709,19 @@ 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 (object_address_get_data (value_type (val), &addr)) + { + struct type *type = value_enclosing_type (val); + int length = TYPE_LENGTH (check_typedef (type)); - if (length) - read_memory (addr, value_contents_all_raw (val), length); + if (length) + { + addr += value_offset (val); + read_memory (addr, value_contents_all_raw (val), length); + } + } } else if (VALUE_LVAL (val) == lval_register) { @@ -1061,7 +1126,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); } @@ -1167,6 +1243,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 @@ -1176,8 +1253,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 @@ -2060,12 +2141,25 @@ find_overload_match (struct type **arg_types, int nargs, if (method) { gdb_assert (obj); + + /* OBJ may be a pointer value rather than the object itself. */ + obj = coerce_ref (obj); + while (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_PTR) + obj = coerce_ref (value_ind (obj)); obj_type_name = TYPE_NAME (value_type (obj)); - /* Hack: evaluate_subexp_standard often passes in a pointer - value rather than the object itself, so try again. */ - if ((!obj_type_name || !*obj_type_name) - && (TYPE_CODE (value_type (obj)) == TYPE_CODE_PTR)) - obj_type_name = TYPE_NAME (TYPE_TARGET_TYPE (value_type (obj))); + + /* First check whether this is a data member, e.g. a pointer to + a function. */ + if (TYPE_CODE (check_typedef (value_type (obj))) == TYPE_CODE_STRUCT) + { + *valp = search_struct_field (name, obj, 0, + check_typedef (value_type (obj)), 0); + if (*valp) + { + *staticp = 1; + return 0; + } + } fns_ptr = value_find_oload_method_list (&temp, name, 0, &num_fns, @@ -2085,16 +2179,29 @@ find_overload_match (struct type **arg_types, int nargs, } else { - const char *qualified_name = SYMBOL_CPLUS_DEMANGLED_NAME (fsym); + const char *qualified_name = SYMBOL_NATURAL_NAME (fsym); + + /* If we have a function with a C++ name, try to extract just + the function part. Do not try this for non-functions (e.g. + function pointers). */ + if (qualified_name + && TYPE_CODE (check_typedef (SYMBOL_TYPE (fsym))) == TYPE_CODE_FUNC) + { + func_name = cp_func_name (qualified_name); - /* If we have a C++ name, try to extract just the function - part. */ - if (qualified_name) - func_name = cp_func_name (qualified_name); + /* If cp_func_name did not remove anything, the name of the + symbol did not include scope or argument types - it was + probably a C-style function. */ + if (func_name && strcmp (func_name, qualified_name) == 0) + { + xfree (func_name); + func_name = NULL; + } + } - /* If there was no C++ name, this must be a C-style function. - Just return the same symbol. Do the same if cp_func_name - fails for some reason. */ + /* If there was no C++ name, this must be a C-style function or + not a function at all. Just return the same symbol. Do the + same if cp_func_name fails for some reason. */ if (func_name == NULL) { *symp = fsym; @@ -2525,8 +2632,8 @@ check_field (struct type *type, const char *name) the comment before value_struct_elt_for_reference. */ struct value * -value_aggregate_elt (struct type *curtype, - char *name, int want_address, +value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside) { switch (TYPE_CODE (curtype)) @@ -2534,7 +2641,7 @@ value_aggregate_elt (struct type *curtype, case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: return value_struct_elt_for_reference (curtype, 0, curtype, - name, NULL, + name, expect_type, want_address, noside); case TYPE_CODE_NAMESPACE: return value_namespace_elt (curtype, name, @@ -2545,6 +2652,56 @@ value_aggregate_elt (struct type *curtype, } } +/* Compares the two method/function types T1 and T2 for "equality" + with respect to the the methods' parameters. If the types of the + two parameter lists are the same, returns 1; 0 otherwise. This + comparison may ignore any artificial parameters in T1 if + SKIP_ARTIFICIAL is non-zero. This function will ALWAYS skip + the first artificial parameter in T1, assumed to be a 'this' pointer. + + The type T2 is expected to have come from make_params (in eval.c). */ +static int +compare_parameters (struct type *t1, struct type *t2, int skip_artificial) +{ + int start = 0; + + if (TYPE_FIELD_ARTIFICIAL (t1, 0)) + ++start; + + /* If skipping artificial fields, find the first real field + in T1. */ + if (skip_artificial) + { + while (start < TYPE_NFIELDS (t1) + && TYPE_FIELD_ARTIFICIAL (t1, start)) + ++start; + } + + /* Now compare parameters */ + + /* Special case: a method taking void. T1 will contain no + non-artificial fields, and T2 will contain TYPE_CODE_VOID. */ + if ((TYPE_NFIELDS (t1) - start) == 0 && TYPE_NFIELDS (t2) == 1 + && TYPE_CODE (TYPE_FIELD_TYPE (t2, 0)) == TYPE_CODE_VOID) + return 1; + + if ((TYPE_NFIELDS (t1) - start) == TYPE_NFIELDS (t2)) + { + int i; + for (i = 0; i < TYPE_NFIELDS (t2); ++i) + { + if (rank_one_type (TYPE_FIELD_TYPE (t1, start + i), + TYPE_FIELD_TYPE (t2, i)) + != 0) + return 0; + } + + return 1; + } + + return 0; +} + /* C++: Given an aggregate type CURTYPE, and a member name NAME, return the address of this member as a "pointer to member" type. If INTYPE is non-null, then it will be the type of the member we @@ -2622,23 +2779,46 @@ value_struct_elt_for_reference (struct type *domain, int offset, } if (t_field_name && strcmp (t_field_name, name) == 0) { - int j = TYPE_FN_FIELDLIST_LENGTH (t, i); + int j; + int len = TYPE_FN_FIELDLIST_LENGTH (t, i); struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); check_stub_method_group (t, i); - if (intype == 0 && j > 1) - error (_("non-unique member `%s' requires type instantiation"), name); if (intype) { - while (j--) - if (TYPE_FN_FIELD_TYPE (f, j) == intype) - break; - if (j < 0) - error (_("no member function matches that type instantiation")); - } + for (j = 0; j < len; ++j) + { + if (compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype, 0) + || compare_parameters (TYPE_FN_FIELD_TYPE (f, j), intype, 1)) + break; + } + + if (j == len) + error (_("no member function matches that type instantiation")); } else - j = 0; + { + int ii; + /* Skip artificial methods. This is necessary if, for example, + the user wants to "print subclass::subclass" with only + one defined user constructor. There is no ambiguity in this + case. */ + for (ii = 0; ii < TYPE_FN_FIELDLIST_LENGTH (t, i); + ++ii) + { + if (TYPE_FN_FIELD_ARTIFICIAL (f, ii)) + --len; + } + + /* Desired method is ambiguous if more than one method is + defined. */ + if (len > 1) + error (_("non-unique member `%s' requires type instantiation"), name); + + /* This assumes, of course, that all artificial methods appear + BEFORE any concrete methods. */ + j = TYPE_FN_FIELDLIST_LENGTH (t, i) - 1; + } if (TYPE_FN_FIELD_STATIC_P (f, j)) { @@ -2752,7 +2932,7 @@ value_maybe_namespace_elt (const struct type *curtype, struct symbol *sym; struct value *result; - sym = cp_lookup_symbol_namespace (namespace_name, name, NULL, + sym = cp_lookup_symbol_namespace(namespace_name, name, get_selected_block (0), VAR_DOMAIN); @@ -2896,7 +3076,7 @@ value_of_local (const char *name, int complain) /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER symbol instead of the LOC_ARG one (if both exist). */ - sym = lookup_block_symbol (b, name, NULL, VAR_DOMAIN); + sym = lookup_block_symbol (b, name, VAR_DOMAIN); if (sym == NULL) { if (complain) @@ -2950,8 +3130,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 cbb5d94..f9634ea 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: @@ -1153,6 +1152,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) @@ -1172,7 +1172,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 48fedfd..5c207e3 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; @@ -257,7 +267,9 @@ allocate_value_lazy (struct type *type) val->next = all_values; all_values = val; val->type = type; + type_incref (type); val->enclosing_type = type; + type_incref (type); VALUE_LVAL (val) = not_lval; val->location.address = 0; VALUE_FRAME_ID (val) = null_frame_id; @@ -342,6 +354,8 @@ value_type (struct value *value) void deprecated_set_value_type (struct value *value, struct type *type) { + type_incref (type); + type_decref (value->type); value->type = type; } @@ -608,6 +622,9 @@ value_free (struct value *val) if (val->parent != NULL) value_free (val->parent); + type_decref (val->type); + type_decref (val->enclosing_type); + if (VALUE_LVAL (val) == lval_computed) { struct lval_funcs *funcs = val->location.computed.funcs; @@ -711,6 +728,9 @@ value_copy (struct value *arg) val = allocate_value_lazy (encl_type); else val = allocate_value (encl_type); + + type_incref (arg->type); + type_decref (val->type); val->type = arg->type; VALUE_LVAL (val) = VALUE_LVAL (arg); val->location = arg->location; @@ -746,12 +766,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; @@ -759,6 +782,10 @@ 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); + set_value_address (component, addr); } @@ -889,6 +916,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. @@ -1364,6 +1414,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 @@ -1411,11 +1495,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); } @@ -1430,13 +1513,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: @@ -1838,6 +1921,8 @@ value_change_enclosing_type (struct value *val, struct type *new_encl_type) val->contents = (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type)); + type_incref (new_encl_type); + type_decref (val->enclosing_type); val->enclosing_type = new_encl_type; return val; } @@ -1902,6 +1987,8 @@ value_primitive_field (struct value *arg1, int offset, memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1), TYPE_LENGTH (value_enclosing_type (arg1))); } + type_incref (type); + type_decref (v->type); v->type = type; v->offset = value_offset (arg1); v->embedded_offset = (offset + value_embedded_offset (arg1) @@ -2152,6 +2239,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 * @@ -2165,6 +2288,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 * @@ -2323,4 +2459,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 6f6b756..b9ca650 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -339,11 +339,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); @@ -433,6 +438,7 @@ extern struct value *value_struct_elt (struct value **argp, extern struct value *value_aggregate_elt (struct type *curtype, char *name, + struct type *expect_type, int want_address, enum noside noside); @@ -678,7 +684,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 fbe8ff8..490ca33 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -26,9 +26,12 @@ #include "gdbcmd.h" #include "block.h" #include "valprint.h" +#include "objfiles.h" +#include "parser-defs.h" #include "gdb_assert.h" #include "gdb_string.h" +#include "gdb_regex.h" #include "varobj.h" #include "vec.h" @@ -59,6 +62,15 @@ char *varobj_format_string[] = /* String representations of gdb's known languages */ char *varobj_language_string[] = { "unknown", "C", "C++", "Java" }; +/* True if we want to allow Python-based pretty-printing. */ +static int pretty_printing = 0; + +void +varobj_enable_pretty_printing (void) +{ + pretty_printing = 1; +} + /* Data structures */ /* Every root variable has one of these structures saved in its @@ -173,9 +185,31 @@ struct varobj frozen. */ int not_fetched; + /* Sub-range of children which the MI consumer has requested. If + FROM < 0 or TO < 0, means that all children have been + requested. */ + int from; + int to; + + /* The pretty-printer constructor. If NULL, then the default + pretty-printer will be looked up. If None, then no + pretty-printer will be installed. */ + PyObject *constructor; + /* The pretty-printer that has been constructed. If NULL, then a new printer object is needed, and one will be constructed. */ PyObject *pretty_printer; + + /* The iterator returned by the printer's 'children' method, or NULL + if not available. */ + PyObject *child_iter; + + /* We request one extra item from the iterator, so that we can + report to the caller whether there are more items than we have + already reported. However, we don't want to install this value + when we read it, because that will mess up future updates. So, + we stash it here instead. */ + PyObject *saved_item; }; struct cpstack @@ -221,6 +255,8 @@ static void free_variable (struct varobj *var); static struct cleanup *make_cleanup_free_variable (struct varobj *var); +static struct cleanup *make_cleanup_uninstall_variable (struct varobj *var); + static struct type *get_type (struct varobj *var); static struct type *get_value_type (struct varobj *var); @@ -236,8 +272,6 @@ static char *cppop (struct cpstack **pstack); static int install_new_value (struct varobj *var, struct value *value, int initial); -static void install_default_visualizer (struct varobj *var); - /* Language-specific routines. */ static enum varobj_languages variable_language (struct varobj *var); @@ -450,6 +484,8 @@ is_root_p (struct varobj *var) struct cleanup * varobj_ensure_python_env (struct varobj *var) { + gdb_assert (var->root->is_valid); + return ensure_python_env (var->root->exp->gdbarch, var->root->exp->language_defn); } @@ -614,9 +650,9 @@ varobj_create (char *objname, do_cleanups (old_chain); return NULL; } + make_cleanup_uninstall_variable (var); } - install_default_visualizer (var); discard_cleanups (old_chain); return var; } @@ -731,15 +767,8 @@ instantiate_pretty_printer (PyObject *constructor, struct value *value) #if HAVE_PYTHON PyObject *val_obj = NULL; PyObject *printer; - 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; @@ -792,7 +821,12 @@ varobj_get_display_hint (struct varobj *var) char *result = NULL; #if HAVE_PYTHON - struct cleanup *back_to = varobj_ensure_python_env (var); + struct cleanup *back_to; + + if (!var->root->is_valid) + return NULL; + + back_to = varobj_ensure_python_env (var); if (var->pretty_printer) result = gdbpy_get_display_hint (var->pretty_printer); @@ -803,6 +837,17 @@ varobj_get_display_hint (struct varobj *var) return result; } +/* Return true if the varobj has items after TO, false otherwise. */ + +int +varobj_has_more (struct varobj *var, int to) +{ + if (VEC_length (varobj_p, var->children) > to) + return 1; + return ((to == -1 || VEC_length (varobj_p, var->children) == to) + && var->saved_item != NULL); +} + /* If the variable object is bound to a specific thread, that is its evaluation can always be done in context of a frame inside that thread, returns GDB id of the thread -- which @@ -835,22 +880,90 @@ varobj_get_frozen (struct varobj *var) return var->frozen; } +/* A helper function that restricts a range to what is actually + available in a VEC. This follows the usual rules for the meaning + of FROM and TO -- if either is negative, the entire range is + used. */ + +static void +restrict_range (VEC (varobj_p) *children, int *from, int *to) +{ + if (*from < 0 || *to < 0) + { + *from = 0; + *to = VEC_length (varobj_p, children); + } + else + { + if (*from > VEC_length (varobj_p, children)) + *from = VEC_length (varobj_p, children); + if (*to > VEC_length (varobj_p, children)) + *to = VEC_length (varobj_p, children); + if (*from > *to) + *from = *to; + } +} + +/* A helper for update_dynamic_varobj_children that installs a new + child when needed. */ + +static void +install_dynamic_child (struct varobj *var, + VEC (varobj_p) **changed, + VEC (varobj_p) **new, + int *cchanged, + int index, + const char *name, + struct value *value) +{ + if (VEC_length (varobj_p, var->children) < index + 1) + { + /* There's no child yet. */ + struct varobj *child = varobj_add_child (var, name, value); + if (new) + VEC_safe_push (varobj_p, *new, child); + *cchanged = 1; + } + else + { + varobj_p existing = VEC_index (varobj_p, var->children, index); + if (install_new_value (existing, value, 0)) + { + if (changed) + VEC_safe_push (varobj_p, *changed, existing); + } + } +} + +#if HAVE_PYTHON + +static int +dynamic_varobj_has_child_method (struct varobj *var) +{ + struct cleanup *back_to; + PyObject *printer = var->pretty_printer; + int result; + + back_to = varobj_ensure_python_env (var); + result = PyObject_HasAttr (printer, gdbpy_children_cst); + do_cleanups (back_to); + return result; +} + +#endif + static int update_dynamic_varobj_children (struct varobj *var, VEC (varobj_p) **changed, - VEC (varobj_p) **new_and_unchanged, - int *cchanged) - + VEC (varobj_p) **new, + int *cchanged, + int update_children, + int to) { #if HAVE_PYTHON - /* FIXME: we *might* want to provide this functionality as - a standalone function, so that other interested parties - than varobj code can benefit for this. */ struct cleanup *back_to; PyObject *children; - PyObject *iterator; int i; - int children_changed = 0; PyObject *printer = var->pretty_printer; back_to = varobj_ensure_python_env (var); @@ -862,87 +975,103 @@ update_dynamic_varobj_children (struct varobj *var, return 0; } - children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, - NULL); - - if (!children) + if (update_children || !var->child_iter) { - gdbpy_print_stack (); - error (_("Null value returned for children")); - } + children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst, + NULL); + + if (!children) + { + gdbpy_print_stack (); + error (_("Null value returned for children")); + } - make_cleanup_py_decref (children); + make_cleanup_py_decref (children); - if (!PyIter_Check (children)) - error (_("Returned value is not iterable")); + if (!PyIter_Check (children)) + error (_("Returned value is not iterable")); - iterator = PyObject_GetIter (children); - if (!iterator) - { - gdbpy_print_stack (); - error (_("Could not get children iterator")); + Py_XDECREF (var->child_iter); + var->child_iter = PyObject_GetIter (children); + if (!var->child_iter) + { + gdbpy_print_stack (); + error (_("Could not get children iterator")); + } + + Py_XDECREF (var->saved_item); + var->saved_item = NULL; + + i = 0; } - make_cleanup_py_decref (iterator); + else + i = VEC_length (varobj_p, var->children); - for (i = 0; ; ++i) + /* We ask for one extra child, so that MI can report whether there + are more children. */ + for (; to < 0 || i < to + 1; ++i) { - PyObject *item = PyIter_Next (iterator); - PyObject *py_v; - struct value *v; - char *name; - struct cleanup *inner; - + PyObject *item; + + /* See if there was a leftover from last time. */ + if (var->saved_item) + { + item = var->saved_item; + var->saved_item = NULL; + } + else + item = PyIter_Next (var->child_iter); + if (!item) break; - inner = make_cleanup_py_decref (item); - if (!PyArg_ParseTuple (item, "sO", &name, &py_v)) - error (_("Invalid item from the child list")); - - v = convert_value_from_python (py_v); + /* We don't want to push the extra child on any report list. */ + if (to < 0 || i < to) + { + PyObject *py_v; + char *name; + struct value *v; + struct cleanup *inner; - /* TODO: This assume the name of the i-th child never changes. */ + inner = make_cleanup_py_decref (item); - /* Now see what to do here. */ - if (VEC_length (varobj_p, var->children) < i + 1) - { - /* There's no child yet. */ - struct varobj *child = varobj_add_child (var, name, v); - if (new_and_unchanged) - VEC_safe_push (varobj_p, *new_and_unchanged, child); - children_changed = 1; + if (!PyArg_ParseTuple (item, "sO", &name, &py_v)) + error (_("Invalid item from the child list")); + + v = convert_value_from_python (py_v); + install_dynamic_child (var, changed, new, + cchanged, i, name, v); + do_cleanups (inner); } - else + else { - varobj_p existing = VEC_index (varobj_p, var->children, i); - if (install_new_value (existing, v, 0) && changed) - { - if (changed) - VEC_safe_push (varobj_p, *changed, existing); - } - else - { - if (new_and_unchanged) - VEC_safe_push (varobj_p, *new_and_unchanged, existing); - } - } + Py_XDECREF (var->saved_item); + var->saved_item = item; - do_cleanups (inner); + /* We want to truncate the child list just before this + element. */ + break; + } } if (i < VEC_length (varobj_p, var->children)) { - int i; - children_changed = 1; - for (i = 0; i < VEC_length (varobj_p, var->children); ++i) - varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0); + int j; + *cchanged = 1; + for (j = i; j < VEC_length (varobj_p, var->children); ++j) + varobj_delete (VEC_index (varobj_p, var->children, j), NULL, 0); + VEC_truncate (varobj_p, var->children, i); } - VEC_truncate (varobj_p, var->children, i); + + /* If there are fewer children than requested, note that the list of + children changed. */ + if (to >= 0 && VEC_length (varobj_p, var->children) < to) + *cchanged = 1; + var->num_children = VEC_length (varobj_p, var->children); do_cleanups (back_to); - *cchanged = children_changed; return 1; #else gdb_assert (0 && "should never be called if Python is not enabled"); @@ -954,20 +1083,26 @@ varobj_get_num_children (struct varobj *var) { if (var->num_children == -1) { - int changed; - if (!var->pretty_printer - || !update_dynamic_varobj_children (var, NULL, NULL, &changed)) + if (var->pretty_printer) + { + int dummy; + + /* If we have a dynamic varobj, don't report -1 children. + So, try to fetch some children first. */ + update_dynamic_varobj_children (var, NULL, NULL, &dummy, 0, 0); + } + else var->num_children = number_of_children (var); } - return var->num_children; + return var->num_children >= 0 ? var->num_children : 0; } /* Creates a list of the immediate children of a variable object; the return code is the number of such children or -1 on error */ VEC (varobj_p)* -varobj_list_children (struct varobj *var) +varobj_list_children (struct varobj *var, int *from, int *to) { struct varobj *child; char *name; @@ -975,12 +1110,16 @@ varobj_list_children (struct varobj *var) var->children_requested = 1; - if (var->pretty_printer + if (var->pretty_printer) + { /* This, in theory, can result in the number of children changing without frontend noticing. But well, calling -var-list-children on the same varobj twice is not something a sane frontend would do. */ - && update_dynamic_varobj_children (var, NULL, NULL, &children_changed)) - return var->children; + update_dynamic_varobj_children (var, NULL, NULL, &children_changed, + 0, *to); + restrict_range (var->children, from, to); + return var->children; + } if (var->num_children == -1) var->num_children = number_of_children (var); @@ -1006,10 +1145,10 @@ varobj_list_children (struct varobj *var) name = name_of_child (var, i); existing = create_child (var, i, name); VEC_replace (varobj_p, var->children, i, existing); - install_default_visualizer (existing); } } + restrict_range (var->children, from, to); return var->children; } @@ -1020,7 +1159,6 @@ varobj_add_child (struct varobj *var, const char *name, struct value *value) VEC_length (varobj_p, var->children), name, value); VEC_safe_push (varobj_p, var->children, v); - install_default_visualizer (v); return v; } @@ -1082,6 +1220,12 @@ varobj_get_attributes (struct varobj *var) return attributes; } +int +varobj_pretty_printed_p (struct varobj *var) +{ + return var->pretty_printer != NULL; +} + char * varobj_get_formatted_value (struct varobj *var, enum varobj_display_formats format) @@ -1159,6 +1303,116 @@ varobj_set_value (struct varobj *var, char *expression) return 1; } +#if HAVE_PYTHON + +/* A helper function to install a constructor function and visualizer + in a varobj. */ + +static void +install_visualizer (struct varobj *var, PyObject *constructor, + PyObject *visualizer) +{ + Py_XDECREF (var->constructor); + var->constructor = constructor; + + Py_XDECREF (var->pretty_printer); + var->pretty_printer = visualizer; + + Py_XDECREF (var->child_iter); + var->child_iter = NULL; +} + +/* Install the default visualizer for VAR. */ + +static void +install_default_visualizer (struct varobj *var) +{ + if (pretty_printing) + { + PyObject *pretty_printer = NULL; + + if (var->value) + { + pretty_printer = gdbpy_get_varobj_pretty_printer (var->value); + if (! pretty_printer) + { + gdbpy_print_stack (); + error (_("Cannot instantiate printer for default visualizer")); + } + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + + install_visualizer (var, NULL, pretty_printer); + } +} + +/* Instantiate and install a visualizer for VAR using CONSTRUCTOR to + make a new object. */ + +static void +construct_visualizer (struct varobj *var, PyObject *constructor) +{ + PyObject *pretty_printer; + + Py_INCREF (constructor); + if (constructor == Py_None) + pretty_printer = NULL; + else + { + pretty_printer = instantiate_pretty_printer (constructor, var->value); + if (! pretty_printer) + { + gdbpy_print_stack (); + Py_DECREF (constructor); + constructor = Py_None; + Py_INCREF (constructor); + } + + if (pretty_printer == Py_None) + { + Py_DECREF (pretty_printer); + pretty_printer = NULL; + } + } + + install_visualizer (var, constructor, pretty_printer); +} + +#endif /* HAVE_PYTHON */ + +/* A helper function for install_new_value. This creates and installs + a visualizer for VAR, if appropriate. */ + +static void +install_new_value_visualizer (struct varobj *var) +{ +#if HAVE_PYTHON + /* If the constructor is None, then we want the raw value. If VAR + does not have a value, just skip this. */ + if (var->constructor != Py_None && var->value) + { + struct cleanup *cleanup; + PyObject *pretty_printer = NULL; + + cleanup = varobj_ensure_python_env (var); + + if (!var->constructor) + install_default_visualizer (var); + else + construct_visualizer (var, var->constructor); + + do_cleanups (cleanup); + } +#else + /* Do nothing. */ +#endif +} + /* Assign a new value to a variable object. If INITIAL is non-zero, this is the first assignement after the variable object was just created, or changed type. In that case, just assign the value @@ -1199,10 +1453,7 @@ install_new_value (struct varobj *var, struct value *value, int initial) that in C++ a reference is not rebindable, it cannot meaningfully change. So, get hold of the real value. */ if (value) - { - value = coerce_ref (value); - release_value (value); - } + value = coerce_ref (value); if (var->type && TYPE_CODE (var->type) == TYPE_CODE_UNION) /* For unions, we need to fetch the value implicitly because @@ -1249,7 +1500,7 @@ install_new_value (struct varobj *var, struct value *value, int initial) values. Don't get string rendering if the value is lazy -- if it is, the code above has decided that the value should not be fetched. */ - if (value && !value_lazy (value)) + if (value && !value_lazy (value) && !var->pretty_printer) print_value = value_get_print_value (value, var->format, var); /* If the type is changeable, compare the old and the new values. @@ -1265,7 +1516,7 @@ install_new_value (struct varobj *var, struct value *value, int initial) { changed = 1; } - else + else if (! var->pretty_printer) { /* Try to compare the values. That requires that both values are non-lazy. */ @@ -1310,74 +1561,53 @@ install_new_value (struct varobj *var, struct value *value, int initial) if (var->value != NULL && var->value != value) value_free (var->value); var->value = value; - if (var->print_value) - xfree (var->print_value); - var->print_value = print_value; + if (value != NULL) + value_incref (value); if (value && value_lazy (value) && intentionally_not_fetched) var->not_fetched = 1; else var->not_fetched = 0; var->updated = 0; + install_new_value_visualizer (var); + + /* If we installed a pretty-printer, re-compare the printed version + to see if the variable changed. */ + if (var->pretty_printer) + { + xfree (print_value); + print_value = value_get_print_value (var->value, var->format, var); + if (!var->print_value || strcmp (var->print_value, print_value) != 0) + changed = 1; + } + if (var->print_value) + xfree (var->print_value); + var->print_value = print_value; + gdb_assert (!var->value || value_type (var->value)); return changed; } -static void -install_visualizer (struct varobj *var, PyObject *visualizer) +/* Return the requested range for a varobj. VAR is the varobj. FROM + and TO are out parameters; *FROM and *TO will be set to the + selected sub-range of VAR. If no range was selected using + -var-set-update-range, then both will be -1. */ +void +varobj_get_child_range (struct varobj *var, int *from, int *to) { -#if HAVE_PYTHON - /* If there are any children now, wipe them. */ - varobj_delete (var, NULL, 1 /* children only */); - var->num_children = -1; - - Py_XDECREF (var->pretty_printer); - var->pretty_printer = visualizer; - - install_new_value (var, var->value, 1); - - /* If we removed the visualizer, and the user ever requested the - object's children, then we must compute the list of children. - Note that we needn't do this when installing a visualizer, - because updating will recompute dynamic children. */ - if (!visualizer && var->children_requested) - varobj_list_children (var); -#else - error (_("Python support required")); -#endif + *from = var->from; + *to = var->to; } -static void -install_default_visualizer (struct varobj *var) +/* Set the selected sub-range of children of VAR to start at index + FROM and end at index TO. If either FROM or TO is less than zero, + this is interpreted as a request for all children. */ +void +varobj_set_child_range (struct varobj *var, int from, int to) { -#if HAVE_PYTHON - struct cleanup *cleanup; - PyObject *pretty_printer = NULL; - - cleanup = varobj_ensure_python_env (var); - - if (var->value) - { - pretty_printer = gdbpy_get_varobj_pretty_printer (var->value); - if (! pretty_printer) - { - gdbpy_print_stack (); - error (_("Cannot instantiate printer for default visualizer")); - } - } - - if (pretty_printer == Py_None) - { - Py_DECREF (pretty_printer); - pretty_printer = NULL; - } - - install_visualizer (var, pretty_printer); - do_cleanups (cleanup); -#else - /* No error is right as this function is inserted just as a hook. */ -#endif + var->from = from; + var->to = to; } void @@ -1395,31 +1625,19 @@ varobj_set_visualizer (struct varobj *var, const char *visualizer) make_cleanup_py_decref (globals); constructor = PyRun_String (visualizer, Py_eval_input, globals, globals); - - /* Do not instantiate NoneType. */ - if (constructor == Py_None) - { - pretty_printer = Py_None; - Py_INCREF (pretty_printer); - } - else - pretty_printer = instantiate_pretty_printer (constructor, var->value); - - Py_XDECREF (constructor); - if (! pretty_printer) + if (! constructor) { gdbpy_print_stack (); error (_("Could not evaluate visualizer expression: %s"), visualizer); } - if (pretty_printer == Py_None) - { - Py_DECREF (pretty_printer); - pretty_printer = NULL; - } + construct_visualizer (var, constructor); + Py_XDECREF (constructor); - install_visualizer (var, pretty_printer); + /* If there are any children now, wipe them. */ + varobj_delete (var, NULL, 1 /* children only */); + var->num_children = -1; do_cleanups (back_to); #else @@ -1530,44 +1748,63 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit) /* We probably should not get children of a varobj that has a pretty-printer, but for which -var-list-children was never - invoked. Presumably, such varobj is not yet expanded in the - UI, so we need not bother getting it. */ + invoked. */ if (v->pretty_printer) { - VEC (varobj_p) *changed = 0, *new_and_unchanged = 0; + VEC (varobj_p) *changed = 0, *new = 0; int i, children_changed; varobj_p tmp; - if (!v->children_requested) - continue; - if (v->frozen) continue; + if (!v->children_requested) + { + int dummy; + + /* If we initially did not have potential children, but + now we do, consider the varobj as changed. + Otherwise, if children were never requested, consider + it as unchanged -- presumably, such varobj is not yet + expanded in the UI, so we need not bother getting + it. */ + if (!varobj_has_more (v, 0)) + { + update_dynamic_varobj_children (v, NULL, NULL, &dummy, 0, 0); + if (varobj_has_more (v, 0)) + r.changed = 1; + } + + if (r.changed) + VEC_safe_push (varobj_update_result, result, &r); + + continue; + } + /* If update_dynamic_varobj_children returns 0, then we have a non-conforming pretty-printer, so we skip it. */ - if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged, - &children_changed)) + if (update_dynamic_varobj_children (v, &changed, &new, + &children_changed, 1, v->to)) { - if (children_changed) - r.children_changed = 1; - for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i) + if (children_changed || new) { - varobj_update_result r = {tmp}; - r.changed = 1; - r.value_installed = 1; - VEC_safe_push (varobj_update_result, stack, &r); + r.children_changed = 1; + r.new = new; } - for (i = 0; - VEC_iterate (varobj_p, new_and_unchanged, i, tmp); - ++i) + for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i) { varobj_update_result r = {tmp}; + r.changed = 1; r.value_installed = 1; VEC_safe_push (varobj_update_result, stack, &r); } if (r.changed || r.children_changed) VEC_safe_push (varobj_update_result, result, &r); + + /* Free CHANGED, but not NEW, because NEW has been put + into the result vector. */ + VEC_free (varobj_p, changed); + continue; } } @@ -1855,7 +2092,12 @@ new_variable (void) var->frozen = 0; var->not_fetched = 0; var->children_requested = 0; + var->from = -1; + var->to = -1; + var->constructor = 0; var->pretty_printer = 0; + var->child_iter = 0; + var->saved_item = 0; return var; } @@ -1885,7 +2127,10 @@ free_variable (struct varobj *var) if (var->pretty_printer) { struct cleanup *cleanup = varobj_ensure_python_env (var); - Py_DECREF (var->pretty_printer); + Py_XDECREF (var->constructor); + Py_XDECREF (var->pretty_printer); + Py_XDECREF (var->child_iter); + Py_XDECREF (var->saved_item); do_cleanups (cleanup); } #endif @@ -1918,6 +2163,18 @@ make_cleanup_free_variable (struct varobj *var) return make_cleanup (do_free_variable_cleanup, var); } +static void +do_uninstall_variable_cleanup (void *var) +{ + uninstall_variable (var); +} + +static struct cleanup * +make_cleanup_uninstall_variable (struct varobj *var) +{ + return make_cleanup (do_uninstall_variable_cleanup, var); +} + /* This returns the type of the variable. It also skips past typedefs to return the real type of the variable. @@ -2132,6 +2389,8 @@ value_of_root (struct varobj **var_handle, int *type_changed) else { tmp_var->obj_name = xstrdup (var->obj_name); + tmp_var->from = var->from; + tmp_var->to = var->to; varobj_delete (var, NULL, 0); install_variable (tmp_var); @@ -2166,7 +2425,11 @@ static char * my_value_of_variable (struct varobj *var, enum varobj_display_formats format) { if (var->root->is_valid) - return (*var->root->lang->value_of_variable) (var, format); + { + if (var->pretty_printer) + return value_get_print_value (var->value, var->format, var); + return (*var->root->lang->value_of_variable) (var, format); + } else return NULL; } @@ -2189,43 +2452,51 @@ value_get_print_value (struct value *value, enum varobj_display_formats format, struct cleanup *back_to = varobj_ensure_python_env (var); PyObject *value_formatter = var->pretty_printer; - if (value_formatter && PyObject_HasAttr (value_formatter, - gdbpy_to_string_cst)) + if (value_formatter) { - char *hint; - struct value *replacement; - int string_print = 0; - PyObject *output = NULL; + /* First check to see if we have any children at all. If so, + we simply return {...}. */ + if (dynamic_varobj_has_child_method (var)) + return xstrdup ("{...}"); - hint = gdbpy_get_display_hint (value_formatter); - if (hint) + if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst)) { - if (!strcmp (hint, "string")) - string_print = 1; - xfree (hint); - } + char *hint; + struct value *replacement; + int string_print = 0; + PyObject *output = NULL; + + hint = gdbpy_get_display_hint (value_formatter); + if (hint) + { + if (!strcmp (hint, "string")) + string_print = 1; + xfree (hint); + } - output = apply_varobj_pretty_printer (value_formatter, - &replacement); - if (output) - { - PyObject *py_str = python_string_to_target_python_string (output); - if (py_str) - { - char *s = PyString_AsString (py_str); - len = PyString_Size (py_str); - thevalue = xmemdup (s, len + 1, len + 1); - Py_DECREF (py_str); + output = apply_varobj_pretty_printer (value_formatter, + &replacement); + if (output) + { + PyObject *py_str + = python_string_to_target_python_string (output); + if (py_str) + { + char *s = PyString_AsString (py_str); + len = PyString_Size (py_str); + thevalue = xmemdup (s, len + 1, len + 1); + Py_DECREF (py_str); + } + Py_DECREF (output); } - Py_DECREF (output); - } - if (thevalue && !string_print) - { - do_cleanups (back_to); - return thevalue; + if (thevalue && !string_print) + { + do_cleanups (back_to); + return thevalue; + } + if (replacement) + value = replacement; } - if (replacement) - value = replacement; } do_cleanups (back_to); } @@ -2954,10 +3225,7 @@ cplus_describe_child (struct varobj *parent, int index, *cname = xstrdup (TYPE_FIELD_NAME (type, index)); if (cvalue && value) - { - *cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value); - release_value (*cvalue); - } + *cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value); if (ctype) { @@ -3163,6 +3431,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. */ @@ -3180,6 +3461,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/varobj.h b/gdb/varobj.h index 7297243..f43c593 100644 --- a/gdb/varobj.h +++ b/gdb/varobj.h @@ -78,6 +78,12 @@ typedef struct varobj_update_result_t new value of varobj is already computed and installed, or has to be yet installed. Don't use this outside varobj.c */ int value_installed; + + /* This will be non-NULL when new children were added to the varobj. + It lists the new children (which must necessarily come at the end + of the child list) added during an update. The caller is + responsible for freeing this vector. */ + VEC (varobj_p) *new; } varobj_update_result; DEF_VEC_O (varobj_update_result); @@ -112,13 +118,24 @@ extern void varobj_set_frozen (struct varobj *var, int frozen); extern int varobj_get_frozen (struct varobj *var); +extern void varobj_get_child_range (struct varobj *var, int *from, int *to); + +extern void varobj_set_child_range (struct varobj *var, int from, int to); + extern char *varobj_get_display_hint (struct varobj *var); extern int varobj_get_num_children (struct varobj *var); -/* Return the list of children of VAR. The returned vector - should not be modified in any way. */ -extern VEC (varobj_p)* varobj_list_children (struct varobj *var); +/* Return the list of children of VAR. The returned vector should not + be modified in any way. FROM and TO are in/out parameters + indicating the range of children to return. If either *FROM or *TO + is less than zero on entry, then all children will be returned. On + return, *FROM and *TO will be updated to indicate the real range + that was returned. The resulting VEC will contain at least the + children from *FROM to just before *TO; it might contain more + children, depending on whether any more were available. */ +extern VEC (varobj_p)* varobj_list_children (struct varobj *var, + int *from, int *to); extern char *varobj_get_type (struct varobj *var); @@ -149,6 +166,13 @@ extern int varobj_editable_p (struct varobj *var); extern int varobj_floating_p (struct varobj *var); -extern void varobj_set_visualizer (struct varobj *var, const char *visualizer); +extern void +varobj_set_visualizer (struct varobj *var, const char *visualizer); + +extern void varobj_enable_pretty_printing (void); + +extern int varobj_has_more (struct varobj *var, int to); + +extern int varobj_pretty_printed_p (struct varobj *var); #endif /* VAROBJ_H */ diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index c56ab86..dacf913 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -3038,6 +3038,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