http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: commit ccde1530479cc966374351038057b9dda90aa251 branch `archer' - the merge of branches: archer-tromey-delayed-symfile archer-tromey-python archer-pmuldoon-next-over-throw archer-jankratochvil-fortran-module archer-jankratochvil-watchpoint archer-jankratochvil-vla archer-keiths-expr-cumulative diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ff8b86e..f450a7b 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -167,6 +167,12 @@ TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@ TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@ # Did the user give us a --with-gdb-datadir option? +GDB_DATADIR_PATH = @GDB_DATADIR_PATH@ + +# The argument to --with-pythondir. If not given, this is +# GDB_DATADIR_PATH/python. +pythondir = @pythondir@ + GDB_DATADIR = @GDB_DATADIR@ # Helper code from gnulib. @@ -267,23 +273,39 @@ SUBDIR_TUI_CFLAGS= \ # SUBDIR_PYTHON_OBS = \ python.o \ + py-block.o \ + py-breakpoint.o \ py-cmd.o \ py-frame.o \ py-function.o \ + py-hooks.o \ + py-inferior.o \ + py-infthread.o \ py-lazy-string.o \ py-objfile.o \ + py-param.o \ py-prettyprint.o \ + py-symbol.o \ + py-symtab.o \ py-type.o \ py-utils.o \ py-value.o SUBDIR_PYTHON_SRCS = \ python/python.c \ + python/py-block.c \ + python/py-breakpoint.c \ python/py-cmd.c \ python/py-frame.c \ python/py-function.c \ + python/py-hooks.c \ + python/py-inferior.c \ + python/py-infthread.c \ python/py-lazy-string.c \ python/py-objfile.c \ + python/py-param.c \ python/py-prettyprint.c \ + python/py-symbol.c \ + python/py-symtab.c \ python/py-type.c \ python/py-utils.c \ python/py-value.c @@ -756,7 +778,8 @@ config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \ -gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h +gdb_usleep.h jit.h python/python.h python/python-internal.h \ +xml-syscall.h ada-operator.inc microblaze-tdep.h # Header files that already have srcdir in them, or which are in objdir. @@ -1270,6 +1293,12 @@ stamp-h: $(srcdir)/config.in config.status CONFIG_LINKS= \ $(SHELL) config.status +.gdbinit: $(srcdir)/gdbinit.in config.status + CONFIG_FILES=".gdbinit:gdbinit.in" \ + CONFIG_COMMANDS= \ + CONFIG_HEADERS= \ + $(SHELL) config.status + config.status: $(srcdir)/configure configure.tgt configure.host $(SHELL) config.status --recheck @@ -1970,6 +1999,14 @@ python.o: $(srcdir)/python/python.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c $(POSTCOMPILE) +py-block.o: $(srcdir)/python/py-block.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-block.c + $(POSTCOMPILE) + +py-breakpoint.o: $(srcdir)/python/py-breakpoint.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c + $(POSTCOMPILE) + py-cmd.o: $(srcdir)/python/py-cmd.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c $(POSTCOMPILE) @@ -1982,6 +2019,18 @@ py-function.o: $(srcdir)/python/py-function.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c $(POSTCOMPILE) +py-hooks.o: $(srcdir)/python/py-hooks.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-hooks.c + $(POSTCOMPILE) + +py-inferior.o: $(srcdir)/python/py-inferior.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-inferior.c + $(POSTCOMPILE) + +py-infthread.o: $(srcdir)/python/py-infthread.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-infthread.c + $(POSTCOMPILE) + py-lazy-string.o: $(srcdir)/python/py-lazy-string.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-lazy-string.c $(POSTCOMPILE) @@ -1990,10 +2039,22 @@ py-objfile.o: $(srcdir)/python/py-objfile.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-objfile.c $(POSTCOMPILE) +py-param.o: $(srcdir)/python/py-param.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-param.c + $(POSTCOMPILE) + py-prettyprint.o: $(srcdir)/python/py-prettyprint.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-prettyprint.c $(POSTCOMPILE) +py-symbol.o: $(srcdir)/python/py-symbol.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symbol.c + $(POSTCOMPILE) + +py-symtab.o: $(srcdir)/python/py-symtab.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-symtab.c + $(POSTCOMPILE) + py-type.o: $(srcdir)/python/py-type.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-type.c $(POSTCOMPILE) @@ -2006,6 +2067,36 @@ py-value.o: $(srcdir)/python/py-value.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-value.c $(POSTCOMPILE) +# All python library files, with the "python/lib" stripped off. +# Note that we should only install files in the "gdb" module. +PY_FILES = gdb/FrameIterator.py gdb/FrameWrapper.py gdb/command/alias.py \ + gdb/command/backtrace.py gdb/command/require.py \ + gdb/command/pahole.py gdb/command/upto.py gdb/command/__init__.py \ + gdb/command/ignore_errors.py gdb/command/save_breakpoints.py \ + gdb/function/caller_is.py gdb/function/in_scope.py \ + gdb/function/__init__.py gdb/backtrace.py gdb/__init__.py + +# Install the Python library. Python library files go under +# $(pythondir). +install-python: + files='$(PY_FILES)'; for file in $$files; do \ + dir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(pythondir)/$$dir; \ + $(INSTALL_DATA) $(srcdir)/python/lib/$$file $(DESTDIR)$(pythondir)/$$file; \ + done + +# Other packages may have their files installed in $(pythondir). +uninstall-python: + files='$(PY_FILES)'; for file in $$files; do \ + slashdir=`echo "/$$file" | sed 's,/[^/]*$$,,'`; \ + rm -f $(DESTDIR)$(pythondir)/$$file; \ + while test "x$$file" != "x$$slashdir"; do \ + rmdir 2>/dev/null "$(DESTDIR)$(pythondir)$$slashdir"; \ + file="$$slashdir"; \ + slashdir=`echo "$$file" | sed 's,/[^/]*$$,,'`; \ + done \ + done + # # Dependency tracking. Most of this is conditional on GNU Make being # found by configure; if GNU Make is not found, we fall back to a diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 40b70ab..b291d40 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -4781,14 +4781,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); } @@ -10931,6 +10927,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) { @@ -11319,6 +11349,7 @@ parse (void) static const struct exp_descriptor ada_exp_descriptor = { ada_print_subexp, ada_operator_length, + ada_operator_check, ada_op_name, ada_dump_subexp_body, ada_evaluate_subexp diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index 5c9e558..55a1873 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -350,6 +350,20 @@ amd64_linux_dr_unset_status (unsigned long mask) } } +/* See i386_dr_low_type.detach. Do not use wrappers amd64_linux_dr_set_control + or amd64_linux_dr_reset_addr as they would modify the register cache + (amd64_linux_dr). */ + +static void +amd64_linux_dr_detach (void) +{ + int regnum; + + amd64_linux_dr_set (inferior_ptid, DR_CONTROL, 0); + amd64_linux_dr_unset_status (~0UL); + for (regnum = DR_FIRSTADDR; regnum <= DR_LASTADDR; regnum++) + amd64_linux_dr_set (inferior_ptid, regnum, 0); +} static void amd64_linux_new_thread (ptid_t ptid) @@ -702,6 +716,7 @@ _initialize_amd64_linux_nat (void) i386_dr_low.reset_addr = amd64_linux_dr_reset_addr; i386_dr_low.get_status = amd64_linux_dr_get_status; i386_dr_low.unset_status = amd64_linux_dr_unset_status; + i386_dr_low.detach = amd64_linux_dr_detach; i386_set_debug_register_length (8); /* Override the GNU/Linux inferior startup hook. */ diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c index 5776bb0..6099e99 100644 --- a/gdb/ax-gdb.c +++ b/gdb/ax-gdb.c @@ -1810,7 +1810,7 @@ gen_expr (struct expression *exp, union exp_element **pc, /* 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, this_name, NULL, VAR_DOMAIN); + sym = lookup_block_symbol (b, this_name, VAR_DOMAIN); if (!sym) error (_("no `%s' found"), this_name); diff --git a/gdb/block.c b/gdb/block.c index 48ac21b..0eccecb 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -227,8 +227,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) @@ -318,6 +319,25 @@ allocate_block (struct obstack *obstack) BLOCK_SUPERBLOCK (bl) = NULL; BLOCK_DICT (bl) = NULL; BLOCK_NAMESPACE (bl) = NULL; + BLOCK_FORTRAN_USE (bl) = NULL; return bl; } + +/* Return OBJFILE in which BLOCK is located or NULL if we cannot find it for + whatever reason. */ + +struct objfile * +block_objfile (const struct block *block) +{ + struct symbol *func; + + if (block == NULL) + return NULL; + + func = block_linkage_function (block); + if (func == NULL) + return NULL; + + return SYMBOL_SYMTAB (func)->objfile; +} diff --git a/gdb/block.h b/gdb/block.h index 7eedb6c..b147826 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -96,6 +96,15 @@ struct block cplus_specific; } language_specific; + + /* FIXME: It should be in the LANGUAGE_SPECIFIC region but the + BLOCK_NAMESPACE accessor is not protected by the C language check. */ + + struct + { + struct fortran_using *use; + } + fortran_specific; }; #define BLOCK_START(bl) (bl)->startaddr @@ -104,6 +113,7 @@ struct block #define BLOCK_SUPERBLOCK(bl) (bl)->superblock #define BLOCK_DICT(bl) (bl)->dict #define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace +#define BLOCK_FORTRAN_USE(bl) (bl)->fortran_specific.use /* Macro to loop through all symbols in a block BL, in no particular order. ITER helps keep track of the iteration, and should be a @@ -166,4 +176,6 @@ extern const struct block *block_global_block (const struct block *block); extern struct block *allocate_block (struct obstack *obstack); +extern struct objfile *block_objfile (const struct block *block); + #endif /* BLOCK_H */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index d404ee7..2be397f 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -61,6 +61,7 @@ #include "valprint.h" #include "jit.h" #include "xml-syscall.h" +#include "parser-defs.h" /* readline include files */ #include "readline/readline.h" @@ -614,6 +615,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 @@ -634,42 +682,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; } @@ -1868,6 +1881,36 @@ create_longjmp_master_breakpoint (char *func_name) do_cleanups (old_chain); } +/* Install a master breakpoint on the unwinder's debug hook. */ + +void +create_exception_master_breakpoint (void) +{ + struct objfile *objfile; + + ALL_OBJFILES (objfile) + { + struct minimal_symbol *debug_hook; + + debug_hook = lookup_minimal_symbol_text ("_Unwind_DebugHook", objfile); + if (debug_hook != NULL) + { + CORE_ADDR pc; + struct breakpoint *b; + + pc = find_function_start_pc (get_objfile_arch (objfile), + SYMBOL_VALUE_ADDRESS (debug_hook), + SYMBOL_OBJ_SECTION (debug_hook)); + b = create_internal_breakpoint (get_objfile_arch (objfile), + pc, bp_exception_master); + b->addr_string = xstrdup ("_Unwind_DebugHook"); + b->enable_state = bp_disabled; + } + } + + update_global_location_list (1); +} + void update_breakpoints_after_exec (void) { @@ -1909,7 +1952,7 @@ update_breakpoints_after_exec (void) /* Thread event breakpoints must be set anew after an exec(), as must overlay event and longjmp master breakpoints. */ if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master) + || b->type == bp_longjmp_master || b->type == bp_exception_master) { delete_breakpoint (b); continue; @@ -1924,7 +1967,8 @@ update_breakpoints_after_exec (void) /* Longjmp and longjmp-resume breakpoints are also meaningless after an exec. */ - if (b->type == bp_longjmp || b->type == bp_longjmp_resume) + if (b->type == bp_longjmp || b->type == bp_longjmp_resume + || b->type == bp_exception || b->type == bp_exception_resume) { delete_breakpoint (b); continue; @@ -1985,6 +2029,7 @@ update_breakpoints_after_exec (void) create_longjmp_master_breakpoint ("_longjmp"); create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); + create_exception_master_breakpoint (); } int @@ -2008,6 +2053,7 @@ detach_breakpoints (int pid) if (b->inserted) val |= remove_breakpoint_1 (b, mark_inserted); } + val |= target_detach_watchpoints (); do_cleanups (old_chain); return val; } @@ -2107,12 +2153,14 @@ remove_breakpoint_1 (struct bp_location *b, insertion_state_t is) return val; b->inserted = (is == mark_inserted); } - else if (b->loc_type == bp_loc_hardware_watchpoint) + /* bp_loc_hardware_watchpoint with mark_inserted is being handled by + target_detach_watchpoints. */ + else if (b->loc_type == bp_loc_hardware_watchpoint && is == mark_uninserted) { struct value *v; struct value *n; - b->inserted = (is == mark_inserted); + b->inserted = 0; val = target_remove_watchpoint (b->address, b->length, b->watchpoint_type); @@ -2892,6 +2940,12 @@ print_it_typical (bpstat bs) result = PRINT_NOTHING; break; + case bp_exception_master: + /* These should never be enabled. */ + printf_filtered (_("Exception Master Breakpoint: gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + case bp_watchpoint: case bp_hardware_watchpoint: annotate_watchpoint (b->number); @@ -2979,6 +3033,8 @@ print_it_typical (bpstat bs) case bp_none: case bp_longjmp: case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: @@ -3383,8 +3439,12 @@ bpstat_check_location (const struct bp_location *bl, /* If BS refers to a watchpoint, determine if the watched values has actually changed, and we should stop. If not, set BS->stop - to 0. */ -static void + to 0. + Return 0 for watchpoints which could not be the cause of this trap. + In such case PRINT_IT will be print_it_noop and STOP will be 0. + Otherwise return 1 but in such case it is not guaranteed whether this + breakpoint did or did not trigger this trap. */ +static int bpstat_check_watchpoint (bpstat bs) { const struct bp_location *bl = bs->breakpoint_at; @@ -3473,8 +3533,10 @@ bpstat_check_watchpoint (bpstat bs) anything for this watchpoint. */ bs->print_it = print_it_noop; bs->stop = 0; + return 0; } } + return 1; } @@ -3588,6 +3650,8 @@ bpstat_stop_status (struct address_space *aspace, for (bl = b->loc; bl != NULL; bl = bl->next) { + bpstat bs_prev = bs; + /* For hardware watchpoints, we look only at the first location. The watchpoint_check function will work on entire expression, not the individual locations. For read watchopints, the @@ -3605,6 +3669,7 @@ bpstat_stop_status (struct address_space *aspace, /* Come here if it's a watchpoint, or if the break address matches */ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */ + gdb_assert (bs_prev->next == bs); /* Assume we stop. Should we find watchpoint that is not actually triggered, or if condition of breakpoint is false, we'll reset @@ -3612,12 +3677,22 @@ bpstat_stop_status (struct address_space *aspace, bs->stop = 1; bs->print = 1; - bpstat_check_watchpoint (bs); - if (!bs->stop) - continue; + if (!bpstat_check_watchpoint (bs)) + { + /* Ensure bpstat_explains_signal stays false if this BL could not be + the cause of this trap. */ + + gdb_assert (bs->print_it == print_it_noop); + gdb_assert (!bs->stop); + xfree (bs); + bs = bs_prev; + bs->next = NULL; + continue; + } if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master) + || b->type == bp_longjmp_master + || b->type == bp_exception_master) /* We do not stop for these. */ bs->stop = 0; else @@ -3827,6 +3902,7 @@ bpstat_what (bpstat bs) struct bpstat_what retval; retval.call_dummy = 0; + retval.is_longjmp = 0; for (; bs != NULL; bs = bs->next) { enum class bs_class = no_effect; @@ -3873,10 +3949,15 @@ bpstat_what (bpstat bs) bs_class = no_effect; break; case bp_longjmp: + case bp_exception: bs_class = long_jump; + retval.is_longjmp = bs->breakpoint_at->owner->type == bp_longjmp; break; case bp_longjmp_resume: + case bp_exception_resume: bs_class = long_resume; + retval.is_longjmp + = bs->breakpoint_at->owner->type == bp_longjmp_resume; break; case bp_step_resume: if (bs->stop) @@ -3899,6 +3980,7 @@ bpstat_what (bpstat bs) case bp_thread_event: case bp_overlay_event: case bp_longjmp_master: + case bp_exception_master: bs_class = bp_nostop; break; case bp_catchpoint: @@ -4043,6 +4125,8 @@ print_one_breakpoint_location (struct breakpoint *b, {bp_access_watchpoint, "acc watchpoint"}, {bp_longjmp, "longjmp"}, {bp_longjmp_resume, "longjmp resume"}, + {bp_exception, "exception"}, + {bp_exception_resume, "exception resume"}, {bp_step_resume, "step resume"}, {bp_watchpoint_scope, "watchpoint scope"}, {bp_call_dummy, "call dummy"}, @@ -4050,6 +4134,7 @@ print_one_breakpoint_location (struct breakpoint *b, {bp_thread_event, "thread events"}, {bp_overlay_event, "overlay events"}, {bp_longjmp_master, "longjmp master"}, + {bp_exception_master, "exception master"}, {bp_catchpoint, "catchpoint"}, {bp_tracepoint, "tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"}, @@ -4174,6 +4259,8 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: @@ -4181,6 +4268,7 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_thread_event: case bp_overlay_event: case bp_longjmp_master: + case bp_exception_master: case bp_tracepoint: case bp_fast_tracepoint: case bp_jit_event: @@ -4819,6 +4907,8 @@ allocate_bp_location (struct breakpoint *bpt) case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: @@ -4827,6 +4917,7 @@ allocate_bp_location (struct breakpoint *bpt) case bp_overlay_event: case bp_jit_event: case bp_longjmp_master: + case bp_exception_master: loc->loc_type = bp_loc_software_breakpoint; break; case bp_hardware_breakpoint: @@ -5013,8 +5104,7 @@ make_breakpoint_permanent (struct breakpoint *b) } /* Call this routine when stepping and nexting to enable a breakpoint - if we do a longjmp() in THREAD. When we hit that breakpoint, call - set_longjmp_resume_breakpoint() to figure out where we are going. */ + if we do a longjmp() or 'throw' in THREAD. */ void set_longjmp_breakpoint (int thread) @@ -5027,10 +5117,11 @@ set_longjmp_breakpoint (int thread) clones of those and enable them for the requested thread. */ ALL_BREAKPOINTS_SAFE (b, temp) if (b->pspace == current_program_space - && b->type == bp_longjmp_master) + && (b->type == bp_longjmp_master + || b->type == bp_exception_master)) { struct breakpoint *clone = clone_momentary_breakpoint (b); - clone->type = bp_longjmp; + clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception; clone->thread = thread; } } @@ -5042,7 +5133,7 @@ delete_longjmp_breakpoint (int thread) struct breakpoint *b, *temp; ALL_BREAKPOINTS_SAFE (b, temp) - if (b->type == bp_longjmp) + if (b->type == bp_longjmp || b->type == bp_exception) { if (b->thread == thread) delete_breakpoint (b); @@ -6117,6 +6208,8 @@ mention (struct breakpoint *b) case bp_finish: case bp_longjmp: case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: case bp_step_resume: case bp_call_dummy: case bp_watchpoint_scope: @@ -6125,6 +6218,7 @@ mention (struct breakpoint *b) case bp_overlay_event: case bp_jit_event: case bp_longjmp_master: + case bp_exception_master: break; } @@ -7509,6 +7603,7 @@ struct until_break_command_continuation_args { struct breakpoint *breakpoint; struct breakpoint *breakpoint2; + int thread_num; }; /* This function is called by fetch_inferior_event via the @@ -7523,6 +7618,7 @@ until_break_command_continuation (void *arg) delete_breakpoint (a->breakpoint); if (a->breakpoint2) delete_breakpoint (a->breakpoint2); + delete_longjmp_breakpoint (a->thread_num); } void @@ -7534,6 +7630,8 @@ until_break_command (char *arg, int from_tty, int anywhere) struct breakpoint *breakpoint; struct breakpoint *breakpoint2 = NULL; struct cleanup *old_chain; + int thread; + struct thread_info *tp; clear_proceed_status (); @@ -7572,6 +7670,9 @@ until_break_command (char *arg, int from_tty, int anywhere) old_chain = make_cleanup_delete_breakpoint (breakpoint); + tp = inferior_thread (); + thread = tp->num; + /* Keep within the current frame, or in frames called by the current one. */ @@ -7584,6 +7685,10 @@ until_break_command (char *arg, int from_tty, int anywhere) frame_unwind_caller_id (frame), bp_until); make_cleanup_delete_breakpoint (breakpoint2); + + set_longjmp_breakpoint (thread); + tp->initiating_frame = frame_unwind_caller_id (frame); + make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } proceed (-1, TARGET_SIGNAL_DEFAULT, 0); @@ -7600,6 +7705,7 @@ until_break_command (char *arg, int from_tty, int anywhere) args->breakpoint = breakpoint; args->breakpoint2 = breakpoint2; + args->thread_num = thread; discard_cleanups (old_chain); add_continuation (inferior_thread (), @@ -8785,6 +8891,7 @@ delete_command (char *arg, int from_tty) && b->type != bp_thread_event && b->type != bp_overlay_event && b->type != bp_longjmp_master + && b->type != bp_exception_master && b->number >= 0) { breaks_to_delete = 1; @@ -8804,6 +8911,7 @@ delete_command (char *arg, int from_tty) && b->type != bp_jit_event && b->type != bp_overlay_event && b->type != bp_longjmp_master + && b->type != bp_exception_master && b->number >= 0) delete_breakpoint (b); } @@ -9114,6 +9222,7 @@ breakpoint_re_set_one (void *bint) reset later by breakpoint_re_set. */ case bp_overlay_event: case bp_longjmp_master: + case bp_exception_master: delete_breakpoint (b); break; @@ -9136,6 +9245,8 @@ breakpoint_re_set_one (void *bint) case bp_step_resume: case bp_longjmp: case bp_longjmp_resume: + case bp_exception: + case bp_exception_resume: case bp_jit_event: break; } @@ -9178,6 +9289,7 @@ breakpoint_re_set (void) create_longjmp_master_breakpoint ("_longjmp"); create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); + create_exception_master_breakpoint (); } /* Reset the thread number of this breakpoint: @@ -10173,6 +10285,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. @@ -10717,4 +10845,5 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."), automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); + observer_attach_mark_used (breakpoint_types_mark_used); } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 6b373a3..59aa412 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -56,6 +56,13 @@ enum bptype bp_longjmp, /* secret breakpoint to find longjmp() */ bp_longjmp_resume, /* secret breakpoint to escape longjmp() */ + /* An internal breakpoint that is installed on the unwinder's + debug hook. */ + bp_exception, + /* An internal breakpoint that is set at the point where an + exception will land. */ + bp_exception_resume, + /* Used by wait_for_inferior for stepping over subroutine calls, for stepping over signal handlers, and for skipping prologues. */ bp_step_resume, @@ -118,6 +125,9 @@ enum bptype bp_longjmp_master, + /* Like bp_longjmp_master, but for exceptions. */ + bp_exception_master, + bp_catchpoint, bp_tracepoint, @@ -603,6 +613,10 @@ struct bpstat_what continuing from a call dummy without popping the frame is not a useful one). */ int call_dummy; + + /* Used for BPSTAT_WHAT_SET_LONGJMP_RESUME. True if we are + handling a longjmp, false if we are handling an exception. */ + int is_longjmp; }; /* The possible return values for print_bpstat, print_it_normal, @@ -985,6 +999,9 @@ extern int catching_syscall_number (int syscall_number); /* Tell a breakpoint to be quiet. */ extern void make_breakpoint_silent (struct breakpoint *); +/* Set break condition of breakpoint B to EXP. */ +extern void set_breakpoint_condition (struct breakpoint *b, char *exp, int from_tty); + /* Return a tracepoint with the given number if found. */ extern struct breakpoint *get_tracepoint (int num); diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 8e00979..92efb39 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -418,6 +418,24 @@ exp : exp '(' nonempty_typelist ')' const_or_volatile } ; +/* +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; } ; @@ -785,12 +803,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); @@ -2033,6 +2052,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; @@ -2041,9 +2067,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 ()) { @@ -2079,10 +2115,19 @@ yylex (void) && parse_language->la_language != language_cplus) break; + 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; } @@ -2111,6 +2156,8 @@ yylex (void) return 0; case ' ': + name_prefix_len++; + terminate_prefix = 0; case '\t': case '\n': lexptr++; @@ -2268,11 +2315,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'. */ @@ -2357,14 +2406,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). */ @@ -2423,6 +2487,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 d620881..34cb34a 100644 --- a/gdb/c-lang.c +++ b/gdb/c-lang.c @@ -1140,6 +1140,7 @@ static const struct exp_descriptor exp_descriptor_c = { print_subexp_standard, operator_length_standard, + operator_check_standard, op_name_standard, dump_subexp_body_standard, evaluate_subexp_c diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index d1af481..96b0705 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, @@ -197,6 +196,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"); + } } @@ -353,10 +369,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; @@ -368,13 +388,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; } @@ -558,7 +584,12 @@ c_type_print_varspec_suffix (struct type *type, struct ui_file *stream, fprintf_filtered (stream, ")"); fprintf_filtered (stream, "["); - if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 + if (TYPE_ARRAY_UPPER_BOUND_IS_DWARF_BLOCK (type)) + { + /* No _() - printed sources should not be locale dependent. */ + fprintf_filtered (stream, "variable"); + } + else if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 && !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) fprintf_filtered (stream, "%d", (TYPE_LENGTH (type) @@ -591,7 +622,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/coffread.c b/gdb/coffread.c index 8e5dca9..7e7fb8b 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -2123,6 +2123,7 @@ static struct sym_fns coff_sym_fns = coff_new_init, /* sym_new_init: init anything gbl to entire symtab */ coff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ coff_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ coff_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: xlate external to internal form */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/config.in b/gdb/config.in index ebde876..907b275 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -46,11 +46,10 @@ language is requested. */ #undef ENABLE_NLS -/* look for global separate data files in this path [DATADIR/gdb] */ +/* Global directory for GDB data files. */ #undef GDB_DATADIR -/* Define if the gdb-datadir directory should be relocated when GDB is moved. - */ +/* Define if GDB datadir should be relocated when GDB is moved. */ #undef GDB_DATADIR_RELOCATABLE /* Define to be a string naming the default host character set. */ @@ -653,6 +652,9 @@ 'ptrdiff_t'. */ #undef PTRDIFF_T_SUFFIX +/* Define to install path for Python sources */ +#undef PYTHONDIR + /* Relocated directory for source files. */ #undef RELOC_SRCDIR diff --git a/gdb/configure b/gdb/configure index 4980106..be69488 100755 --- a/gdb/configure +++ b/gdb/configure @@ -676,6 +676,8 @@ REPORT_BUGS_TO PKGVERSION TARGET_OBS subdirs +pythondir +GDB_DATADIR_PATH GDB_DATADIR DEBUGDIR am__fastdepCC_FALSE @@ -885,6 +887,7 @@ enable_dependency_tracking with_separate_debug_dir with_gdb_datadir with_relocated_sources +with_pythondir enable_targets enable_64_bit_bfd enable_gdbcli @@ -1586,6 +1589,10 @@ Optional Packages: [DATADIR/gdb] --with-relocated-sources=PATH automatically relocate this path for source files + --with-gdb-datadir look for global separate data files in this path + [DATADIR/gdb] + --with-pythondir install Python data files in this path + [DATADIR/gdb/python] --with-libunwind use libunwind frame unwinding support --with-curses use the curses library instead of the termcap library @@ -6866,6 +6873,73 @@ _ACEOF fi +# GDB's datadir relocation + +gdbdatadir=${datadir}/gdb + + +# Check whether --with-gdb-datadir was given. +if test "${with_gdb_datadir+set}" = set; then : + withval=$with_gdb_datadir; gdbdatadir="${withval}" +fi + + + + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + ac_define_dir=`eval echo $gdbdatadir` + ac_define_dir=`eval echo $ac_define_dir` + +cat >>confdefs.h <<_ACEOF +#define GDB_DATADIR "$ac_define_dir" +_ACEOF + + + +if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi +else + test_prefix=$exec_prefix +fi + +case ${gdbdatadir} in + "${test_prefix}"|"${test_prefix}/"*|\ + '${exec_prefix}'|'${exec_prefix}/'*) + +$as_echo "#define GDB_DATADIR_RELOCATABLE 1" >>confdefs.h + + ;; +esac +GDB_DATADIR_PATH=${gdbdatadir} + + + +# Check whether --with-pythondir was given. +if test "${with_pythondir+set}" = set; then : + withval=$with_pythondir; pythondir="${withval}" +else + pythondir=no +fi + + +# If the user passed in a path, define it. Otherwise, compute it at +# runtime based on the possibly-relocatable datadir. +if test "$pythondir" = "no"; then + pythondir='$(GDB_DATADIR_PATH)/python' +else + +cat >>confdefs.h <<_ACEOF +#define PYTHONDIR "$pythondir" +_ACEOF + +fi + + + subdirs="$subdirs doc testsuite" @@ -9604,6 +9678,8 @@ $as_echo "#define HAVE_PYTHON 1" >>confdefs.h CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). diff --git a/gdb/configure.ac b/gdb/configure.ac index a756a2d..b44e21d 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -108,6 +108,51 @@ AS_HELP_STRING([--with-relocated-sources=PATH], [automatically relocate this pat [Relocated directory for source files. ]) ]) +# GDB's datadir relocation + +gdbdatadir=${datadir}/gdb + +AC_ARG_WITH([gdb-datadir], + [AS_HELP_STRING([--with-gdb-datadir], + [look for global separate data files in this path [DATADIR/gdb]])], [gdbdatadir="${withval}"]) + +AC_DEFINE_DIR(GDB_DATADIR, gdbdatadir, + [Global directory for GDB data files. ]) + +if test "x$exec_prefix" = xNONE || test "x$exec_prefix" = 'x${prefix}'; then + if test "x$prefix" = xNONE; then + test_prefix=/usr/local + else + test_prefix=$prefix + fi +else + test_prefix=$exec_prefix +fi + +case ${gdbdatadir} in + "${test_prefix}"|"${test_prefix}/"*|\ + '${exec_prefix}'|'${exec_prefix}/'*) + AC_DEFINE(GDB_DATADIR_RELOCATABLE, 1, [Define if GDB datadir should be relocated when GDB is moved.]) + ;; +esac +GDB_DATADIR_PATH=${gdbdatadir} +AC_SUBST(GDB_DATADIR_PATH) + +AC_ARG_WITH([pythondir], + [AS_HELP_STRING([--with-pythondir], + [install Python data files in this path [DATADIR/gdb/python]])], [pythondir="${withval}"], [pythondir=no]) + +# If the user passed in a path, define it. Otherwise, compute it at +# runtime based on the possibly-relocatable datadir. +if test "$pythondir" = "no"; then + pythondir='$(GDB_DATADIR_PATH)/python' +else + AC_DEFINE_UNQUOTED(PYTHONDIR, "$pythondir", + [Define to install path for Python sources]) +fi +AC_SUBST(pythondir) + + AC_CONFIG_SUBDIRS(doc testsuite) # Check whether to support alternative target configurations @@ -674,6 +719,8 @@ if test "${have_libpython}" = yes; then CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index 81f6a5d..097db65 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -389,7 +389,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 04b665b..21e013a 100644 --- a/gdb/cp-namespace.c +++ b/gdb/cp-namespace.c @@ -34,14 +34,17 @@ #include "buildsym.h" 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); @@ -117,7 +120,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; @@ -132,7 +135,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; @@ -146,7 +150,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); } @@ -199,7 +204,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. */ @@ -207,14 +215,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; } @@ -229,12 +244,48 @@ cp_add_using (const char *dest, 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 @@ -252,9 +303,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, @@ -276,8 +326,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; } @@ -288,25 +337,98 @@ 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)); + } +} + +/* Used for cleanups to reset the "searched" flag incase + of an error. */ + +static void +reset_directive_searched (void *data) +{ + struct using_direct *direct = data; + direct->searched = 0; +} + +/* 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; + struct cleanup *searched_cleanup; + + if(!declaration_only) + /* First, try to find the symbol in the given namespace. */ + sym = cp_lookup_symbol_in_namespace (scope, name, block, domain); - /* First, go through the using directives. If any of them add new + if ( sym != NULL) + return sym; + + if (has_stack_frames ()) + current_line = find_pc_line (get_frame_pc (get_selected_frame (NULL)), + 0).line; + else + current_line = 0; + + /* 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. */ @@ -314,39 +436,78 @@ 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; + searched_cleanup = make_cleanup (reset_directive_searched, current); + + /* 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); + } + + current->searched = 0; + if (sym) + return sym; + + continue; + } + + if (declaration_only) + { + current->searched = 0; + discard_cleanups (searched_cleanup); + 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; + discard_cleanups (searched_cleanup); + if (sym != NULL) 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 @@ -356,17 +517,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 @@ -376,12 +535,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) @@ -402,6 +560,7 @@ lookup_symbol_file (const char *name, sym = lookup_possible_namespace_symbol (name); if (sym != NULL) return sym; + } return NULL; @@ -429,9 +588,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) @@ -677,7 +835,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) { @@ -718,7 +876,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 c31fcff..fc294ae 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -190,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) @@ -840,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); } diff --git a/gdb/cp-support.h b/gdb/cp-support.h index a629955..2afdb48 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); @@ -79,10 +98,16 @@ extern int cp_validate_operator (const char *input); 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); @@ -99,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 6ef6767..5f4825c 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -3565,6 +3565,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 d716d0d..35dc185 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1159,6 +1159,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} @@ -19145,7 +19155,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 @@ -19428,8 +19438,6 @@ containing @code{end}. For example: @smallexample (@value{GDBP}) python -Type python script -End with a line saying just "end". >print 23 >end 23 @@ -19442,6 +19450,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 @@ -19449,6 +19465,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 @@ -19461,13 +19485,17 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. * Basic Python:: Basic Python Functions. * Exception Handling:: * Auto-loading:: Automatically loading Python code. -* Values From Inferior:: +* Values From Inferior:: Python representation of values. * Types In Python:: Python representation of types. * Pretty Printing:: Pretty-printing values. * Selecting Pretty-Printers:: How GDB chooses a pretty-printer. +* Inferiors In Python:: Python representation of inferiors (processes) +* Threads In Python:: Accessing inferior threads from Python. * Commands In Python:: Implementing new commands in Python. +* Parameters In Python:: Adding new @value{GDBN} parameters. * Functions In Python:: Writing new convenience functions. * Objfiles In Python:: Object files. +* Breakpoints In Python:: Manipulating breakpoints using Python. * Frames In Python:: Acessing inferior stack frames from Python. * Lazy Strings In Python:: Python representation of lazy strings. @end menu @@ -19495,6 +19523,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 @@ -19511,6 +19545,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 @@ -19535,6 +19570,21 @@ compute values, for example, it is the only way to get the value of a convenience variable (@pxref{Convenience Vars}) as a @code{gdb.Value}. @end defun +@findex gdb.post_event +@defun post_event event +Put @var{event}, a callable object taking no arguments, into +@value{GDBN}'s internal event queue. This callable will be invoked at +some later point, during @value{GDBN}'s event processing. Events +posted using @code{post_event} will be run in the order in which they +were posted; however, there is no way to know when they will be +processed relative to other events inside @value{GDBN}. + +@value{GDBN} is not thread-safe. If your Python program uses multiple +threads, you must be careful to only call @value{GDBN}-specific +functions in the main @value{GDBN} thread. @code{post_event} ensures +this. +@end defun + @findex gdb.write @defun write string Print a string to @value{GDBN}'s paginated standard output stream. @@ -19549,6 +19599,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 @@ -19787,6 +19842,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 @@ -19909,7 +19967,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. @@ -19917,7 +19975,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 @@ -20271,6 +20330,121 @@ import gdb.libstdcxx.v6 gdb.libstdcxx.v6.register_printers (gdb.current_objfile ()) @end smallexample +@node Inferiors In Python +@subsubsection Inferiors In Python + +Programs which are being run under @value{GDBN} are called inferiors +(@pxref{Inferiors and Programs}). Python scripts can access +information about and manipulate inferiors controlled by @value{GDBN} +via objects of the @code{gdb.Inferior} class. + +The following inferior-related functions are available in the @code{gdb} +module: + +@defun inferiors +Return a tuple containing all inferior objects. +@end defun + +A @code{gdb.Inferior} object has the following attributes: + +@table @code +@defivar Inferior num +ID of inferior, as assigned by GDB. +@end defivar + +@defivar Inferior pid +Process ID of the inferior, assigned by the underlying OS. +@end defivar + +@defivar Inferior was_attached +Boolean signaling whether the inferior was created using `attach', or +started by @value{GDBN} itself. +@end defivar +@end table + +A @code{gdb.Inferior} object has the following methods: + +@table @code +@defmethod Inferior threads +This method returns a tuple holding all the threads which are valid +when it is called. If there are no valid threads, the method will +return an empty list. +@end defmethod + +@findex gdb.read_memory +@defmethod Inferior read_memory @var{address} @var{length} +Read @var{length} bytes of memory from the inferior, starting at +@var{address}. Returns a buffer object, which behaves much like an array +or a string. It can be modified and given to the @code{gdb.write_memory} +function. +@end defmethod + +@findex gdb.write_memory +@defmethod Inferior write_memory @var{address} @var{buffer} @r{[}@var{length}@r{]} +Write the contents of @var{buffer} (a Python object which supports the +buffer protocol, i.e., a string, an array or the object returned from +@code{gdb.read_memory}) to the inferior, starting at @var{address}. +If given, @var{length} determines the number of bytes from @var{buffer} to +be written. +@end defmethod + +@findex gdb.search_memory +@defmethod Inferior search_memory @var{address} @var{length} @var{pattern} @r{[}@var{size}@r{]} @r{[}@var{max_count}@r{]} +Search a region of the inferior memory starting at @var{address} with the +given @var{length}. @var{pattern} can be a string, a byte array, a buffer +object, a number, a @code{gdb.Value} object (@pxref{Values From Inferior}) +or a list or tuple with elements in any combination of those types. If +@var{size} is given and is non-zero, it specifies the size in bytes of a +Python scalar or @code{gdb.Value} in the search pattern. If @var{size} is +zero or not specified, it is taken from the value's type in the current +language. This is useful when one wants to specify the search pattern as +a mixture of types. Note that this means, for example, that in the case of +C-like languages a search for an untyped 0x42 will search for +@samp{(int) 0x42} which is typically four bytes. @var{max_count} is the +highest number of matches to search for. +@end defmethod +@end table + +@node Threads In Python +@subsubsection Threads In Python + +Python scripts can access information about and manipulate inferior threads +controlled by @value{GDBN} via objects of the @code{gdb.InferiorThread} class. + +The following inferior-related functions are available in the @code{gdb} +module: + +@findex gdb.selected_thread +@defun selected_thread +This function returns the thread object for the selected thread. If there +is no selected thread, this will return @code{None}. +@end defun + +A @code{gdb.InferiorThread} object has the following attributes: + +@table @code +@defivar InferiorThread num +ID of the thread, as assigned by GDB. +@end defivar +@end table + +A @code{gdb.InferiorThread} object has the following methods: + +@table @code +@defmethod InferiorThread frames +Return a tuple containing all frames in the thread. +@end defmethod + +@defmethod InferiorThread newest_frame +Return the newest frame thread's stack. +@end defmethod + +@defmethod InferiorThread switch_to_thread +This changes @value{GDBN}'s currently selected thread to the one represented +by this object. +@end defmethod +@end table + @node Commands In Python @subsubsection Commands In Python @@ -20523,6 +20697,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 @@ -20627,6 +20930,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. @@ -20691,6 +21070,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 @@ -20699,10 +21086,18 @@ Return the frame that called this frame. Return the frame called by this frame. @end defmethod +@defmethod Frame find_sal +Return the frame's symtab and line object. @c (@pxref{Symtab_and_line,, Symtab and line}). +@end defmethod + @defmethod Frame read_var variable Return the value of the given variable in this frame. @var{variable} must be a string. @end defmethod + +@defmethod Frame select +Set this frame to be the user's selected frame. +@end defmethod @end table @node Lazy Strings In Python diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 347c860..5d7002e 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -2107,6 +2107,18 @@ time, and so we attempt to handle symbols incrementally. For instance, we create @dfn{partial symbol tables} consisting of only selected symbols, and only expand them to full symbol tables when necessary. +@menu +* Symbol Reading:: +* Partial Symbol Tables:: +* Types:: +* Object File Formats:: +* Debugging File Formats:: +* Adding a New Symbol Reader to GDB:: +* Memory Management for Symbol Files:: +* Memory Management for Types:: +@end menu + +@node Symbol Reading @section Symbol Reading @cindex symbol reading @@ -2199,6 +2211,7 @@ symtab. Upon return, @code{pst->readin} should have been set to 1, and zero if there were no symbols in that part of the symbol file. @end table +@node Partial Symbol Tables @section Partial Symbol Tables @value{GDBN} has three types of symbol tables: @@ -2294,6 +2307,7 @@ and all the psymbols themselves are allocated in a pair of large arrays on an obstack, so there is little to be gained by trying to free them unless you want to do a lot more work. +@node Types @section Types @unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}). @@ -2316,6 +2330,7 @@ types map to one @code{TYPE_CODE_*} type, and are distinguished by other members of the type struct, such as whether the type is signed or unsigned, and how many bits it uses. +@anchor{Builtin Types} @unnumberedsubsec Builtin Types (e.g., @code{builtin_type_void}, @code{builtin_type_char}). These are instances of type structs that roughly correspond to @@ -2330,6 +2345,7 @@ only one instance exists, while @file{c-lang.c} builds as many @code{TYPE_CODE_INT} types as needed, with each one associated with some particular objfile. +@node Object File Formats @section Object File Formats @cindex object file formats @@ -2415,6 +2431,7 @@ SOM, which is a cross-language ABI). The SOM reader is in @file{somread.c}. +@node Debugging File Formats @section Debugging File Formats This section describes characteristics of debugging information that @@ -2486,6 +2503,7 @@ DWARF 3 is an improved version of DWARF 2. @cindex SOM debugging info Like COFF, the SOM definition includes debugging information. +@node Adding a New Symbol Reader to GDB @section Adding a New Symbol Reader to @value{GDBN} @cindex adding debugging info reader @@ -2508,6 +2526,7 @@ will only ever be implemented by one object file format may be called directly. This interface should be described in a file @file{bfd/lib@var{xyz}.h}, which is included by @value{GDBN}. +@node Memory Management for Symbol Files @section Memory Management for Symbol Files Most memory associated with a loaded symbol file is stored on @@ -2519,10 +2538,45 @@ released when the objfile is unloaded or reloaded. Therefore one objfile must not reference symbol or type data from another objfile; they could be unloaded at different times. -User convenience variables, et cetera, have associated types. Normally -these types live in the associated objfile. However, when the objfile -is unloaded, those types are deep copied to global memory, so that -the values of the user variables and history items are not lost. +@node Memory Management for Types +@section Memory Management for Types +@cindex memory management for types + +@findex TYPE_OBJFILE +@code{TYPE_OBJFILE} macro indicates the current memory owner of the type. +Non-@code{NULL} value indicates it is owned by an objfile (specifically by its +obstack) and in such case the type remains valid till the objfile is unloaded +or reloaded. For such types with an associated objfile no reference counting +is being made. + +User convenience variables, et cetera, have associated types. Normally these +types live in the associated objfile. However, when the objfile is unloaded, +those types are deep copied to global memory, so that the values of the user +variables and history items are not lost. During the copy they will get their +@code{TYPE_OBJFILE} set to @code{NULL} and become so-called @dfn{reclaimable} +types. + +Types with null @code{TYPE_OBJFILE} can be either permanent types +(@pxref{Builtin Types}) or reclaimable types which will be deallocated at the +first idle @value{GDBN} moment if the last object referencing them is removed. +Permanent types are allocated by the function @code{alloc_type} (and its +derivations like @code{init_type}) specifying objfile as @code{NULL}. The +reclaimable types are created the same way but moreover they need to have +@code{type_init_group} called to start their tracking as being possibly +deallocatable. + +@findex free_all_types +When @value{GDBN} gets idle it always calls the @code{free_all_types} function +which deallocates any unused types. All types currently not owned by an +objfile must be marked as used on each @code{free_all_types} call as they would +get deallocated as unused otherwise. + +@code{free_all_types} automatically checks for any cross-type references such +as through @code{TYPE_TARGET_TYPE}, @code{TYPE_POINTER_TYPE} etc.@: and +prevents early deallocation for any such existing references. Reclaimable +types may reference any other reclaimable types or even permanent types. But +permanent types must not reference reclaimable types (nor an objfile associated +type). @node Language Support diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi index db3d114..759200f 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -213,6 +213,11 @@ Bytes from @var{data} to @var{data} + @var{len} have been written to the current inferior at @var{addr}. @end deftypefun +@deftypefun void mark_used (void) +Mark any possibly reclaimable objects as used during a mark-and-sweep garbage +collector pass. Currently only @code{type_mark_used} marker is supported. +@end deftypefun + @deftypefun void test_notification (int @var{somearg}) This observer is used for internal testing. Do not use. See testsuite/gdb.gdb/observer.exp. diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 99100d7..5915249 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -38,6 +38,7 @@ #include "complaints.h" #include "dwarf2-frame.h" +#include "addrmap.h" struct comp_unit; @@ -1582,6 +1583,14 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) CORE_ADDR offset; CORE_ADDR seek_pc; + if (objfile->quick_addrmap) + { + if (!addrmap_find (objfile->quick_addrmap, *pc)) + continue; + } + /* FIXME: Read-in only .debug_frame/.eh_frame without .debug_info? */ + require_partial_symbols (objfile); + fde_table = objfile_data (objfile, dwarf2_frame_objfile_data); if (fde_table == NULL) continue; diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index ed21edf..1b10cb7 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -868,6 +868,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, ctx->initialized = 0; goto no_push; + case DW_OP_push_object_address: + if (ctx->get_object_address == NULL) + error (_("DWARF-2 expression error: DW_OP_push_object_address must " + "have a value to push.")); + result = (ctx->get_object_address) (ctx->baton); + break; + default: error (_("Unhandled dwarf expression opcode 0x%x"), op); } diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 437ca39..f7fce92 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -102,10 +102,10 @@ struct dwarf_expr_context The result must be live until the current expression evaluation is complete. */ unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length); +#endif /* Return the `object address' for DW_OP_push_object_address. */ CORE_ADDR (*get_object_address) (void *baton); -#endif /* The current depth of dwarf expression recursion, via DW_OP_call*, DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 6679d74..54d2bae 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -121,6 +121,9 @@ struct dwarf_expr_baton { struct frame_info *frame; struct objfile *objfile; + /* From DW_TAG_variable's DW_AT_location (not DW_TAG_type's + DW_AT_data_location) for DW_OP_push_object_address. */ + CORE_ADDR object_address; }; /* Helper functions for dwarf2_evaluate_loc_desc. */ @@ -189,22 +192,33 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, symbaton = SYMBOL_LOCATION_BATON (framefunc); *start = find_location_expression (symbaton, length, pc); } - else + else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_locexpr_funcs) { struct dwarf2_locexpr_baton *symbaton; + symbaton = SYMBOL_LOCATION_BATON (framefunc); - if (symbaton != NULL) - { - *length = symbaton->size; - *start = symbaton->data; - } - else - *start = NULL; + gdb_assert (symbaton != NULL); + *start = symbaton->data; + *length = symbaton->size; } + else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_missing_funcs) + { + struct dwarf2_locexpr_baton *symbaton; + + symbaton = SYMBOL_LOCATION_BATON (framefunc); + gdb_assert (symbaton == NULL); + *start = NULL; + *length = 0; /* unused */ + } + else + internal_error (__FILE__, __LINE__, + _("Unsupported SYMBOL_COMPUTED_OPS %p for \"%s\""), + SYMBOL_COMPUTED_OPS (framefunc), + SYMBOL_PRINT_NAME (framefunc)); if (*start == NULL) error (_("Could not find the frame base for \"%s\"."), - SYMBOL_NATURAL_NAME (framefunc)); + SYMBOL_PRINT_NAME (framefunc)); } /* Helper function for dwarf2_evaluate_loc_desc. Computes the CFA for @@ -227,6 +241,129 @@ dwarf_expr_tls_address (void *baton, CORE_ADDR offset) return target_translate_tls_address (debaton->objfile, offset); } +static CORE_ADDR +dwarf_expr_object_address (void *baton) +{ + struct dwarf_expr_baton *debaton = baton; + + /* The message is suppressed in DWARF_BLOCK_EXEC. */ + if (debaton->object_address == 0) + error (_("Cannot resolve DW_OP_push_object_address for a missing object")); + + return debaton->object_address; +} + +/* Address of the variable we are currently referring to. It is set from + DW_TAG_variable's DW_AT_location (not DW_TAG_type's DW_AT_data_location) for + DW_OP_push_object_address. */ + +static CORE_ADDR object_address; + +/* Callers use object_address_set while their callers use the result set so we + cannot run the cleanup at the local block of our direct caller. Still we + should reset OBJECT_ADDRESS at least for the next GDB command. */ + +static void +object_address_cleanup (void *prev_save_voidp) +{ + CORE_ADDR *prev_save = prev_save_voidp; + + object_address = *prev_save; + xfree (prev_save); +} + +/* Set the base address - DW_AT_location - of a variable. It is being later + used to derive other object addresses by DW_OP_push_object_address. + + It would be useful to sanity check ADDRESS - such as for some objects with + unset value_raw_address - but some valid addresses may be zero (such as first + objects in relocatable .o files). */ + +void +object_address_set (CORE_ADDR address) +{ + CORE_ADDR *prev_save; + + prev_save = xmalloc (sizeof *prev_save); + *prev_save = object_address; + make_cleanup (object_address_cleanup, prev_save); + + object_address = address; +} + +/* Evaluate DWARF expression at DATA ... DATA + SIZE with its result readable + by dwarf_expr_fetch (RETVAL, 0). FRAME parameter can be NULL to call + get_selected_frame to find it. Returned dwarf_expr_context freeing is + pushed on the cleanup chain. */ + +static struct dwarf_expr_context * +dwarf_expr_prep_ctx (struct frame_info *frame, gdb_byte *data, + unsigned short size, struct dwarf2_per_cu_data *per_cu) +{ + struct dwarf_expr_context *ctx; + struct dwarf_expr_baton baton; + + if (!frame) + frame = get_selected_frame (NULL); + + baton.frame = frame; + baton.objfile = dwarf2_per_cu_objfile (per_cu); + baton.object_address = object_address; + + ctx = new_dwarf_expr_context (); + make_cleanup_free_dwarf_expr_context (ctx); + + ctx->gdbarch = get_objfile_arch (baton.objfile); + ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->baton = &baton; + ctx->read_reg = dwarf_expr_read_reg; + ctx->read_mem = dwarf_expr_read_mem; + ctx->get_frame_base = dwarf_expr_frame_base; + ctx->get_frame_cfa = dwarf_expr_frame_cfa; + ctx->get_tls_address = dwarf_expr_tls_address; + ctx->get_object_address = dwarf_expr_object_address; + + dwarf_expr_eval (ctx, data, size); + + /* It was used only during dwarf_expr_eval. */ + ctx->baton = NULL; + + return ctx; +} + +/* Evaluate DWARF expression at DLBATON expecting it produces exactly one + CORE_ADDR result on the DWARF stack stack. */ + +CORE_ADDR +dwarf_locexpr_baton_eval (struct dwarf2_locexpr_baton *dlbaton) +{ + struct dwarf_expr_context *ctx; + CORE_ADDR retval; + struct cleanup *back_to = make_cleanup (null_cleanup, 0); + + ctx = dwarf_expr_prep_ctx (NULL, dlbaton->data, dlbaton->size, + dlbaton->per_cu); + if (ctx->num_pieces > 0) + error (_("DW_OP_*piece is unsupported for DW_FORM_block")); + + retval = dwarf_expr_fetch (ctx, 0); + + if (ctx->location == DWARF_VALUE_REGISTER) + { + /* Inlined dwarf_expr_read_reg as we no longer have the baton. */ + + int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (ctx->gdbarch, retval); + struct type *type = builtin_type (ctx->gdbarch)->builtin_data_ptr; + struct frame_info *frame = get_selected_frame (NULL); + + retval = address_from_register (type, gdb_regnum, frame); + } + + do_cleanups (back_to); + + return retval; +} + struct piece_closure { /* The number of pieces used to describe this variable. */ @@ -408,9 +545,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, struct dwarf2_per_cu_data *per_cu) { struct value *retval; - struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; - struct cleanup *old_chain; + struct cleanup *old_chain = make_cleanup (null_cleanup, 0); if (size == 0) { @@ -420,22 +556,8 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, return retval; } - baton.frame = frame; - baton.objfile = dwarf2_per_cu_objfile (per_cu); - - ctx = new_dwarf_expr_context (); - old_chain = make_cleanup_free_dwarf_expr_context (ctx); - - ctx->gdbarch = get_objfile_arch (baton.objfile); - ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); - ctx->baton = &baton; - ctx->read_reg = dwarf_expr_read_reg; - ctx->read_mem = dwarf_expr_read_mem; - ctx->get_frame_base = dwarf_expr_frame_base; - ctx->get_frame_cfa = dwarf_expr_frame_cfa; - ctx->get_tls_address = dwarf_expr_tls_address; + ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu); - dwarf_expr_eval (ctx, data, size); if (ctx->num_pieces > 0) { struct piece_closure *c; @@ -465,6 +587,11 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, CORE_ADDR address = dwarf_expr_fetch (ctx, 0); int in_stack_memory = dwarf_expr_fetch_in_stack_memory (ctx, 0); + /* object_address_set called here is required in ALLOCATE_VALUE's + CHECK_TYPEDEF for the object's possible + DW_OP_push_object_address. */ + object_address_set (address); + retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = lval_memory; set_value_lazy (retval, 1); @@ -872,7 +999,7 @@ static int loclist_describe_location (struct symbol *symbol, struct ui_file *stream) { /* FIXME: Could print the entire list of locations. */ - fprintf_filtered (stream, "a variable with multiple locations"); + fprintf_filtered (stream, _("a variable with multiple locations")); return 1; } @@ -888,16 +1015,56 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch, data = find_location_expression (dlbaton, &size, ax->scope); if (data == NULL) - error (_("Variable \"%s\" is not available."), SYMBOL_NATURAL_NAME (symbol)); + error (_("Variable \"%s\" is not available."), SYMBOL_PRINT_NAME (symbol)); dwarf2_tracepoint_var_ref (symbol, gdbarch, ax, value, data, size); } -/* The set of location functions used with the DWARF-2 expression - evaluator and location lists. */ +/* The set of location functions used with the DWARF-2 location lists. */ const struct symbol_computed_ops dwarf2_loclist_funcs = { loclist_read_variable, loclist_read_needs_frame, loclist_describe_location, loclist_tracepoint_var_ref }; + +static struct value * +missing_read_variable (struct symbol *symbol, struct frame_info *frame) +{ + struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + + gdb_assert (dlbaton == NULL); + error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol)); +} + +static int +missing_read_needs_frame (struct symbol *symbol) +{ + return 0; +} + +static int +missing_describe_location (struct symbol *symbol, struct ui_file *stream) +{ + fprintf_filtered (stream, _("a variable we are unable to resolve")); + return 1; +} + +static void +missing_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch, + struct agent_expr *ax, struct axs_value *value) +{ + struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + + gdb_assert (dlbaton == NULL); + error (_("Unable to resolve variable \"%s\""), SYMBOL_PRINT_NAME (symbol)); +} + +/* The set of location functions used with the DWARF-2 evaluator when we are + unable to resolve the symbols. */ +const struct symbol_computed_ops dwarf2_missing_funcs = { + missing_read_variable, + missing_read_needs_frame, + missing_describe_location, + missing_tracepoint_var_ref +}; diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index fa0bd11..fdea2b4 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -72,5 +72,11 @@ struct dwarf2_loclist_baton extern const struct symbol_computed_ops dwarf2_locexpr_funcs; extern const struct symbol_computed_ops dwarf2_loclist_funcs; +extern const struct symbol_computed_ops dwarf2_missing_funcs; + +extern void object_address_set (CORE_ADDR address); + +extern CORE_ADDR dwarf_locexpr_baton_eval + (struct dwarf2_locexpr_baton *dlbaton); #endif /* dwarf2loc.h */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 15ef3e9..99f729b 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -48,6 +48,11 @@ #include "gdbcmd.h" #include "block.h" #include "addrmap.h" +#include "block.h" +#include "f-lang.h" +#include "typeprint.h" +#include "jv-lang.h" +#include "vec.h" #include #include "gdb_string.h" @@ -96,7 +101,7 @@ typedef struct pubnames_header _PUBNAMES_HEADER; #define _ACTUAL_PUBNAMES_HEADER_SIZE 13 -/* .debug_pubnames header +/* .debug_aranges header Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct aranges_header @@ -153,7 +158,10 @@ struct dwarf2_section_info asection *asection; gdb_byte *buffer; bfd_size_type size; - int was_mmapped; + /* A function to call to deallocate BUFFER. If NULL, no + deallocation is needed. A pointer to this structure is passed as + the only argument. */ + void (*destructor) (struct dwarf2_section_info *); }; struct dwarf2_per_objfile @@ -333,6 +341,19 @@ struct dwarf2_cu DIEs for namespaces, we don't need to try to infer them from mangled names. */ unsigned int has_namespace_info : 1; + + /* Fields are valid according to the LANGUAGE field. */ + union + { + /* language_fortran */ + struct + { + /* Module names imported to the block being currently read in. */ + struct fortran_using *use; + } + fortran; + } + language_specific; }; /* Persistent data held for a compilation unit, even when not @@ -487,8 +508,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; /* The scope to prepend to our children. This is generally @@ -677,6 +697,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 @@ -788,7 +813,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, @@ -813,6 +841,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 *); @@ -940,6 +972,11 @@ 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 char *physname_prefix (struct die_info *die, 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 *typename_concat (struct obstack *, @@ -984,17 +1021,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 *); @@ -1028,7 +1073,10 @@ static gdb_byte *read_full_die (const struct die_reader_specs *reader, static void process_die (struct die_info *, struct dwarf2_cu *); -static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *); +static char *dwarf2_physname (struct die_info *, struct dwarf2_cu *); + +static char *fortran_module_linkage_name (struct die_info *die, + struct dwarf2_cu *cu); static char *dwarf2_canonicalize_name (char *, struct dwarf2_cu *, struct obstack *); @@ -1144,6 +1192,9 @@ static void age_cached_comp_units (void); static void free_one_cached_comp_unit (void *); +static void fetch_die_type_attrs (struct die_info *die, struct type *type, + struct dwarf2_cu *cu); + static struct type *set_die_type (struct die_info *, struct type *, struct dwarf2_cu *); @@ -1163,22 +1214,31 @@ static void dwarf2_clear_marks (struct dwarf2_per_cu_data *); static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu); +static void destroy_section (struct dwarf2_section_info *info); + +static struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton + (struct attribute *attr, struct dwarf2_cu *cu); + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ int dwarf2_has_info (struct objfile *objfile) { - struct dwarf2_per_objfile *data; - - /* Initialize per-objfile state. */ - data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); - memset (data, 0, sizeof (*data)); - set_objfile_data (objfile, dwarf2_objfile_data_key, data); - dwarf2_per_objfile = data; + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); + if (!dwarf2_per_objfile) + { + /* Initialize per-objfile state. */ + struct dwarf2_per_objfile *data + = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); + memset (data, 0, sizeof (*data)); + set_objfile_data (objfile, dwarf2_objfile_data_key, data); + dwarf2_per_objfile = data; - bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL); - return (data->info.asection != NULL && data->abbrev.asection != NULL); + bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL); + } + return (dwarf2_per_objfile->info.asection != NULL + && dwarf2_per_objfile->abbrev.asection != NULL); } /* When loading sections, we can either look for ".", or for @@ -1271,10 +1331,13 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) } /* Decompress a section that was compressed using zlib. Store the - decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ + decompressed buffer, and its size, in OUTBUF and OUTSIZE. The + result is allocated on OBSTACK; if OBSTACK is NULL, xmalloc is + used. */ static void -zlib_decompress_section (struct objfile *objfile, asection *sectp, +zlib_decompress_section (struct objfile *objfile, struct obstack *obstack, + asection *sectp, gdb_byte **outbuf, bfd_size_type *outsize) { bfd *abfd = objfile->obfd; @@ -1291,6 +1354,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, z_stream strm; int rc; int header_size = 12; + struct cleanup *old = NULL; if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 || bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size) @@ -1320,8 +1384,13 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, strm.avail_in = compressed_size - header_size; strm.next_in = (Bytef*) compressed_buffer + header_size; strm.avail_out = uncompressed_size; - uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack, - uncompressed_size); + if (obstack) + uncompressed_buffer = obstack_alloc (obstack, uncompressed_size); + else + { + uncompressed_buffer = xmalloc (uncompressed_size); + old = make_cleanup (xfree, uncompressed_buffer); + } rc = inflateInit (&strm); while (strm.avail_in > 0) { @@ -1342,26 +1411,176 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp, error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), bfd_get_filename (abfd), rc); + if (old) + discard_cleanups (old); do_cleanups (cleanup); *outbuf = uncompressed_buffer; *outsize = uncompressed_size; #endif } -/* Read the contents of the section SECTP from object file specified by - OBJFILE, store info about the section into INFO. - If the section is compressed, uncompress it before returning. */ +/* A cleanup that calls destroy_section. */ static void -dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) +destroy_section_cleanup (void *arg) +{ + destroy_section (arg); +} + +/* Read the .debug_aranges section and construct an address map. */ + +void +dwarf2_create_quick_addrmap (struct objfile *objfile) +{ + char *aranges_buffer, *aranges_ptr; + bfd *abfd = objfile->obfd; + CORE_ADDR baseaddr; + struct cleanup *old; + struct obstack temp_obstack; + struct addrmap *mutable_map; + + if (!dwarf2_per_objfile->aranges.asection) + return; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + dwarf2_read_section_1 (objfile, NULL, &dwarf2_per_objfile->aranges); + aranges_buffer = dwarf2_per_objfile->aranges.buffer; + aranges_ptr = aranges_buffer; + old = make_cleanup (destroy_section_cleanup, &dwarf2_per_objfile->aranges); + + obstack_init (&temp_obstack); + make_cleanup_obstack_free (&temp_obstack); + mutable_map = addrmap_create_mutable (&temp_obstack); + + while ((aranges_ptr - aranges_buffer) < dwarf2_per_objfile->aranges.size) + { + struct comp_unit_head cu_header; + unsigned int bytes_read, segment_size, delta; + LONGEST info_offset; + struct dwarf2_cu cu; + char *end_ptr; + + cu_header.initial_length_size = 0; + end_ptr = aranges_ptr; + aranges_ptr = read_comp_unit_head (&cu_header, aranges_ptr, abfd); + end_ptr += cu_header.initial_length_size + cu_header.length; + + /* Sanity check. */ + if (end_ptr - aranges_ptr >= dwarf2_per_objfile->aranges.size) + { + do_cleanups (old); + complaint (&symfile_complaints, + _("aranges entry runs off end of `.debug_aranges' section, ignored")); + return; + } + if (cu_header.addr_size == 0) + { + do_cleanups (old); + complaint (&symfile_complaints, + _("aranges entry has zero addr_size, ignored")); + return; + } + + segment_size = read_1_byte (abfd, aranges_ptr); + aranges_ptr += 1; + + /* Align the pointer to twice the pointer size. I didn't see + this in the spec but it appears to be required. */ + delta = (aranges_ptr - aranges_buffer) % (2 * cu_header.addr_size); + delta = (2 * cu_header.addr_size - delta) % (2 * cu_header.addr_size); + aranges_ptr += delta; + + memset (&cu, 0, sizeof (cu)); + cu.header.addr_size = cu_header.addr_size; + + while (1) + { + CORE_ADDR address, length; + + address = read_address (abfd, aranges_ptr, &cu, &bytes_read); + aranges_ptr += bytes_read; + + length = read_address (abfd, aranges_ptr, &cu, &bytes_read); + aranges_ptr += bytes_read; + + if (address == 0 && length == 0) + break; + + if (length == 0) + { + do_cleanups (old); + complaint (&symfile_complaints, + _("aranges entry has zero length, ignored")); + return; + } + + address += baseaddr; + + addrmap_set_empty (mutable_map, address, address + length - 1, + objfile); + } + + /* Some older versions of GCC incorrectly started the arange + with a (0,0) pair. If we encounter any oddity while reading + the section, just abandon the attempt; falling back to the + slower code is always safe. */ + if (aranges_ptr != end_ptr) + { + do_cleanups (old); + complaint (&symfile_complaints, + _("aranges entry ends early, ignored")); + return; + } + } + + objfile->quick_addrmap = addrmap_create_fixed (mutable_map, + &objfile->objfile_obstack); + do_cleanups (old); +} + +/* Free a section buffer allocated with xmalloc. */ + +static void +xfree_section_buffer (struct dwarf2_section_info *info) +{ + xfree (info->buffer); +} + +/* If section described by INFO was mmapped, munmap it now. */ + +static void +munmap_section_buffer (struct dwarf2_section_info *info) +{ +#ifdef HAVE_MMAP + intptr_t begin = (intptr_t) info->buffer; + intptr_t map_begin = begin & ~(pagesize - 1); + size_t map_length = info->size + begin - map_begin; + gdb_assert (munmap ((void *) map_begin, map_length) == 0); +#else + /* Without HAVE_MMAP, we should never be here to begin with. */ + gdb_assert (0); +#endif +} + +/* Read the contents of the section at OFFSET and of size SIZE from + the object file specified by OBJFILE into OBSTACK and store it into + INFO. If OBSTACK is NULL, xmalloc is used instead. If the section + is compressed, uncompress it before returning. */ + +static void +dwarf2_read_section_1 (struct objfile *objfile, + struct obstack *obstack, + struct dwarf2_section_info *info) { bfd *abfd = objfile->obfd; asection *sectp = info->asection; gdb_byte *buf, *retbuf; unsigned char header[4]; + struct cleanup *old = NULL; info->buffer = NULL; - info->was_mmapped = 0; + info->destructor = 0; if (info->asection == NULL || info->size == 0) return; @@ -1374,7 +1593,7 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) /* Upon decompression, update the buffer and its size. */ if (strncmp (header, "ZLIB", sizeof (header)) == 0) { - zlib_decompress_section (objfile, sectp, &info->buffer, + zlib_decompress_section (objfile, obstack, sectp, &info->buffer, &info->size); return; } @@ -1397,7 +1616,7 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) if (retbuf != MAP_FAILED) { - info->was_mmapped = 1; + info->destructor = munmap_section_buffer; info->buffer = retbuf + (sectp->filepos & (pagesize - 1)) ; return; } @@ -1405,8 +1624,15 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) #endif /* If we get here, we are a normal, not-compressed section. */ - info->buffer = buf - = obstack_alloc (&objfile->objfile_obstack, info->size); + if (obstack) + buf = obstack_alloc (obstack, info->size); + else + { + buf = xmalloc (info->size); + old = make_cleanup (xfree, buf); + info->destructor = xfree_section_buffer; + } + info->buffer = buf; /* When debugging .o files, we may need to apply relocations; see http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . @@ -1415,6 +1641,8 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) retbuf = symfile_relocate_debug_section (abfd, sectp, buf); if (retbuf != NULL) { + if (old) + discard_cleanups (old); info->buffer = retbuf; return; } @@ -1423,6 +1651,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 @@ -2389,11 +2630,18 @@ partial_die_parent_scope (struct partial_die_info *pdi, || parent->tag == DW_TAG_union_type || parent->tag == DW_TAG_enumeration_type) { + char *parent_name = parent->name; + + /* G++ 4.1 produced DW_TAG_namespace with DW_AT_name "::". */ + if (parent->tag == DW_TAG_namespace && parent_name != NULL + && strcmp (parent_name, "::") == 0) + parent_name = NULL; + if (grandparent_scope == NULL) - parent->scope = parent->name; + parent->scope = parent_name; else parent->scope = typename_concat (&cu->comp_unit_obstack, grandparent_scope, - parent->name, cu); + parent_name, cu); } else if (parent->tag == DW_TAG_enumerator) /* Enumerators should not get the name of the enumeration as a prefix. */ @@ -2405,7 +2653,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; } @@ -2420,12 +2668,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 @@ -2441,12 +2699,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; @@ -2543,6 +2798,13 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) &objfile->global_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); break; + case DW_TAG_module: + add_psymbol_to_list (actual_name, strlen (actual_name), + built_actual_name, + MODULE_DOMAIN, LOC_STATIC, + &objfile->global_psymbols, + 0, (CORE_ADDR) 0, cu->language, objfile); + break; case DW_TAG_class_type: case DW_TAG_interface_type: case DW_TAG_structure_type: @@ -2586,34 +2848,17 @@ 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); } -/* Determine whether a die of type TAG living in a C++ class or - namespace needs to have the name of the scope prepended to the - name listed in the die. */ +/* Determine whether DIE needs to have the name of the scope prepended + to the 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: @@ -2623,7 +2868,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; } @@ -2656,12 +2917,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 @@ -2752,27 +3013,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; - } } } @@ -3325,6 +3565,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"), @@ -3340,41 +3588,71 @@ 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 given DIE's DW_AT_decl_line number. Return -1 if in case of an + error. */ + +static 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 @@ -3385,9 +3663,15 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu) struct dwarf2_cu *imported_cu; 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) { @@ -3436,17 +3720,27 @@ 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. */ - imported_name_prefix = determine_prefix (imported_die, imported_cu); - - if (strlen (imported_name_prefix) > 0) - { + imported_name_prefix = determine_prefix (imported_die, cu); + + 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, "::"); @@ -3457,8 +3751,14 @@ read_import_statement (struct die_info *die, struct dwarf2_cu *cu) 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 @@ -3727,6 +4027,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; @@ -3825,6 +4133,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) @@ -3843,13 +4152,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, NULL)) + 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; @@ -3876,14 +4195,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); @@ -3899,6 +4223,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); @@ -3952,7 +4283,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, @@ -4517,7 +4848,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, return; /* Get physical name. */ - physname = dwarf2_linkage_name (die, cu); + physname = dwarf2_physname (die, cu); /* The name is already allocated along with this objfile, so we don't need to duplicate it for the type. */ @@ -4679,7 +5010,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, return; /* Get the mangled name. */ - physname = dwarf2_linkage_name (die, cu); + physname = dwarf2_physname (die, cu); /* Look up member function name in fieldlist. */ for (i = 0; i < fip->nfnfields; i++) @@ -5010,14 +5341,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); } } @@ -5258,51 +5593,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. @@ -5380,6 +5670,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. */ @@ -5393,7 +5706,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; @@ -5440,16 +5753,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 @@ -5638,7 +5946,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)); } } @@ -5654,20 +5962,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); +} + +/* 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. */ - /* FIXME: Support the separate Fortran module namespaces. */ + new = push_context (0, 0); + save_file_symbols = file_symbols; + file_symbols = NULL; + save_global_symbols = global_symbols; + global_symbols = NULL; + save_list_in_scope = cu->list_in_scope; + + /* Process the child DIEs. */ + + child_die = die->child; while (child_die && child_die->tag) { + /* Any DW_TAG_subprogram will reset LIST_IN_SCOPE to LOCAL_SYMBOLS. */ + cu->list_in_scope = &global_symbols; + process_die (child_die, cu); child_die = sibling_die (child_die); } + + /* Finish this module and restore the context. */ + + TYPE_MODULE_BLOCK (type) = finish_block (NULL, &global_symbols, + new->old_blocks, 0, 0, objfile); + + if (file_symbols) + complaint (&symfile_complaints, _("DW_TAG_module contains static symbols")); + if (local_symbols) + complaint (&symfile_complaints, _("DW_TAG_module contains local symbols")); + if (param_symbols) + complaint (&symfile_complaints, _("DW_TAG_module contains function " + "parameters")); + + file_symbols = save_file_symbols; + global_symbols = save_global_symbols; + cu->list_in_scope = save_list_in_scope; + + pop_context (); + + set_die_type (die, type, cu); + + return type; +} + +/* Import a Fortran module. Only store the module name for its later lookup by + f_lookup_symbol_nonlocal. */ + +static void +read_fortran_imported_module (struct die_info *die, struct dwarf2_cu *cu) +{ + struct objfile *objfile = cu->objfile; + struct attribute *attr; + struct die_info *module_die; + char *module_name; + struct fortran_using *use; + + attr = dwarf2_attr (die, DW_AT_import, cu); + if (attr == NULL) + return; + + module_die = follow_die_ref (die, attr, &cu); + module_name = dwarf2_name (module_die, cu); + if (module_name == NULL) + { + complaint (&symfile_complaints, + _("Imported DIE at offset 0x%x has no name"), die->offset); + return; + } + + /* Fortran does not allow any duplicity between local and any of the imported + symbols. Therefore the order of the USE statements is not portant. + gfortran prints: + Error: Name 'X' at (1) is an ambiguous reference to 'X' from module 'Y' */ + + use = obstack_alloc (&objfile->objfile_obstack, sizeof (*use) + + strlen (module_name)); + strcpy (use->module_name, module_name); + gdb_assert (cu->language == language_fortran); + use->next = cu->language_specific.fortran.use; + cu->language_specific.fortran.use = use; +} + +/* Import a single Fortran declaration and possibly rename it. */ + +static void +read_fortran_imported_declaration (struct die_info *die, struct dwarf2_cu *cu) +{ + struct attribute *attr; + struct die_info *imported_die; + struct symbol *sym; + char *rename = dwarf2_name (die, cu); + + attr = dwarf2_attr (die, DW_AT_import, cu); + if (attr == NULL) + { + complaint (&symfile_complaints, + _("Fortran DW_TAG_imported_declaration is missing " + "DW_AT_import at offset 0x%x"), die->offset); + return; + } + imported_die = follow_die_ref (die, attr, &cu); + + sym = new_symbol (imported_die, NULL, cu); + + if (sym && rename) + SYMBOL_CPLUS_DEMANGLED_NAME (sym) = rename; } /* Return the name of the namespace represented by DIE. Set @@ -5832,29 +6275,113 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) struct gdbarch *gdbarch = get_objfile_arch (objfile); struct type *type, *range_type, *index_type, *char_type; struct attribute *attr; - unsigned int length; + int length; + + index_type = objfile_type (objfile)->builtin_int; + /* RANGE_TYPE is allocated from OBJFILE, not as a permanent type. */ + range_type = alloc_type (objfile); + /* LOW_BOUND and HIGH_BOUND are set for real below. */ + range_type = create_range_type (range_type, index_type, 0, -1); + + /* C/C++ should probably have the low bound 0 but C/C++ does not use + DW_TAG_string_type. */ + TYPE_LOW_BOUND (range_type) = 1; attr = dwarf2_attr (die, DW_AT_string_length, cu); - if (attr) - { - length = DW_UNSND (attr); + if (attr && attr_form_is_block (attr)) + { + /* Security check for a size overflow. */ + if (DW_BLOCK (attr)->size + 2 < DW_BLOCK (attr)->size) + TYPE_HIGH_BOUND (range_type) = 1; + /* Extend the DWARF block by a new DW_OP_deref/DW_OP_deref_size + instruction as DW_AT_string_length specifies the length location, not + its value. */ + else + { + struct dwarf2_locexpr_baton *length_baton = NULL; + struct dwarf_block *blk = DW_BLOCK (attr); + + /* Turn any single DW_OP_reg* into DW_OP_breg*(0) but clearing + DW_OP_deref* in such case. */ + + if (blk->size == 1 && blk->data[0] >= DW_OP_reg0 + && blk->data[0] <= DW_OP_reg31) + length_baton = dwarf2_attr_to_locexpr_baton (attr, cu); + else if (blk->size > 1 && blk->data[0] == DW_OP_regx) + { + ULONGEST ulongest; + gdb_byte *end; + + end = read_uleb128 (&blk->data[1], &blk->data[blk->size], + &ulongest); + if (end == &blk->data[blk->size]) + length_baton = dwarf2_attr_to_locexpr_baton (attr, cu); + } + + if (length_baton == NULL) + { + struct attribute *size_attr; + + length_baton = obstack_alloc (&cu->comp_unit_obstack, + sizeof (*length_baton)); + length_baton->per_cu = cu->per_cu; + length_baton->size = DW_BLOCK (attr)->size + 2; + length_baton->data = obstack_alloc (&cu->comp_unit_obstack, + length_baton->size); + memcpy (length_baton->data, DW_BLOCK (attr)->data, + DW_BLOCK (attr)->size); + + /* DW_AT_BYTE_SIZE existing together with DW_AT_STRING_LENGTH + specifies the size of an integer to fetch. */ + size_attr = dwarf2_attr (die, DW_AT_byte_size, cu); + if (size_attr) + { + length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref_size; + length_baton->data[DW_BLOCK (attr)->size + 1] = + DW_UNSND (size_attr); + if (length_baton->data[DW_BLOCK (attr)->size + 1] + != DW_UNSND (size_attr)) + complaint (&symfile_complaints, + _("DW_AT_string_length's DW_AT_byte_size " + "integer exceeds the byte size storage")); + } + else + { + length_baton->data[DW_BLOCK (attr)->size] = DW_OP_deref; + length_baton->data[DW_BLOCK (attr)->size + 1] = DW_OP_nop; + } + } + + TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1; + TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = length_baton; + TYPE_DYNAMIC (range_type) = 1; + } } else { - /* check for the DW_AT_byte_size attribute */ + if (attr && attr_form_is_constant (attr)) + { + /* We currently do not support a constant address where the location + should be read from - attr_form_is_block is expected instead. See + DWARF for the DW_AT_STRING_LENGTH vs. DW_AT_BYTE_SIZE difference. + */ + /* PASSTHRU */ + } + attr = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr) - { - length = DW_UNSND (attr); - } + if (attr && attr_form_is_block (attr)) + { + TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1; + TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + } + else if (attr && attr_form_is_constant (attr)) + TYPE_HIGH_BOUND (range_type) = dwarf2_get_attr_constant_value (attr, 0); else - { - length = 1; - } + TYPE_HIGH_BOUND (range_type) = 1; } - index_type = objfile_type (objfile)->builtin_int; - range_type = create_range_type (NULL, index_type, 1, length); char_type = language_string_char_type (cu->language_defn, gdbarch); type = create_string_type (NULL, char_type, range_type); @@ -5954,7 +6481,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; @@ -6062,8 +6588,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) struct type *base_type; struct type *range_type; struct attribute *attr; - LONGEST low = 0; - LONGEST high = -1; + LONGEST low; char *name; LONGEST negative_mask; @@ -6077,49 +6602,101 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) 0, NULL, cu->objfile); } - if (cu->language == language_fortran) - { - /* FORTRAN implies a lower bound of 1, if not given. */ - low = 1; - } + /* LOW_BOUND and HIGH_BOUND are set for real below. */ + range_type = create_range_type (NULL, base_type, 0, -1); + + negative_mask = + (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1); - /* FIXME: For variable sized arrays either of these could be - a variable rather than a constant value. We'll allow it, - but we don't know how to handle it. */ attr = dwarf2_attr (die, DW_AT_lower_bound, cu); - if (attr) - low = dwarf2_get_attr_constant_value (attr, 0); + if (attr && attr_form_is_block (attr)) + { + TYPE_LOW_BOUND_IS_DWARF_BLOCK (range_type) = 1; + TYPE_RANGE_DATA (range_type)->low.u.dwarf_block = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + /* For setting a default if DW_AT_UPPER_BOUND would be missing. */ + low = 0; + } + else + { + if (attr && attr_form_is_constant (attr)) + low = dwarf2_get_attr_constant_value (attr, 0); + else + { + if (cu->language == language_fortran) + { + /* FORTRAN implies a lower bound of 1, if not given. */ + low = 1; + } + else + { + /* According to DWARF we should assume the value 0 only for + LANGUAGE_C and LANGUAGE_CPLUS. */ + low = 0; + } + } + if (!TYPE_UNSIGNED (base_type) && (low & negative_mask)) + low |= negative_mask; + TYPE_LOW_BOUND (range_type) = low; + if (low >= 0) + TYPE_UNSIGNED (range_type) = 1; + } attr = dwarf2_attr (die, DW_AT_upper_bound, cu); - if (attr) - { - if (attr->form == DW_FORM_block1) - { - /* GCC encodes arrays with unspecified or dynamic length - with a DW_FORM_block1 attribute. - FIXME: GDB does not yet know how to handle dynamic - arrays properly, treat them as arrays with unspecified - length for now. - - FIXME: jimb/2003-09-22: GDB does not really know - how to handle arrays of unspecified length - either; we just represent them as zero-length - arrays. Choose an appropriate upper bound given - the lower bound we've computed above. */ - high = low - 1; - } - else - high = dwarf2_get_attr_constant_value (attr, 1); + if (!attr || (!attr_form_is_block (attr) && !attr_form_is_constant (attr))) + { + attr = dwarf2_attr (die, DW_AT_count, cu); + /* It does not hurt but it is needlessly ineffective in check_typedef. */ + if (attr && (attr_form_is_block (attr) || attr_form_is_constant (attr))) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1; + TYPE_DYNAMIC (range_type) = 1; + } + /* Pass it now as the regular DW_AT_upper_bound. */ } - negative_mask = - (LONGEST) -1 << (TYPE_LENGTH (base_type) * TARGET_CHAR_BIT - 1); - if (!TYPE_UNSIGNED (base_type) && (low & negative_mask)) - low |= negative_mask; - if (!TYPE_UNSIGNED (base_type) && (high & negative_mask)) - high |= negative_mask; + if (attr && attr_form_is_block (attr)) + { + TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) = 1; + TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + } + else + { + if (attr && attr_form_is_constant (attr)) + { + LONGEST high; - range_type = create_range_type (NULL, base_type, low, high); + high = dwarf2_get_attr_constant_value (attr, 0); + if (!TYPE_UNSIGNED (base_type) && (high & negative_mask)) + high |= negative_mask; + TYPE_HIGH_BOUND (range_type) = high; + } + else + { + TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; + TYPE_HIGH_BOUND (range_type) = low - 1; + } + } + + /* DW_AT_bit_stride is currently unsupported as we count in bytes. */ + attr = dwarf2_attr (die, DW_AT_byte_stride, cu); + if (attr && attr_form_is_block (attr)) + { + TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (range_type) = 1; + TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_block = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + } + else if (attr && attr_form_is_constant (attr)) + { + TYPE_BYTE_STRIDE (range_type) = dwarf2_get_attr_constant_value (attr, 0); + if (TYPE_BYTE_STRIDE (range_type) == 0) + complaint (&symfile_complaints, + _("Found DW_AT_byte_stride with unsupported value 0")); + } name = dwarf2_name (die, cu); if (name) @@ -6578,6 +7155,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. */ @@ -6786,8 +7364,8 @@ read_partial_die (struct partial_die_info *part_die, } break; case DW_AT_MIPS_linkage_name: - part_die->name = DW_STRING (&attr); - break; + if (cu->language == language_ada) + part_die->name = DW_STRING (&attr); case DW_AT_low_pc: has_low_pc_attr = 1; part_die->lowpc = DW_ADDR (&attr); @@ -6984,7 +7562,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; @@ -8326,10 +8905,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 @@ -8351,21 +8932,29 @@ 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), 0, objfile); + + /* Cache this symbol's name and the name's demangled form (if any). */ + + linkagename = dwarf2_physname (die, cu); + SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), 0, objfile); + if (cu->language == language_fortran) + { + SYMBOL_CPLUS_DEMANGLED_NAME (sym) = SYMBOL_LINKAGE_NAME (sym); + SYMBOL_LINKAGE_NAME (sym) = fortran_module_linkage_name (die, cu); + } /* Default assumptions. Use the passed type or decode it from the die. */ @@ -8465,7 +9054,18 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) var_decode_location (attr, sym, cu); attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0)) - add_symbol_to_list (sym, &global_symbols); + { + /* Workaround gfortran PR debug/40040 - it uses + DW_AT_location for variables in -fPIC libraries which may + get overriden by other libraries/executable and get + a different address. Resolve it by .dynsym instead. */ + + if (cu->language == language_fortran && die->parent + && die->parent->tag == DW_TAG_module) + SYMBOL_CLASS (sym) = LOC_UNRESOLVED; + + add_symbol_to_list (sym, &global_symbols); + } else add_symbol_to_list (sym, cu->list_in_scope); } @@ -8602,7 +9202,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) { @@ -8626,6 +9226,11 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) SYMBOL_CLASS (sym) = LOC_TYPEDEF; add_symbol_to_list (sym, &global_symbols); break; + case DW_TAG_module: + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_DOMAIN (sym) = MODULE_DOMAIN; + add_symbol_to_list (sym, &global_symbols); + break; default: /* Not a tag we recognize. Hopefully we aren't processing trash data, but since we must specifically ignore things @@ -8639,8 +9244,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); @@ -8952,12 +9556,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; } @@ -9039,10 +9649,103 @@ 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; + char *name; + + /* 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); + } + } + + name = ui_file_obsavestring (buf, &cu->objfile->objfile_obstack, &length); + ui_file_delete (buf); + return name; +} + +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)"; + /* G++ 4.1 produced DW_TAG_namespace with DW_AT_name "::". */ + else if (strcmp (name, "::") == 0) + name = NULL; + 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, @@ -9092,17 +9795,111 @@ sibling_die (struct die_info *die) return die->sibling; } -/* Get linkage name of a die, return NULL if not found. */ +/* Construct a physname for the given DIE in CU. */ static char * -dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) +dwarf2_physname (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); + + 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; + } + } - attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); - if (attr && DW_STRING (attr)) - return DW_STRING (attr); - return dwarf2_name (die, cu); + return name; +} + +/* Return the fully qualified .symtab name for symbols contained in Fortran + modules. Return DWARF2_NAME otherwise. */ + +static char * +fortran_module_linkage_name (struct die_info *die, struct dwarf2_cu *cu) +{ + char *name; + + gdb_assert (cu->language == language_fortran); + + name = dwarf2_name (die, cu); + + if (name && die->parent && die->parent->tag == DW_TAG_module) + { + char *module_name = dwarf2_name (die->parent, cu); + + if (module_name) + { + char *retval; + + /* `__modulename_MOD_variablename0'. */ + retval = obstack_alloc (&cu->objfile->objfile_obstack, + 2 + strlen (module_name) + 5 + strlen (name) + + 1); + sprintf (retval, "__%s_MOD_%s", module_name, name); + + return retval; + } + } + + return name; } /* Get name of a die, return NULL if not found. */ @@ -11450,6 +12247,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) @@ -11479,35 +12304,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; } } @@ -11795,6 +12610,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. */ @@ -11803,6 +12643,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) { struct dwarf2_offset_and_type **slot, ofs; + fetch_die_type_attrs (die, type, cu); + /* For Ada types, make sure that the gnat-specific data is always initialized (if not already set). There are a few types where we should not be doing so, because the type-specific area is @@ -11958,23 +12800,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. */ @@ -11983,15 +12815,15 @@ static void dwarf2_per_objfile_free (struct objfile *objfile, void *d) { struct dwarf2_per_objfile *data = d; - munmap_section_buffer (&data->info); - munmap_section_buffer (&data->abbrev); - munmap_section_buffer (&data->line); - munmap_section_buffer (&data->str); - munmap_section_buffer (&data->macinfo); - munmap_section_buffer (&data->ranges); - munmap_section_buffer (&data->loc); - munmap_section_buffer (&data->frame); - munmap_section_buffer (&data->eh_frame); + destroy_section (&data->info); + destroy_section (&data->abbrev); + destroy_section (&data->line); + destroy_section (&data->str); + destroy_section (&data->macinfo); + destroy_section (&data->ranges); + destroy_section (&data->loc); + destroy_section (&data->frame); + destroy_section (&data->eh_frame); } void _initialize_dwarf2_read (void); @@ -11999,6 +12831,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 (NULL, dwarf2_per_objfile_free); diff --git a/gdb/elfread.c b/gdb/elfread.c index 78e9163..4e208d1 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -879,20 +879,13 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) str_sect->filepos, bfd_section_size (abfd, str_sect)); } - if (dwarf2_has_info (objfile)) - { - /* DWARF 2 sections */ - dwarf2_build_psymtabs (objfile); - } - - /* FIXME: kettenis/20030504: This still needs to be integrated with - dwarf2read.c in a better way. */ - dwarf2_build_frame_info (objfile); + if (dwarf2_has_info (objfile)) + dwarf2_create_quick_addrmap (objfile); /* If the file has its own symbol tables it has no separate debug info. `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS. `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */ - if (!objfile_has_partial_symbols (objfile)) + else { char *debugfile; @@ -910,6 +903,20 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) } } +static void +read_psyms (struct objfile *objfile) +{ + if (dwarf2_has_info (objfile)) + { + /* DWARF 2 sections */ + dwarf2_build_psymtabs (objfile); + } + + /* FIXME: kettenis/20030504: This still needs to be integrated with + dwarf2read.c in a better way. */ + dwarf2_build_frame_info (objfile); +} + /* This cleans up the objfile's deprecated_sym_stab_info pointer, and the chain of stab_section_info's, that might be dangling from it. */ @@ -1052,6 +1059,7 @@ static struct sym_fns elf_sym_fns = elf_new_init, /* sym_new_init: init anything gbl to entire symtab */ elf_symfile_init, /* sym_init: read initial info, setup for sym_read() */ elf_symfile_read, /* sym_read: read a symbol file into symtab */ + read_psyms, /* sym_read_psymbols */ elf_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ elf_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/eval.c b/gdb/eval.c index 27b7895..90c29a3 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -43,6 +43,7 @@ #include "gdb_obstack.h" #include "objfiles.h" #include "python/python.h" +#include "dwarf2loc.h" #include "gdb_assert.h" @@ -696,6 +697,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; @@ -1332,7 +1334,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)++; @@ -1356,21 +1357,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) { @@ -1496,8 +1516,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) { @@ -1588,6 +1607,8 @@ evaluate_subexp_standard (struct type *expect_type, /* First determine the type code we are dealing with. */ arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (value_raw_address (arg1)); type = check_typedef (value_type (arg1)); code = TYPE_CODE (type); @@ -1608,6 +1629,7 @@ evaluate_subexp_standard (struct type *expect_type, code = TYPE_CODE (type); } } + do_cleanups (old_chain); switch (code) { @@ -1769,6 +1791,27 @@ evaluate_subexp_standard (struct type *expect_type, xfree (expect_type); return arg1; + 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); @@ -2040,13 +2083,19 @@ evaluate_subexp_standard (struct type *expect_type, { int subscript_array[MAX_FORTRAN_DIMS]; int array_size_array[MAX_FORTRAN_DIMS]; + int byte_stride_array[MAX_FORTRAN_DIMS]; int ndimensions = 1, i; struct type *tmp_type; int offset_item; /* The array offset where the item lives */ + CORE_ADDR offset_byte; /* byte_stride based offset */ + unsigned element_size; if (nargs > MAX_FORTRAN_DIMS) error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS); + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (value_raw_address (arg1)); + tmp_type = check_typedef (value_type (arg1)); ndimensions = calc_f77_array_dims (type); @@ -2076,6 +2125,9 @@ evaluate_subexp_standard (struct type *expect_type, upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); + byte_stride_array[nargs - i - 1] = + TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); + array_size_array[nargs - i - 1] = upper - lower + 1; /* Zero-normalize subscripts so that offsetting will work. */ @@ -2094,13 +2146,25 @@ evaluate_subexp_standard (struct type *expect_type, tmp_type = check_typedef (TYPE_TARGET_TYPE (tmp_type)); } + /* Kept for the f77_get_upperbound / f77_get_lowerbound calls above. */ + do_cleanups (old_chain); + /* Now let us calculate the offset for this item */ - offset_item = subscript_array[ndimensions - 1]; + offset_item = 0; + offset_byte = 0; + + for (i = ndimensions - 1; i >= 0; --i) + { + offset_item *= array_size_array[i]; + if (byte_stride_array[i] == 0) + offset_item += subscript_array[i]; + else + offset_byte += subscript_array[i] * byte_stride_array[i]; + } - for (i = ndimensions - 1; i > 0; --i) - offset_item = - array_size_array[i - 1] * offset_item + subscript_array[i - 1]; + element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (tmp_type)); + offset_byte += offset_item * element_size; /* Let us now play a dirty trick: we will take arg1 which is a value node pointing to the topmost level @@ -2110,7 +2174,7 @@ evaluate_subexp_standard (struct type *expect_type, returns the correct type value */ deprecated_set_value_type (arg1, tmp_type); - return value_subscripted_rvalue (arg1, offset_item, 0); + return value_subscripted_rvalue (arg1, offset_byte); } case BINOP_LOGICAL_AND: @@ -2344,14 +2408,22 @@ evaluate_subexp_standard (struct type *expect_type, if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR) expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type)); arg1 = evaluate_subexp (expect_type, exp, pos, noside); + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (value_raw_address (arg1)); type = check_typedef (value_type (arg1)); if (TYPE_CODE (type) == TYPE_CODE_METHODPTR || TYPE_CODE (type) == TYPE_CODE_MEMBERPTR) error (_("Attempt to dereference pointer to member without an object")); if (noside == EVAL_SKIP) - goto nosideret; + { + do_cleanups (old_chain); + goto nosideret; + } if (unop_user_defined_p (op, arg1)) - return value_x_unop (arg1, op, noside); + { + do_cleanups (old_chain); + return value_x_unop (arg1, op, noside); + } else if (noside == EVAL_AVOID_SIDE_EFFECTS) { type = check_typedef (value_type (arg1)); @@ -2360,12 +2432,18 @@ evaluate_subexp_standard (struct type *expect_type, /* In C you can dereference an array to get the 1st elt. */ || TYPE_CODE (type) == TYPE_CODE_ARRAY ) - return value_zero (TYPE_TARGET_TYPE (type), - lval_memory); + { + do_cleanups (old_chain); + return value_zero (TYPE_TARGET_TYPE (type), + lval_memory); + } else if (TYPE_CODE (type) == TYPE_CODE_INT) - /* GDB allows dereferencing an int. */ - return value_zero (builtin_type (exp->gdbarch)->builtin_int, - lval_memory); + { + do_cleanups (old_chain); + /* GDB allows dereferencing an int. */ + return value_zero (builtin_type (exp->gdbarch)->builtin_int, + lval_memory); + } else error (_("Attempt to take contents of a non-pointer value.")); } @@ -2375,9 +2453,14 @@ evaluate_subexp_standard (struct type *expect_type, do. "long long" variables are rare enough that BUILTIN_TYPE_LONGEST would seem to be a mistake. */ if (TYPE_CODE (type) == TYPE_CODE_INT) - return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int, - (CORE_ADDR) value_as_address (arg1)); - return value_ind (arg1); + { + do_cleanups (old_chain); + return value_at_lazy (builtin_type (exp->gdbarch)->builtin_int, + (CORE_ADDR) value_as_address (arg1)); + } + arg1 = value_ind (arg1); + do_cleanups (old_chain); + return arg1; case UNOP_ADDR: /* C++: check for and handle pointer to members. */ @@ -2712,7 +2795,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; @@ -2723,12 +2806,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); } @@ -2780,9 +2868,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 ca216cf..2195fef 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -95,6 +95,11 @@ enum exp_opcode 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 */ @@ -451,4 +456,5 @@ extern char *op_string (enum exp_opcode); extern void dump_raw_expression (struct expression *, struct ui_file *, char *); extern void dump_prefix_expression (struct expression *, struct ui_file *); + #endif /* !defined (EXPRESSION_H) */ diff --git a/gdb/f-lang.c b/gdb/f-lang.c index b914b49..67c7232 100644 --- a/gdb/f-lang.c +++ b/gdb/f-lang.c @@ -31,6 +31,8 @@ #include "f-lang.h" #include "valprint.h" #include "value.h" +#include "block.h" +#include "gdb_assert.h" /* Following is dubious stuff that had been in the xcoff reader. */ @@ -306,6 +308,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 +375,7 @@ const struct language_defn f_language_defn = c_value_print, /* FIXME */ NULL, /* Language specific skip_trampoline */ NULL, /* name_of_this */ - basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ + f_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */ basic_lookup_transparent_type,/* lookup_transparent_type */ NULL, /* Language specific symbol demangler */ NULL, /* Language specific class_name_from_physname */ diff --git a/gdb/f-lang.h b/gdb/f-lang.h index b98c556..c68379a 100644 --- a/gdb/f-lang.h +++ b/gdb/f-lang.h @@ -28,6 +28,10 @@ extern void f_error (char *); /* Defined in f-exp.y */ extern void f_print_type (struct type *, char *, struct ui_file *, int, int); +extern const char *f_object_address_data_valid_print_to_stream + (struct type *type, struct ui_file *stream); +extern void f_object_address_data_valid_or_error (struct type *type); + extern int f_val_print (struct type *, const gdb_byte *, int, CORE_ADDR, struct ui_file *, int, const struct value_print_options *); @@ -125,3 +129,10 @@ struct builtin_f_type /* Return the Fortran type table for the specified architecture. */ extern const struct builtin_f_type *builtin_f_type (struct gdbarch *gdbarch); +/* List of module names being imported by a block though BLOCK_FORTRAN_USE. */ + +struct fortran_using + { + struct fortran_using *next; + char module_name[1]; + }; diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c index 0332932..6e8668c 100644 --- a/gdb/f-typeprint.c +++ b/gdb/f-typeprint.c @@ -32,7 +32,7 @@ #include "gdbcore.h" #include "target.h" #include "f-lang.h" - +#include "dwarf2loc.h" #include "gdb_string.h" #include @@ -49,6 +49,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *, void f_type_print_base (struct type *, struct ui_file *, int, int); +const char * +f_object_address_data_valid_print_to_stream (struct type *type, + struct ui_file *stream) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + /* Assuming the content printed to STREAM should not be localized. */ + fprintf_filtered (stream, "<%s>", msg); + } + + return msg; +} + +void +f_object_address_data_valid_or_error (struct type *type) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + error (_("Cannot access it because the %s."), _(msg)); + } +} + /* LEVEL is the depth to indent lines by. */ void @@ -58,6 +86,9 @@ f_print_type (struct type *type, char *varstring, struct ui_file *stream, enum type_code code; int demangled_args; + if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) + return; + f_type_print_base (type, stream, show, level); code = TYPE_CODE (type); if ((varstring != NULL && *varstring != '\0') @@ -165,6 +196,9 @@ f_type_print_varspec_suffix (struct type *type, struct ui_file *stream, QUIT; + if (TYPE_CODE (type) != TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: diff --git a/gdb/f-valprint.c b/gdb/f-valprint.c index 9bd3640..f52b858 100644 --- a/gdb/f-valprint.c +++ b/gdb/f-valprint.c @@ -54,15 +54,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2]; /* The following macro gives us the size of the nth dimension, Where n is 1 based. */ -#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1]) +#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1]) -/* The following gives us the offset for row n where n is 1-based. */ +/* The following gives us the element size for row n where n is 1-based. */ -#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0]) +#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0]) int f77_get_lowerbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type)) error (_("Lower bound may not be '*' in F77")); @@ -72,14 +74,17 @@ f77_get_lowerbound (struct type *type) int f77_get_upperbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) { - /* We have an assumed size array on our hands. Assume that - upper_bound == lower_bound so that we show at least 1 element. - If the user wants to see more elements, let him manually ask for 'em - and we'll subscript the array and show him. */ + /* We have an assumed size array on our hands. As type_length_get + already assumes a length zero of arrays with underfined bounds VALADDR + passed to the Fortran functions does not contained the real inferior + memory content. User should request printing of specific array + elements instead. */ - return f77_get_lowerbound (type); + return f77_get_lowerbound (type) - 1; } return TYPE_ARRAY_UPPER_BOUND_VALUE (type); @@ -135,24 +140,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream) upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); - F77_DIM_SIZE (ndimen) = upper - lower + 1; + F77_DIM_COUNT (ndimen) = upper - lower + 1; + + F77_DIM_BYTE_STRIDE (ndimen) = + TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); tmp_type = TYPE_TARGET_TYPE (tmp_type); ndimen++; } - /* Now we multiply eltlen by all the offsets, so that later we + /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we can print out array elements correctly. Up till now we - know an offset to apply to get the item but we also + know an eltlen to apply to get the item but we also have to know how much to add to get to the next item */ ndimen--; eltlen = TYPE_LENGTH (tmp_type); - F77_DIM_OFFSET (ndimen) = eltlen; + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; while (--ndimen > 0) { - eltlen *= F77_DIM_SIZE (ndimen + 1); - F77_DIM_OFFSET (ndimen) = eltlen; + eltlen *= F77_DIM_COUNT (ndimen + 1); + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; } } @@ -172,34 +182,34 @@ f77_print_array_1 (int nss, int ndimensions, struct type *type, if (nss != ndimensions) { - for (i = 0; (i < F77_DIM_SIZE (nss) && (*elts) < options->print_max); i++) + for (i = 0; (i < F77_DIM_COUNT (nss) && (*elts) < options->print_max); i++) { fprintf_filtered (stream, "( "); f77_print_array_1 (nss + 1, ndimensions, TYPE_TARGET_TYPE (type), - valaddr + i * F77_DIM_OFFSET (nss), - address + i * F77_DIM_OFFSET (nss), + valaddr + i * F77_DIM_BYTE_STRIDE (nss), + address + i * F77_DIM_BYTE_STRIDE (nss), stream, recurse, options, elts); fprintf_filtered (stream, ") "); } - if (*elts >= options->print_max && i < F77_DIM_SIZE (nss)) + if (*elts >= options->print_max && i < F77_DIM_COUNT (nss)) fprintf_filtered (stream, "..."); } else { - for (i = 0; i < F77_DIM_SIZE (nss) && (*elts) < options->print_max; + for (i = 0; i < F77_DIM_COUNT (nss) && (*elts) < options->print_max; i++, (*elts)++) { val_print (TYPE_TARGET_TYPE (type), - valaddr + i * F77_DIM_OFFSET (ndimensions), + valaddr + i * F77_DIM_BYTE_STRIDE (ndimensions), 0, - address + i * F77_DIM_OFFSET (ndimensions), + address + i * F77_DIM_BYTE_STRIDE (ndimensions), stream, recurse, options, current_language); - if (i != (F77_DIM_SIZE (nss) - 1)) + if (i != (F77_DIM_COUNT (nss) - 1)) fprintf_filtered (stream, ", "); if ((*elts == options->print_max - 1) - && (i != (F77_DIM_SIZE (nss) - 1))) + && (i != (F77_DIM_COUNT (nss) - 1))) fprintf_filtered (stream, "..."); } } @@ -253,6 +263,9 @@ f_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset, CORE_ADDR addr; int index; + if (f_object_address_data_valid_print_to_stream (type, stream) != NULL) + return 0; + CHECK_TYPEDEF (type); switch (TYPE_CODE (type)) { diff --git a/gdb/findcmd.c b/gdb/findcmd.c index c752316..df2687c 100644 --- a/gdb/findcmd.c +++ b/gdb/findcmd.c @@ -27,7 +27,7 @@ /* Copied from bfd_put_bits. */ -static void +void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) { int i; @@ -45,6 +45,41 @@ put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p) } } +/* Allocates a buffer in *PATTERN_BUF, with a hard-coded initial size which + will be returned in *PATTERN_BUF_SIZE. *PATTERN_BUF_END points to the same + place as *PATTERN_BUF, indicating that the buffer is initially empty. */ + +void +allocate_pattern_buffer (char **pattern_buf, char **pattern_buf_end, + ULONGEST *pattern_buf_size) +{ +#define INITIAL_PATTERN_BUF_SIZE 100 + *pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; + *pattern_buf = xmalloc (*pattern_buf_size); + *pattern_buf_end = *pattern_buf; +} + +/* Grows *PATTERN_BUF by a factor of two if it's not large enough to hold + VAL_BYTES more bytes or a 64-bit value, whichever is larger. + *PATTERN_BUF_END is updated as necessary. */ + +void +increase_pattern_buffer (char **pattern_buf, char **pattern_buf_end, + ULONGEST *pattern_buf_size, int val_bytes) +{ + /* Keep it simple and assume size == 'g' when watching for when we + need to grow the pattern buf. */ + if ((*pattern_buf_end - *pattern_buf + max (val_bytes, sizeof (int64_t))) + > *pattern_buf_size) + { + size_t current_offset = *pattern_buf_end - *pattern_buf; + + *pattern_buf_size *= 2; + *pattern_buf = xrealloc (*pattern_buf, *pattern_buf_size); + *pattern_buf_end = *pattern_buf + current_offset; + } +} + /* Subroutine of find_command to simplify it. Parse the arguments of the "find" command. */ @@ -61,8 +96,7 @@ parse_find_args (char *args, ULONGEST *max_countp, char *pattern_buf; /* Current size of search pattern buffer. We realloc space as needed. */ -#define INITIAL_PATTERN_BUF_SIZE 100 - ULONGEST pattern_buf_size = INITIAL_PATTERN_BUF_SIZE; + ULONGEST pattern_buf_size; /* Pointer to one past the last in-use part of pattern_buf. */ char *pattern_buf_end; ULONGEST pattern_len; @@ -75,8 +109,7 @@ parse_find_args (char *args, ULONGEST *max_countp, if (args == NULL) error (_("Missing search parameters.")); - pattern_buf = xmalloc (pattern_buf_size); - pattern_buf_end = pattern_buf; + allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); old_cleanups = make_cleanup (free_current_contents, &pattern_buf); /* Get search granularity and/or max count if specified. @@ -173,16 +206,8 @@ parse_find_args (char *args, ULONGEST *max_countp, v = parse_to_comma_and_eval (&s); val_bytes = TYPE_LENGTH (value_type (v)); - /* Keep it simple and assume size == 'g' when watching for when we - need to grow the pattern buf. */ - if ((pattern_buf_end - pattern_buf + max (val_bytes, sizeof (int64_t))) - > pattern_buf_size) - { - size_t current_offset = pattern_buf_end - pattern_buf; - pattern_buf_size *= 2; - pattern_buf = xrealloc (pattern_buf, pattern_buf_size); - pattern_buf_end = pattern_buf + current_offset; - } + increase_pattern_buffer (&pattern_buf, &pattern_buf_end, + &pattern_buf_size, val_bytes); if (size != '\0') { @@ -237,6 +262,45 @@ parse_find_args (char *args, ULONGEST *max_countp, discard_cleanups (old_cleanups); } +/* Drives target_search_memory to sweep through the specified search space, + possibly in several iterations (with one call to this function for each + iteration). *START_ADDR is the address where the search starts, and is + updated to the next starting address to continue the search. + *SEARCH_SPACE_LEN is the amount of bytes which will be searched, and is + updated for the next iteration. PATTERN_BUF holds the pattern to be searched + for, PATTERN_LEN is the size of the pattern in bytes. If a match is found, + it's address is put in *FOUND_ADDR. + + Returns 1 if found, 0 if not found, and -1 if there was an error requiring + halting of the search (e.g. memory read error). */ + +int +search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, + const char *pattern_buf, ULONGEST pattern_len, + CORE_ADDR *found_addr) +{ + /* Offset from start of this iteration to the next iteration. */ + ULONGEST next_iter_incr; + int found; + + found = target_search_memory (*start_addr, *search_space_len, + pattern_buf, pattern_len, found_addr); + if (found <= 0) + return found; + + /* Begin next iteration at one byte past this match. */ + next_iter_incr = (*found_addr - *start_addr) + 1; + + /* For robustness, we don't let search_space_len go -ve here. */ + if (*search_space_len >= next_iter_incr) + *search_space_len -= next_iter_incr; + else + *search_space_len = 0; + *start_addr += next_iter_incr; + + return found; +} + static void find_command (char *args, int from_tty) { @@ -267,12 +331,11 @@ find_command (char *args, int from_tty) while (search_space_len >= pattern_len && found_count < max_count) { - /* Offset from start of this iteration to the next iteration. */ - ULONGEST next_iter_incr; CORE_ADDR found_addr; - int found = target_search_memory (start_addr, search_space_len, - pattern_buf, pattern_len, &found_addr); + int found; + found = search_memory (&start_addr, &search_space_len, pattern_buf, + pattern_len, &found_addr); if (found <= 0) break; @@ -280,16 +343,6 @@ find_command (char *args, int from_tty) printf_filtered ("\n"); ++found_count; last_found_addr = found_addr; - - /* Begin next iteration at one byte past this match. */ - next_iter_incr = (found_addr - start_addr) + 1; - - /* For robustness, we don't let search_space_len go -ve here. */ - if (search_space_len >= next_iter_incr) - search_space_len -= next_iter_incr; - else - search_space_len = 0; - start_addr += next_iter_incr; } /* Record and print the results. */ diff --git a/gdb/findvar.c b/gdb/findvar.c index e117a8e..6bd3724 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -35,6 +35,7 @@ #include "user-regs.h" #include "block.h" #include "objfiles.h" +#include "dwarf2loc.h" /* Basic byte-swapping routines. All 'extract' functions return a host-format integer from a target-format integer at ADDR which is @@ -397,27 +398,16 @@ symbol_read_needs_frame (struct symbol *sym) /* Given a struct symbol for a variable, and a stack frame id, read the value of the variable and return a (pointer to a) struct value containing the value. - If the variable cannot be found, return a zero pointer. */ + If the variable cannot be found, return a zero pointer. + We have to first find the address of the variable before allocating struct + value to return as its size may depend on DW_OP_PUSH_OBJECT_ADDRESS possibly + used by its type. */ struct value * read_var_value (struct symbol *var, struct frame_info *frame) { - struct value *v; struct type *type = SYMBOL_TYPE (var); CORE_ADDR addr; - int len; - - if (SYMBOL_CLASS (var) == LOC_COMPUTED - || SYMBOL_CLASS (var) == LOC_REGISTER) - /* These cases do not use V. */ - v = NULL; - else - { - v = allocate_value (type); - VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ - } - - len = TYPE_LENGTH (type); if (symbol_read_needs_frame (var)) gdb_assert (frame); @@ -425,32 +415,40 @@ read_var_value (struct symbol *var, struct frame_info *frame) switch (SYMBOL_CLASS (var)) { case LOC_CONST: - /* Put the constant back in target format. */ - store_signed_integer (value_contents_raw (v), len, - gdbarch_byte_order (get_type_arch (type)), - (LONGEST) SYMBOL_VALUE (var)); - VALUE_LVAL (v) = not_lval; - return v; + { + /* Put the constant back in target format. */ + struct value *v = allocate_value (type); + VALUE_LVAL (v) = not_lval; + store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type), + gdbarch_byte_order (get_type_arch (type)), + (LONGEST) SYMBOL_VALUE (var)); + return v; + } case LOC_LABEL: - /* Put the constant back in target format. */ - if (overlay_debugging) - { - CORE_ADDR addr - = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), - SYMBOL_OBJ_SECTION (var)); - store_typed_address (value_contents_raw (v), type, addr); - } - else - store_typed_address (value_contents_raw (v), type, - SYMBOL_VALUE_ADDRESS (var)); - VALUE_LVAL (v) = not_lval; - return v; + { + /* Put the constant back in target format. */ + struct value *v = allocate_value (type); + VALUE_LVAL (v) = not_lval; + if (overlay_debugging) + { + CORE_ADDR addr + = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), + SYMBOL_OBJ_SECTION (var)); + store_typed_address (value_contents_raw (v), type, addr); + } + else + store_typed_address (value_contents_raw (v), type, + SYMBOL_VALUE_ADDRESS (var)); + return v; + } case LOC_CONST_BYTES: { - memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len); + struct value *v = allocate_value (type); VALUE_LVAL (v) = not_lval; + memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), + TYPE_LENGTH (type)); return v; } @@ -492,12 +490,23 @@ read_var_value (struct symbol *var, struct frame_info *frame) break; case LOC_BLOCK: - if (overlay_debugging) - set_value_address (v, symbol_overlayed_address - (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var))); - else - set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (var))); - return v; + { + CORE_ADDR addr; + struct value *v; + + if (overlay_debugging) + addr = symbol_overlayed_address + (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); + else + addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for + DW_OP_push_object_address. */ + object_address_set (addr); + v = allocate_value (type); + VALUE_LVAL (v) = lval_memory; + set_value_address (v, addr); + return v; + } case LOC_REGISTER: case LOC_REGPARM_ADDR: @@ -516,7 +525,6 @@ read_var_value (struct symbol *var, struct frame_info *frame) error (_("Value of register variable not available.")); addr = value_as_address (regval); - VALUE_LVAL (v) = lval_memory; } else { @@ -559,18 +567,33 @@ read_var_value (struct symbol *var, struct frame_info *frame) break; case LOC_OPTIMIZED_OUT: - VALUE_LVAL (v) = not_lval; - set_value_optimized_out (v, 1); - return v; + { + struct value *v = allocate_value (type); + + VALUE_LVAL (v) = not_lval; + set_value_optimized_out (v, 1); + return v; + } default: error (_("Cannot look up value of a botched symbol.")); break; } - set_value_address (v, addr); - set_value_lazy (v, 1); - return v; + { + struct value *v; + + /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for + DW_OP_PUSH_OBJECT_ADDRESS. */ + object_address_set (addr); + v = allocate_value (type); + VALUE_LVAL (v) = lval_memory; + set_value_address (v, addr); + + set_value_lazy (v, 1); + + return v; + } } /* Install default attributes for register values. */ @@ -607,10 +630,11 @@ struct value * value_from_register (struct type *type, int regnum, struct frame_info *frame) { struct gdbarch *gdbarch = get_frame_arch (frame); - struct type *type1 = check_typedef (type); struct value *v; - if (gdbarch_convert_register_p (gdbarch, regnum, type1)) + type = check_typedef (type); + + if (gdbarch_convert_register_p (gdbarch, regnum, type)) { /* The ISA/ABI need to something weird when obtaining the specified value from this register. It might need to @@ -624,7 +648,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame) VALUE_FRAME_ID (v) = get_frame_id (frame); VALUE_REGNUM (v) = regnum; gdbarch_register_to_value (gdbarch, - frame, regnum, type1, value_contents_raw (v)); + frame, regnum, type, value_contents_raw (v)); } else { diff --git a/gdb/gdbinit.in b/gdb/gdbinit.in index ffb7f53..a2e7e94 100644 --- a/gdb/gdbinit.in +++ b/gdb/gdbinit.in @@ -1,5 +1,15 @@ echo Setting up the environment for debugging gdb.\n +# Set up the Python library and "require" command. +python +from os.path import abspath +gdb.datadir = abspath ('@srcdir@/python/lib') +gdb.pythonlibdir = gdb.datadir +gdb.__path__ = [gdb.datadir + '/gdb'] +sys.path.insert(0, gdb.datadir) +end +source @srcdir@/python/lib/gdb/__init__.py + set complaints 1 b internal_error diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index cd24eaf..119af7d 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -185,6 +185,10 @@ struct thread_info /* True if this thread has been explicitly requested to stop. */ int stop_requested; + /* The initiating frame of a nexting operation, used for deciding + which exceptions to intercept. */ + struct frame_id initiating_frame; + /* Private data used by the target vector implementation. */ struct private_thread_info *private; @@ -257,6 +261,9 @@ extern struct thread_info *any_live_thread_of_process (int pid); /* Change the ptid of thread OLD_PTID to NEW_PTID. */ void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid); +/* Prune dead threads from the list of threads. */ +extern void prune_threads (void); + /* Iterator function to call a user-provided callback function once for each known thread. */ typedef int (*thread_callback_func) (struct thread_info *, void *); diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 117606a..536bee2 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -39,6 +39,9 @@ #include "cp-abi.h" #include "gdb_assert.h" #include "hashtab.h" +#include "observer.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" /* Floatformat pairs. */ @@ -119,6 +122,24 @@ static void print_arg_types (struct field *, int, int); static void dump_fn_fieldlists (struct type *, int); static void print_cplus_stuff (struct type *, int); +/* A reference count structure for the type reference count map. Each + type in a hierarchy of types is mapped to the same reference + count. */ +struct type_refc_entry +{ + /* One type in the hierarchy. Each type in the hierarchy gets its + own slot. */ + struct type *type; + + /* A pointer to the shared reference count. */ + int *refc; +}; + +/* The hash table holding all discardable `struct type *' references. */ +static htab_t type_discardable_table; + +/* Current type_discardable_check pass used for TYPE_DISCARDABLE_AGE. */ +static int type_discardable_age_current; /* Allocate a new OBJFILE-associated type structure and fill it with some defaults. Space for the type structure is allocated @@ -149,6 +170,39 @@ alloc_type (struct objfile *objfile) return type; } +/* Declare TYPE as discardable on next garbage collection by free_all_types. + You must call type_mark_used during each free_all_types to protect TYPE from + being deallocated. */ + +static void +set_type_as_discardable (struct type *type) +{ + void **slot; + + gdb_assert (!TYPE_DISCARDABLE (type)); + + TYPE_DISCARDABLE (type) = 1; + TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current; + + slot = htab_find_slot (type_discardable_table, type, INSERT); + gdb_assert (!*slot); + *slot = type; +} + +/* Allocate a new type like alloc_type but preserve for it the discardability + state of PARENT_TYPE. */ + +static struct type * +alloc_type_as_parent (struct type *parent_type) +{ + struct type *new_type = alloc_type_copy (parent_type); + + if (TYPE_DISCARDABLE (parent_type)) + set_type_as_discardable (new_type); + + return new_type; +} + /* Allocate a new GDBARCH-associated type structure and fill it with some defaults. Space for the type structure is allocated on the heap. */ @@ -274,7 +328,7 @@ make_pointer_type (struct type *type, struct type **typeptr) if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ { - ntype = alloc_type_copy (type); + ntype = alloc_type_as_parent (type); if (typeptr) *typeptr = ntype; } @@ -351,7 +405,7 @@ make_reference_type (struct type *type, struct type **typeptr) if (typeptr == 0 || *typeptr == 0) /* We'll need to allocate one. */ { - ntype = alloc_type_copy (type); + ntype = alloc_type_as_parent (type); if (typeptr) *typeptr = ntype; } @@ -726,6 +780,7 @@ create_range_type (struct type *result_type, struct type *index_type, TYPE_ZALLOC (result_type, sizeof (struct range_bounds)); TYPE_LOW_BOUND (result_type) = low_bound; TYPE_HIGH_BOUND (result_type) = high_bound; + TYPE_BYTE_STRIDE (result_type) = 0; if (low_bound >= 0) TYPE_UNSIGNED (result_type) = 1; @@ -825,26 +880,45 @@ create_array_type (struct type *result_type, TYPE_CODE (result_type) = TYPE_CODE_ARRAY; TYPE_TARGET_TYPE (result_type) = element_type; - if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) - low_bound = high_bound = 0; - CHECK_TYPEDEF (element_type); - /* Be careful when setting the array length. Ada arrays can be - empty arrays with the high_bound being smaller than the low_bound. - In such cases, the array length should be zero. */ - if (high_bound < low_bound) - TYPE_LENGTH (result_type) = 0; - else - TYPE_LENGTH (result_type) = - TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); TYPE_NFIELDS (result_type) = 1; TYPE_FIELDS (result_type) = (struct field *) TYPE_ZALLOC (result_type, sizeof (struct field)); TYPE_INDEX_TYPE (result_type) = range_type; TYPE_VPTR_FIELDNO (result_type) = -1; - /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */ + /* DWARF blocks may depend on runtime information like + DW_OP_PUSH_OBJECT_ADDRESS not being available during the + CREATE_ARRAY_TYPE time. */ + if (TYPE_LOW_BOUND_IS_DWARF_BLOCK (range_type) + || TYPE_HIGH_BOUND_IS_DWARF_BLOCK (range_type) + || TYPE_LOW_BOUND_UNDEFINED (range_type) + || TYPE_HIGH_BOUND_UNDEFINED (range_type) + || get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) + { + low_bound = 0; + high_bound = -1; + } + + /* Be careful when setting the array length. Ada arrays can be + empty arrays with the high_bound being smaller than the low_bound. + In such cases, the array length should be zero. TYPE_TARGET_STUB needs to + be checked as it may have dependencies on DWARF blocks depending on + runtime information not available during the CREATE_ARRAY_TYPE time. */ + if (high_bound < low_bound || TYPE_TARGET_STUB (element_type)) + TYPE_LENGTH (result_type) = 0; + else + { + CHECK_TYPEDEF (element_type); + TYPE_LENGTH (result_type) = + TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); + } + if (TYPE_LENGTH (result_type) == 0) - TYPE_TARGET_STUB (result_type) = 1; + { + /* The real size will be computed for specific instances by + CHECK_TYPEDEF. */ + TYPE_TARGET_STUB (result_type) = 1; + } return result_type; } @@ -1331,6 +1405,105 @@ stub_noname_complaint (void) complaint (&symfile_complaints, _("stub type has NULL name")); } +/* Calculate the memory length of array TYPE. + + TARGET_TYPE should be set to `check_typedef (TYPE_TARGET_TYPE (type))' as + a performance hint. Feel free to pass NULL. Set FULL_SPAN to return the + size incl. the possible padding of the last element - it may differ from the + cleared FULL_SPAN return value (the expected SIZEOF) for non-zero + TYPE_BYTE_STRIDE values. */ + +static LONGEST +type_length_get (struct type *type, struct type *target_type, int full_span) +{ + struct type *range_type; + LONGEST byte_stride = 0; /* `= 0' for a false GCC warning. */ + LONGEST count, element_size, retval; + + if (TYPE_CODE (type) != TYPE_CODE_ARRAY + && TYPE_CODE (type) != TYPE_CODE_STRING) + return TYPE_LENGTH (type); + + /* Avoid executing TYPE_HIGH_BOUND for invalid (unallocated/unassociated) + Fortran arrays. The allocated data will never be used so they can be + zero-length. */ + if (object_address_data_not_valid (type)) + return 0; + + range_type = TYPE_INDEX_TYPE (type); + if (TYPE_LOW_BOUND_UNDEFINED (range_type) + || TYPE_HIGH_BOUND_UNDEFINED (range_type)) + return 0; + count = TYPE_HIGH_BOUND (range_type) - TYPE_LOW_BOUND (range_type) + 1; + /* It may happen for wrong DWARF annotations returning garbage data. */ + if (count < 0) + warning (_("Range for type %s has invalid bounds %s..%s"), + TYPE_NAME (type), plongest (TYPE_LOW_BOUND (range_type)), + plongest (TYPE_HIGH_BOUND (range_type))); + /* The code below does not handle count == 0 right. */ + if (count <= 0) + return 0; + if (full_span || count > 1) + { + /* We do not use TYPE_ARRAY_BYTE_STRIDE_VALUE (type) here as we want to + force FULL_SPAN to 1. */ + byte_stride = TYPE_BYTE_STRIDE (range_type); + if (byte_stride == 0) + { + if (target_type == NULL) + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + byte_stride = type_length_get (target_type, NULL, 1); + } + } + + /* For now, we conservatively take the array length to be 0 if its length + exceeds UINT_MAX. The code below assumes that for x < 0, + (ULONGEST) x == -x + ULONGEST_MAX + 1, which is technically not guaranteed + by C, but is usually true (because it would be true if x were unsigned + with its high-order bit on). It uses the fact that high_bound-low_bound is + always representable in ULONGEST and that if high_bound-low_bound+1 + overflows, it overflows to 0. We must change these tests if we decide to + increase the representation of TYPE_LENGTH from unsigned int to ULONGEST. + */ + + if (full_span) + { + retval = count * byte_stride; + if (count == 0 || retval / count != byte_stride || retval > UINT_MAX) + retval = 0; + return retval; + } + if (target_type == NULL) + target_type = check_typedef (TYPE_TARGET_TYPE (type)); + element_size = type_length_get (target_type, NULL, 1); + retval = (count - 1) * byte_stride + element_size; + if (retval < element_size + || (byte_stride != 0 + && (retval - element_size) / byte_stride != count - 1) + || retval > UINT_MAX) + retval = 0; + return retval; +} + +/* Prepare TYPE after being read in by the backend. Currently this function + only propagates the TYPE_DYNAMIC flag. */ + +void +finalize_type (struct type *type) +{ + int i; + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + if (TYPE_FIELD_TYPE (type, i) && TYPE_DYNAMIC (TYPE_FIELD_TYPE (type, i))) + break; + + /* FIXME: cplus_stuff is ignored here. */ + if (i < TYPE_NFIELDS (type) + || (TYPE_VPTR_BASETYPE (type) && TYPE_DYNAMIC (TYPE_VPTR_BASETYPE (type))) + || (TYPE_TARGET_TYPE (type) && TYPE_DYNAMIC (TYPE_TARGET_TYPE (type)))) + TYPE_DYNAMIC (type) = 1; +} + /* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989. If this is a stubbed struct (i.e. declared as struct foo *), see if @@ -1462,51 +1635,36 @@ check_typedef (struct type *type) } } - if (TYPE_TARGET_STUB (type)) + /* copy_type_recursive automatically makes the resulting type containing only + constant values expected by the callers of this function. */ + if (TYPE_DYNAMIC (type)) + { + htab_t copied_types; + struct type *type_old = type; + + copied_types = create_copied_types_hash (NULL); + type = copy_type_recursive (type, copied_types); + htab_delete (copied_types); + + gdb_assert (TYPE_DYNAMIC (type) == 0); + } + + if (TYPE_TARGET_STUB (type) || TYPE_DYNAMIC (type)) { - struct type *range_type; struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type)); + if (TYPE_DYNAMIC (type)) + TYPE_TARGET_TYPE (type) = target_type; if (TYPE_STUB (target_type) || TYPE_TARGET_STUB (target_type)) { /* Empty. */ } else if (TYPE_CODE (type) == TYPE_CODE_ARRAY - && TYPE_NFIELDS (type) == 1 - && (TYPE_CODE (range_type = TYPE_INDEX_TYPE (type)) - == TYPE_CODE_RANGE)) + || TYPE_CODE (type) == TYPE_CODE_STRING) { /* Now recompute the length of the array type, based on its - number of elements and the target type's length. - Watch out for Ada null Ada arrays where the high bound - is smaller than the low bound. */ - const LONGEST low_bound = TYPE_LOW_BOUND (range_type); - const LONGEST high_bound = TYPE_HIGH_BOUND (range_type); - ULONGEST len; - - if (high_bound < low_bound) - len = 0; - else { - /* For now, we conservatively take the array length to be 0 - if its length exceeds UINT_MAX. The code below assumes - that for x < 0, (ULONGEST) x == -x + ULONGEST_MAX + 1, - which is technically not guaranteed by C, but is usually true - (because it would be true if x were unsigned with its - high-order bit on). It uses the fact that - high_bound-low_bound is always representable in - ULONGEST and that if high_bound-low_bound+1 overflows, - it overflows to 0. We must change these tests if we - decide to increase the representation of TYPE_LENGTH - from unsigned int to ULONGEST. */ - ULONGEST ulow = low_bound, uhigh = high_bound; - ULONGEST tlen = TYPE_LENGTH (target_type); - - len = tlen * (uhigh - ulow + 1); - if (tlen == 0 || (len / tlen - 1 + ulow) != uhigh - || len > UINT_MAX) - len = 0; - } - TYPE_LENGTH (type) = len; + number of elements and the target type's length. */ + TYPE_LENGTH (type) = type_length_get (type, target_type, 0); TYPE_TARGET_STUB (type) = 0; } else if (TYPE_CODE (type) == TYPE_CODE_RANGE) @@ -1514,9 +1672,12 @@ check_typedef (struct type *type) TYPE_LENGTH (type) = TYPE_LENGTH (target_type); TYPE_TARGET_STUB (type) = 0; } + TYPE_DYNAMIC (type) = 0; } + /* Cache TYPE_LENGTH for future use. */ TYPE_LENGTH (orig_type) = TYPE_LENGTH (type); + return type; } @@ -1809,6 +1970,7 @@ init_type (enum type_code code, int length, int flags, TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_CALLING_CONVENTION; break; } + return type; } @@ -2986,33 +3148,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; @@ -3027,8 +3198,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; @@ -3039,6 +3212,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)) @@ -3047,12 +3233,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++) { @@ -3061,8 +3280,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)); @@ -3089,24 +3308,75 @@ copy_type_recursive (struct objfile *objfile, } } + /* Both FIELD_LOC_KIND_DWARF_BLOCK and TYPE_RANGE_HIGH_BOUND_IS_COUNT were + possibly converted. */ + TYPE_DYNAMIC (new_type) = 0; + /* For range types, copy the bounds information. */ if (TYPE_CODE (type) == TYPE_CODE_RANGE) { TYPE_RANGE_DATA (new_type) = xmalloc (sizeof (struct range_bounds)); *TYPE_RANGE_DATA (new_type) = *TYPE_RANGE_DATA (type); + + if (TYPE_LOW_BOUND_IS_DWARF_BLOCK (type)) + { + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. */ + if (TYPE_NOT_ALLOCATED (type) + || TYPE_NOT_ASSOCIATED (type)) + TYPE_RANGE_DATA (new_type)->low.u.dwarf_block = NULL; + else + TYPE_LOW_BOUND (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->low.u.dwarf_block); + TYPE_LOW_BOUND_IS_DWARF_BLOCK (new_type) = 0; + } + + if (TYPE_HIGH_BOUND_IS_DWARF_BLOCK (type)) + { + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. */ + if (TYPE_NOT_ALLOCATED (type) + || TYPE_NOT_ASSOCIATED (type)) + TYPE_RANGE_DATA (new_type)->high.u.dwarf_block = NULL; + else + TYPE_HIGH_BOUND (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->high.u.dwarf_block); + TYPE_HIGH_BOUND_IS_DWARF_BLOCK (new_type) = 0; + } + + if (TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (type)) + { + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. */ + if (TYPE_NOT_ALLOCATED (type) + || TYPE_NOT_ASSOCIATED (type)) + TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block = NULL; + else + TYPE_BYTE_STRIDE (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block); + TYPE_BYTE_STRIDE_IS_DWARF_BLOCK (new_type) = 0; + } + + /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */ + if (TYPE_RANGE_HIGH_BOUND_IS_COUNT (type)) + { + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (type) + + TYPE_HIGH_BOUND (type) - 1; + TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type) = 0; + } } /* Copy pointers to other types. */ if (TYPE_TARGET_TYPE (type)) TYPE_TARGET_TYPE (new_type) = - copy_type_recursive (objfile, - TYPE_TARGET_TYPE (type), - copied_types); + copy_type_recursive_1 (objfile, + TYPE_TARGET_TYPE (type), + copied_types); if (TYPE_VPTR_BASETYPE (type)) TYPE_VPTR_BASETYPE (new_type) = - copy_type_recursive (objfile, - TYPE_VPTR_BASETYPE (type), - copied_types); + copy_type_recursive_1 (objfile, + TYPE_VPTR_BASETYPE (type), + copied_types); /* Maybe copy the type_specific bits. NOTE drow/2005-12-09: We do not copy the C++-specific bits like @@ -3124,6 +3394,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. @@ -3146,6 +3427,211 @@ 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); + +#if 0 + +/* Allocate a hash table which is used when freeing a struct type. */ + +static htab_t +create_deleted_types_hash (void) +{ + return htab_create (1, htab_hash_pointer, htab_eq_pointer, NULL); +} + +#endif + +/* Iterate all main_type structures reachable through any `struct type *' from + TYPE. ITER will be called only for one type of each main_type, use + TYPE_CHAIN traversal to find all the type instances. ITER is being called + for each main_type found. ITER returns non-zero if main_type_crawl should + depth-first enter the specific type. ITER must provide some detection for + reentering the same main_type as this function would otherwise endlessly + loop. */ + +static void +main_type_crawl (struct type *type, main_type_crawl_iter iter, void *data) +{ + struct type *type_iter; + int i; + + if (!type) + return; + + gdb_assert (TYPE_OBJFILE (type) == NULL); + + /* `struct cplus_struct_type' handling is unsupported by this function. */ + gdb_assert ((TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + || !HAVE_CPLUS_STRUCT (type)); + + if (!(*iter) (type, data)) + return; + + /* Iterate all the type instances of this main_type. */ + type_iter = type; + do + { + gdb_assert (TYPE_MAIN_TYPE (type_iter) == TYPE_MAIN_TYPE (type)); + + main_type_crawl (TYPE_POINTER_TYPE (type), iter, data); + main_type_crawl (TYPE_REFERENCE_TYPE (type), iter, data); + + type_iter = TYPE_CHAIN (type_iter); + } + while (type_iter != type); + + for (i = 0; i < TYPE_NFIELDS (type); i++) + main_type_crawl (TYPE_FIELD_TYPE (type, i), iter, data); + + main_type_crawl (TYPE_TARGET_TYPE (type), iter, data); + main_type_crawl (TYPE_VPTR_BASETYPE (type), iter, data); +} + +/* A helper for delete_type which deletes a main_type and the things to which + it refers. TYPE is a type whose main_type we wish to destroy. */ + +static void +delete_main_type (struct type *type) +{ + int i; + + gdb_assert (TYPE_DISCARDABLE (type)); + gdb_assert (TYPE_OBJFILE (type) == NULL); + + xfree (TYPE_NAME (type)); + xfree (TYPE_TAG_NAME (type)); + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + { + xfree (TYPE_FIELD_NAME (type, i)); + + if (TYPE_FIELD_LOC_KIND (type, i) == FIELD_LOC_KIND_PHYSNAME) + xfree (TYPE_FIELD_STATIC_PHYSNAME (type, i)); + } + xfree (TYPE_FIELDS (type)); + + gdb_assert (!HAVE_CPLUS_STRUCT (type)); + + xfree (TYPE_MAIN_TYPE (type)); +} + +/* Delete all the instances on TYPE_CHAIN of TYPE, including their referenced + main_type. TYPE must be a reclaimable type - neither permanent nor objfile + associated. */ + +static void +delete_type_chain (struct type *type) +{ + struct type *type_iter, *type_iter_to_free; + + gdb_assert (TYPE_DISCARDABLE (type)); + gdb_assert (TYPE_OBJFILE (type) == NULL); + + delete_main_type (type); + + type_iter = type; + do + { + type_iter_to_free = type_iter; + type_iter = TYPE_CHAIN (type_iter); + xfree (type_iter_to_free); + } + while (type_iter != type); +} + +/* Hash function for type_discardable_table. */ + +static hashval_t +type_discardable_hash (const void *p) +{ + const struct type *type = p; + + return htab_hash_pointer (TYPE_MAIN_TYPE (type)); +} + +/* Equality function for type_discardable_table. */ + +static int +type_discardable_equal (const void *a, const void *b) +{ + const struct type *left = a; + const struct type *right = b; + + return TYPE_MAIN_TYPE (left) == TYPE_MAIN_TYPE (right); +} + +/* A helper for type_mark_used. */ + +static int +type_mark_used_crawl (struct type *type, void *unused) +{ + if (!TYPE_DISCARDABLE (type)) + return 0; + + if (TYPE_DISCARDABLE_AGE (type) == type_discardable_age_current) + return 0; + + TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current; + + /* Continue the traversal. */ + return 1; +} + +/* Mark TYPE and its connected types as used in this free_all_types pass. */ + +void +type_mark_used (struct type *type) +{ + if (type == NULL) + return; + + if (!TYPE_DISCARDABLE (type)) + return; + + main_type_crawl (type, type_mark_used_crawl, NULL); +} + +/* A traverse callback for type_discardable_table which removes any + type_discardable whose reference count is now zero (unused link). */ + +static int +type_discardable_remove (void **slot, void *unused) +{ + struct type *type = *slot; + + gdb_assert (TYPE_DISCARDABLE (type)); + + if (TYPE_DISCARDABLE_AGE (type) != type_discardable_age_current) + { + delete_type_chain (type); + + htab_clear_slot (type_discardable_table, slot); + } + + return 1; +} + +/* Free all the reclaimable types that have been allocated and that have + currently zero reference counter. + + This function is called after each command, successful or not. Use this + cleanup only in the GDB idle state as GDB only marks those types used by + globally tracked objects (with no autovariable references tracking). */ + +void +free_all_types (void) +{ + /* Mark a new pass. As GDB checks all the entries were visited after each + pass there cannot be any stale entries already containing the changed + value. */ + type_discardable_age_current ^= 1; + + observer_notify_mark_used (); + + htab_traverse (type_discardable_table, type_discardable_remove, NULL); +} /* Helper functions to initialize architecture-specific types. */ @@ -3636,6 +4122,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 380f72a..54c8739 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -138,6 +138,8 @@ enum type_code TYPE_CODE_DECFLOAT, /* Decimal floating point. */ + TYPE_CODE_MODULE, /* Fortran module. */ + /* Internal function type. */ TYPE_CODE_INTERNAL_FUNCTION }; @@ -214,6 +216,11 @@ enum type_instance_flag_value #define TYPE_TARGET_STUB(t) (TYPE_MAIN_TYPE (t)->flag_target_stub) +/* Type needs to be evaluated on each CHECK_TYPEDEF and its results must not be + sticky. */ + +#define TYPE_DYNAMIC(t) (TYPE_MAIN_TYPE (t)->flag_dynamic) + /* Static type. If this is set, the corresponding type had * a static modifier. * Note: This may be unnecessary, since static data members @@ -279,6 +286,48 @@ enum type_instance_flag_value #define TYPE_OWNER(t) TYPE_MAIN_TYPE(t)->owner #define TYPE_OBJFILE(t) (TYPE_OBJFILE_OWNED(t)? TYPE_OWNER(t).objfile : NULL) +/* Define this type as being reclaimable during free_all_types. Type is + required to be have TYPE_OBJFILE set to NULL. Setting this flag requires + initializing TYPE_DISCARDABLE_AGE, see alloc_type_discardable. */ + +#define TYPE_DISCARDABLE(t) (TYPE_MAIN_TYPE (t)->flag_discardable) + +/* Marker this type has been visited by the type_mark_used by this + mark-and-sweep types garbage collecting pass. Current pass is represented + by TYPE_DISCARDABLE_AGE_CURRENT. */ + +#define TYPE_DISCARDABLE_AGE(t) (TYPE_MAIN_TYPE (t)->flag_discardable_age) + +/* Is HIGH_BOUND a low-bound relative count (1) or the high bound itself (0)? */ + +#define TYPE_RANGE_HIGH_BOUND_IS_COUNT(range_type) \ + (TYPE_MAIN_TYPE (range_type)->flag_range_high_bound_is_count) + +/* Not allocated. TYPE_ALLOCATED(t) must be NULL in such case. If this flag + is unset and TYPE_ALLOCATED(t) is NULL then the type is allocated. If this + flag is unset and TYPE_ALLOCATED(t) is not NULL then its DWARF block + determines the actual allocation state. */ + +#define TYPE_NOT_ALLOCATED(t) (TYPE_MAIN_TYPE (t)->flag_not_allocated) + +/* Not associated. TYPE_ASSOCIATED(t) must be NULL in such case. If this flag + is unset and TYPE_ASSOCIATED(t) is NULL then the type is associated. If + this flag is unset and TYPE_ASSOCIATED(t) is not NULL then its DWARF block + determines the actual association state. */ + +#define TYPE_NOT_ASSOCIATED(t) (TYPE_MAIN_TYPE (t)->flag_not_associated) + +/* Address of the actual data as for DW_AT_data_location. Its dwarf block must + not be evaluated unless both TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are + false. If TYPE_DATA_LOCATION_IS_ADDR set then TYPE_DATA_LOCATION_ADDR value + is the actual data address value. If unset and + TYPE_DATA_LOCATION_DWARF_BLOCK is NULL then the value is the normal + value_raw_address. If unset and TYPE_DATA_LOCATION_DWARF_BLOCK is not NULL + then its DWARF block determines the actual data address. */ + +#define TYPE_DATA_LOCATION_IS_ADDR(t) \ + (TYPE_MAIN_TYPE (t)->flag_data_location_is_addr) + /* Constant type. If this is set, the corresponding type has a * const modifier. */ @@ -336,8 +385,7 @@ enum field_loc_kind { FIELD_LOC_KIND_BITPOS, /* bitpos */ FIELD_LOC_KIND_PHYSADDR, /* physaddr */ - FIELD_LOC_KIND_PHYSNAME, /* physname */ - FIELD_LOC_KIND_DWARF_BLOCK /* dwarf_block */ + FIELD_LOC_KIND_PHYSNAME /* physname */ }; /* A discriminant to determine which field in the main_type.type_specific @@ -386,6 +434,13 @@ struct main_type unsigned int flag_nottext : 1; unsigned int flag_fixed_instance : 1; unsigned int flag_objfile_owned : 1; + unsigned int flag_discardable : 1; + unsigned int flag_discardable_age : 1; + unsigned int flag_dynamic : 1; + unsigned int flag_range_high_bound_is_count : 1; + unsigned int flag_not_allocated : 1; + unsigned int flag_not_associated : 1; + unsigned int flag_data_location_is_addr : 1; /* A discriminant telling us which field of the type_specific union is being used for this type, if any. */ @@ -456,6 +511,20 @@ struct main_type struct type *target_type; + /* For DW_AT_data_location. */ + union + { + struct dwarf2_locexpr_baton *dwarf_block; + CORE_ADDR addr; + } + data_location; + + /* For DW_AT_allocated. */ + struct dwarf2_locexpr_baton *allocated; + + /* For DW_AT_associated. */ + struct dwarf2_locexpr_baton *associated; + /* For structure and union types, a description of each field. For set and pascal array types, there is one "field", whose type is the domain type of the set or array. @@ -492,12 +561,6 @@ struct main_type CORE_ADDR physaddr; char *physname; - - /* The field location can be computed by evaluating the following DWARF - block. This can be used in Fortran variable-length arrays, for - instance. */ - - struct dwarf2_locexpr_baton *dwarf_block; } loc; @@ -535,13 +598,22 @@ struct main_type struct range_bounds { + struct + { + union + { + struct dwarf2_locexpr_baton *dwarf_block; + LONGEST constant; + } + u; + unsigned is_dwarf_block : 1; + } /* Low bound of range. */ - - LONGEST low; - + low, /* High bound of range. */ - - LONGEST high; + high, + /* Byte stride of range. */ + byte_stride; /* Flags indicating whether the values of low and high are valid. When true, the respective range value is @@ -593,6 +665,9 @@ struct main_type supporting multiple ABIs. Right now this is only fetched from the Dwarf-2 DW_AT_calling_convention attribute. */ unsigned calling_convention; + + /* For TYPE_CODE_MODULE, the list of symbols contained in the module. */ + struct block *module_block; } type_specific; }; @@ -839,13 +914,6 @@ struct cplus_struct_type int is_dynamic : 2; }; -/* Struct used in computing virtual base list */ -struct vbase - { - struct type *vbasetype; /* pointer to virtual base */ - struct vbase *next; /* next in chain */ - }; - /* Struct used for ranking a function for overload resolution */ struct badness_vector { @@ -900,9 +968,9 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type #define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type #define TYPE_CHAIN(thistype) (thistype)->chain -/* Note that if thistype is a TYPEDEF type, you have to call check_typedef. - But check_typedef does set the TYPE_LENGTH of the TYPEDEF type, - so you only have to call check_typedef once. Since allocate_value +/* Note that if thistype is a TYPEDEF, ARRAY or STRING type, you have to call + check_typedef. But check_typedef does set the TYPE_LENGTH of the TYPEDEF + type, so you only have to call check_typedef once. Since allocate_value calls check_typedef, TYPE_LENGTH (VALUE_TYPE (X)) is safe. */ #define TYPE_LENGTH(thistype) (thistype)->length /* Note that TYPE_CODE can be TYPE_CODE_TYPEDEF, so if you want the real @@ -911,15 +979,26 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields #define TYPE_TEMPLATE_ARGS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->template_args +#define TYPE_DATA_LOCATION_DWARF_BLOCK(thistype) TYPE_MAIN_TYPE (thistype)->data_location.dwarf_block +#define TYPE_DATA_LOCATION_ADDR(thistype) TYPE_MAIN_TYPE (thistype)->data_location.addr +#define TYPE_ALLOCATED(thistype) TYPE_MAIN_TYPE (thistype)->allocated +#define TYPE_ASSOCIATED(thistype) TYPE_MAIN_TYPE (thistype)->associated #define TYPE_INDEX_TYPE(type) TYPE_FIELD_TYPE (type, 0) #define TYPE_RANGE_DATA(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.bounds -#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low -#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high +#define TYPE_LOW_BOUND(range_type) TYPE_RANGE_DATA(range_type)->low.u.constant +#define TYPE_HIGH_BOUND(range_type) TYPE_RANGE_DATA(range_type)->high.u.constant +#define TYPE_BYTE_STRIDE(range_type) TYPE_RANGE_DATA(range_type)->byte_stride.u.constant #define TYPE_LOW_BOUND_UNDEFINED(range_type) \ TYPE_RANGE_DATA(range_type)->low_undefined #define TYPE_HIGH_BOUND_UNDEFINED(range_type) \ TYPE_RANGE_DATA(range_type)->high_undefined +#define TYPE_LOW_BOUND_IS_DWARF_BLOCK(range_type) \ + TYPE_RANGE_DATA(range_type)->low.is_dwarf_block +#define TYPE_HIGH_BOUND_IS_DWARF_BLOCK(range_type) \ + TYPE_RANGE_DATA(range_type)->high.is_dwarf_block +#define TYPE_BYTE_STRIDE_IS_DWARF_BLOCK(range_type) \ + TYPE_RANGE_DATA(range_type)->byte_stride.is_dwarf_block /* Moto-specific stuff for FORTRAN arrays */ @@ -928,11 +1007,23 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED(arraytype) \ TYPE_LOW_BOUND_UNDEFINED(TYPE_INDEX_TYPE(arraytype)) +#define TYPE_ARRAY_UPPER_BOUND_IS_DWARF_BLOCK(arraytype) \ + TYPE_HIGH_BOUND_IS_DWARF_BLOCK(TYPE_INDEX_TYPE(arraytype)) +#define TYPE_ARRAY_LOWER_BOUND_IS_DWARF_BLOCK(arraytype) \ + TYPE_LOW_BOUND_IS_DWARF_BLOCK(TYPE_INDEX_TYPE(arraytype)) + #define TYPE_ARRAY_UPPER_BOUND_VALUE(arraytype) \ (TYPE_HIGH_BOUND(TYPE_INDEX_TYPE((arraytype)))) #define TYPE_ARRAY_LOWER_BOUND_VALUE(arraytype) \ - (TYPE_LOW_BOUND(TYPE_INDEX_TYPE((arraytype)))) + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (arraytype)) + +/* TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) with a fallback to the + element size if no specific stride value is known. */ +#define TYPE_ARRAY_BYTE_STRIDE_VALUE(arraytype) \ + (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype)) == 0 \ + ? TYPE_LENGTH (TYPE_TARGET_TYPE (arraytype)) \ + : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (arraytype))) /* C++ */ @@ -961,6 +1052,7 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_GNAT_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.gnat_stuff #define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type #define TYPE_CALLING_CONVENTION(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.calling_convention +#define TYPE_MODULE_BLOCK(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.module_block #define TYPE_BASECLASS(thistype,index) TYPE_FIELD_TYPE(thistype, index) #define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses #define TYPE_BASECLASS_NAME(thistype,index) TYPE_FIELD_NAME(thistype, index) @@ -979,7 +1071,6 @@ extern void allocate_gnat_aux_type (struct type *); #define FIELD_BITPOS(thisfld) ((thisfld).loc.bitpos) #define FIELD_STATIC_PHYSNAME(thisfld) ((thisfld).loc.physname) #define FIELD_STATIC_PHYSADDR(thisfld) ((thisfld).loc.physaddr) -#define FIELD_DWARF_BLOCK(thisfld) ((thisfld).loc.dwarf_block) #define SET_FIELD_BITPOS(thisfld, bitpos) \ (FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_BITPOS, \ FIELD_BITPOS (thisfld) = (bitpos)) @@ -989,9 +1080,6 @@ extern void allocate_gnat_aux_type (struct type *); #define SET_FIELD_PHYSADDR(thisfld, addr) \ (FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_PHYSADDR, \ FIELD_STATIC_PHYSADDR (thisfld) = (addr)) -#define SET_FIELD_DWARF_BLOCK(thisfld, addr) \ - (FIELD_LOC_KIND (thisfld) = FIELD_LOC_KIND_DWARF_BLOCK, \ - FIELD_DWARF_BLOCK (thisfld) = (addr)) #define FIELD_ARTIFICIAL(thisfld) ((thisfld).artificial) #define FIELD_BITSIZE(thisfld) ((thisfld).bitsize) @@ -1002,7 +1090,6 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_FIELD_BITPOS(thistype, n) FIELD_BITPOS (TYPE_FIELD (thistype, n)) #define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) FIELD_STATIC_PHYSNAME (TYPE_FIELD (thistype, n)) #define TYPE_FIELD_STATIC_PHYSADDR(thistype, n) FIELD_STATIC_PHYSADDR (TYPE_FIELD (thistype, n)) -#define TYPE_FIELD_DWARF_BLOCK(thistype, n) FIELD_DWARF_BLOCK (TYPE_FIELD (thistype, n)) #define TYPE_FIELD_ARTIFICIAL(thistype, n) FIELD_ARTIFICIAL(TYPE_FIELD(thistype,n)) #define TYPE_FIELD_BITSIZE(thistype, n) FIELD_BITSIZE(TYPE_FIELD(thistype,n)) #define TYPE_FIELD_PACKED(thistype, n) (FIELD_BITSIZE(TYPE_FIELD(thistype,n))!=0) @@ -1333,6 +1420,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); @@ -1375,6 +1474,8 @@ extern int is_public_ancestor (struct type *, struct type *); extern int is_unique_ancestor (struct type *, struct value *); +extern void type_mark_used (struct type *type); + /* Overload resolution */ #define LENGTH_MATCH(bv) ((bv)->rank[0]) @@ -1437,10 +1538,11 @@ extern void maintenance_print_type (char *, int); extern htab_t create_copied_types_hash (struct objfile *objfile); -extern struct type *copy_type_recursive (struct objfile *objfile, - struct type *type, +extern struct type *copy_type_recursive (struct type *type, htab_t copied_types); extern struct type *copy_type (const struct type *type); +extern void free_all_types (void); + #endif /* GDBTYPES_H */ diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 5321401..b1882a2 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" @@ -456,10 +457,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; @@ -587,15 +586,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/i386-linux-nat.c b/gdb/i386-linux-nat.c index ff837f2..1710487 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -696,6 +696,21 @@ i386_linux_dr_unset_status (unsigned long mask) } } +/* See i386_dr_low_type.detach. Do not use wrappers i386_linux_dr_set_control + or i386_linux_dr_reset_addr as they would modify the register cache + (i386_linux_dr). */ + +static void +i386_linux_dr_detach (void) +{ + int regnum; + + i386_linux_dr_set (inferior_ptid, DR_CONTROL, 0); + i386_linux_dr_unset_status (~0UL); + for (regnum = DR_FIRSTADDR; regnum <= DR_LASTADDR; regnum++) + i386_linux_dr_set (inferior_ptid, regnum, 0); +} + static void i386_linux_new_thread (ptid_t ptid) { @@ -868,6 +883,7 @@ _initialize_i386_linux_nat (void) i386_dr_low.reset_addr = i386_linux_dr_reset_addr; i386_dr_low.get_status = i386_linux_dr_get_status; i386_dr_low.unset_status = i386_linux_dr_unset_status; + i386_dr_low.detach = i386_linux_dr_detach; i386_set_debug_register_length (4); /* Override the default ptrace resume method. */ diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c index fa0cce6..42dfd1c 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -527,6 +527,17 @@ i386_remove_watchpoint (CORE_ADDR addr, int len, int type) return retval; } +/* See target_detach_watchpoints. */ + +static int +i386_detach_watchpoints (void) +{ + if (i386_dr_low.detach) + i386_dr_low.detach (); + + return 0; +} + /* Return non-zero if we can watch a memory region that starts at address ADDR and whose length is LEN bytes. */ @@ -679,6 +690,7 @@ i386_use_watchpoints (struct target_ops *t) t->to_stopped_data_address = i386_stopped_data_address; t->to_insert_watchpoint = i386_insert_watchpoint; t->to_remove_watchpoint = i386_remove_watchpoint; + t->to_detach_watchpoints = i386_detach_watchpoints; t->to_insert_hw_breakpoint = i386_insert_hw_breakpoint; t->to_remove_hw_breakpoint = i386_remove_hw_breakpoint; } diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h index 7317e7d..ea914a5 100644 --- a/gdb/i386-nat.h +++ b/gdb/i386-nat.h @@ -62,6 +62,10 @@ extern void i386_use_watchpoints (struct target_ops *); unset_status -- unset the specified bits of the debug status (DR6) register for all LWPs + detach -- clear all debug registers of only the + INFERIOR_PTID task without affecting any + register caches. + Additionally, the native file should set the debug_register_length field to 4 or 8 depending on the number of bytes used for deubg registers. */ @@ -73,6 +77,7 @@ struct i386_dr_low_type void (*reset_addr) (int); unsigned long (*get_status) (void); void (*unset_status) (unsigned long); + void (*detach) (void); int debug_register_length; }; diff --git a/gdb/infcmd.c b/gdb/infcmd.c index f99a4ae..5599908 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -806,7 +806,7 @@ nexti_command (char *count_string, int from_tty) step_1 (1, 1, count_string); } -static void +void delete_longjmp_breakpoint_cleanup (void *arg) { int thread = * (int *) arg; @@ -846,10 +846,13 @@ step_1 (int skip_subroutines, int single_inst, char *count_string) if (!single_inst || skip_subroutines) /* leave si command alone */ { + struct thread_info *tp = inferior_thread (); + if (in_thread_list (inferior_ptid)) thread = pid_to_thread_id (inferior_ptid); set_longjmp_breakpoint (thread); + tp->initiating_frame = get_frame_id (get_current_frame ()); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } @@ -1198,6 +1201,15 @@ signal_command (char *signum_exp, int from_tty) proceed ((CORE_ADDR) -1, oursig, 0); } +/* A continuation callback for until_next_command. */ + +static void +until_next_continuation (void *arg) +{ + struct thread_info *tp = arg; + delete_longjmp_breakpoint (tp->num); +} + /* Proceed until we reach a different source line with pc greater than our current one or exit the function. We skip calls in both cases. @@ -1214,6 +1226,8 @@ until_next_command (int from_tty) struct symbol *func; struct symtab_and_line sal; struct thread_info *tp = inferior_thread (); + int thread = tp->num; + struct cleanup *old_chain; clear_proceed_status (); set_step_frame (); @@ -1249,7 +1263,19 @@ until_next_command (int from_tty) tp->step_multi = 0; /* Only one call to proceed */ + set_longjmp_breakpoint (thread); + tp->initiating_frame = get_frame_id (frame); + old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); + proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); + + if (target_can_async_p () && is_running (inferior_ptid)) + { + discard_cleanups (old_chain); + add_continuation (tp, until_next_continuation, tp, NULL); + } + else + do_cleanups (old_chain); } static void @@ -1426,6 +1452,7 @@ finish_command_continuation (void *arg) if (bs != NULL && tp->proceed_to_finish) observer_notify_normal_stop (bs, 1 /* print frame */); delete_breakpoint (a->breakpoint); + delete_longjmp_breakpoint (inferior_thread ()->num); } static void @@ -1509,6 +1536,7 @@ finish_forward (struct symbol *function, struct frame_info *frame) struct breakpoint *breakpoint; struct cleanup *old_chain; struct finish_command_continuation_args *cargs; + int thread = tp->num; sal = find_pc_line (get_frame_pc (frame), 0); sal.pc = get_frame_pc (frame); @@ -1519,6 +1547,10 @@ finish_forward (struct symbol *function, struct frame_info *frame) old_chain = make_cleanup_delete_breakpoint (breakpoint); + set_longjmp_breakpoint (thread); + tp->initiating_frame = get_frame_id (frame); + make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); + tp->proceed_to_finish = 1; /* We want stop_registers, please... */ cargs = xmalloc (sizeof (*cargs)); diff --git a/gdb/inferior.h b/gdb/inferior.h index e557d6c..d4ae1df 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -275,6 +275,8 @@ extern void interrupt_target_command (char *args, int from_tty); extern void interrupt_target_1 (int all_threads); +extern void delete_longjmp_breakpoint_cleanup (void *arg); + extern void detach_command (char *, int); extern void notice_new_inferior (ptid_t, int, int); diff --git a/gdb/infrun.c b/gdb/infrun.c index 06f3ea0..fe3719e 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -45,6 +45,8 @@ #include "language.h" #include "solib.h" #include "main.h" +#include "dictionary.h" +#include "block.h" #include "gdb_assert.h" #include "mi/mi-common.h" #include "event-top.h" @@ -2010,6 +2012,8 @@ static void insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch, struct symtab_and_line sr_sal, struct frame_id sr_id); static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); +static void check_exception_resume (struct execution_control_state *, + struct frame_info *, struct symbol *); static void stop_stepping (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); @@ -2930,6 +2934,10 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); + /* Clear WATCHPOINT_TRIGGERED values from previous stop which could + confuse bpstat_stop_status and bpstat_explains_signal. */ + watchpoints_triggered (&ecs->ws); + ecs->event_thread->stop_bpstat = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()), stop_pc, ecs->ptid); @@ -3014,6 +3022,10 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); + /* Clear WATCHPOINT_TRIGGERED values from previous stop which could + confuse bpstat_stop_status and bpstat_explains_signal. */ + watchpoints_triggered (&ecs->ws); + /* Do whatever is necessary to the parent branch of the vfork. */ handle_vfork_child_exec_or_exit (1); @@ -3772,23 +3784,33 @@ process_event_stop_test: ecs->event_thread->stepping_over_breakpoint = 1; - if (!gdbarch_get_longjmp_target_p (gdbarch) - || !gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc)) + if (what.is_longjmp) { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "\ + if (!gdbarch_get_longjmp_target_p (gdbarch) + || !gdbarch_get_longjmp_target (gdbarch, + frame, &jmp_buf_pc)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "\ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); - keep_going (ecs); - return; - } + keep_going (ecs); + return; + } - /* We're going to replace the current step-resume breakpoint - with a longjmp-resume breakpoint. */ - delete_step_resume_breakpoint (ecs->event_thread); + /* We're going to replace the current step-resume breakpoint + with a longjmp-resume breakpoint. */ + delete_step_resume_breakpoint (ecs->event_thread); - /* Insert a breakpoint at resume address. */ - insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc); + /* Insert a breakpoint at resume address. */ + insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc); + } + else + { + struct symbol *func = get_frame_function (frame); + if (func) + check_exception_resume (ecs, frame, func); + } keep_going (ecs); return; @@ -3800,6 +3822,53 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL); delete_step_resume_breakpoint (ecs->event_thread); + if (!what.is_longjmp) + { + /* There are several cases to consider. + + 1. The initiating frame no longer exists. In this case + we must stop, because the exception has gone too far. + + 2. The initiating frame exists, and is the same as the + current frame. + + 2.1. If we are stepping, defer to the stepping logic. + + 2.2. Otherwise, we are not stepping, so we are doing a + "finish" and we have reached the calling frame. So, + stop. + + 3. The initiating frame exists and is different from + the current frame. This means the exception has been + caught beneath the initiating frame, so keep going. */ + struct frame_info *init_frame + = frame_find_by_id (ecs->event_thread->initiating_frame); + if (init_frame) + { + struct frame_id current_id + = get_frame_id (get_current_frame ()); + if (frame_id_eq (current_id, + ecs->event_thread->initiating_frame)) + { + if (ecs->event_thread->step_range_start) + { + /* Case 2.1. */ + break; + } + else + { + /* Case 2.2: fall through. */ + } + } + else + { + /* Case 3. */ + keep_going (ecs); + return; + } + } + } + ecs->event_thread->stop_step = 1; print_stop_reason (END_STEPPING_RANGE, 0); stop_stepping (ecs); @@ -4819,6 +4888,96 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc) set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume); } +/* Insert an exception resume breakpoint. TP is the thread throwing + the exception. The block B is the block of the unwinder debug hook + function. FRAME is the frame corresponding to the call to this + function. SYM is the symbol of the function argument holding the + target PC of the exception. */ + +static void +insert_exception_resume_breakpoint (struct thread_info *tp, + struct block *b, + struct frame_info *frame, + struct symbol *sym) +{ + struct gdb_exception e; + + /* We want to ignore errors here. */ + TRY_CATCH (e, RETURN_MASK_ALL) + { + struct symbol *vsym; + struct value *value; + CORE_ADDR handler; + struct breakpoint *bp; + + vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL); + value = read_var_value (vsym, frame); + handler = value_as_address (value); + + /* We're going to replace the current step-resume breakpoint + with an exception-resume breakpoint. */ + delete_step_resume_breakpoint (tp); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: exception resume at %lx\n", + (unsigned long) handler); + + bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame), + handler, bp_exception_resume); + inferior_thread ()->step_resume_breakpoint = bp; + } +} + +/* This is called when an exception has been intercepted. Check to + see whether the exception's destination is of interest, and if so, + set an exception resume breakpoint there. */ + +static void +check_exception_resume (struct execution_control_state *ecs, + struct frame_info *frame, struct symbol *func) +{ + struct gdb_exception e; + + TRY_CATCH (e, RETURN_MASK_ALL) + { + struct block *b; + struct dict_iterator iter; + struct symbol *sym; + int argno = 0; + + /* The exception breakpoint is a thread-specific breakpoint on + the unwinder's debug hook, declared as: + + void _Unwind_DebugHook (void *cfa, void *handler); + + The CFA argument indicates the frame to which control is + about to be transferred. HANDLER is the destination PC. + + We ignore the CFA and set a temporary breakpoint at HANDLER. + This is not extremely efficient but it avoids issues in gdb + with computing the DWARF CFA, and it also works even in weird + cases such as throwing an exception from inside a signal + handler. */ + + b = SYMBOL_BLOCK_VALUE (func); + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + if (!SYMBOL_IS_ARGUMENT (sym)) + continue; + + if (argno == 0) + ++argno; + else + { + insert_exception_resume_breakpoint (ecs->event_thread, + b, frame, sym); + break; + } + } + } +} + static void stop_stepping (struct execution_control_state *ecs) { diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c index 24b6673..22ed960 100644 --- a/gdb/jv-lang.c +++ b/gdb/jv-lang.c @@ -1121,6 +1121,7 @@ const struct exp_descriptor exp_descriptor_java = { print_subexp_standard, operator_length_standard, + operator_check_standard, op_name_standard, dump_subexp_body_standard, evaluate_subexp_java diff --git a/gdb/language.h b/gdb/language.h index aaefb03..c274572 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 74902b6..a9b4f1e 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -50,8 +50,6 @@ extern char *operator_chars (char *, char **); static void initialize_defaults (struct symtab **default_symtab, int *default_line); -static void set_flags (char *arg, int *is_quoted, char **paren_pointer); - static struct symtabs_and_lines decode_indirect (char **argptr); static char *locate_first_half (char **argptr, int *is_quote_enclosed); @@ -688,9 +686,6 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, struct symtab *file_symtab = NULL; char *copy; - /* This is NULL if there are no parens in *ARGPTR, or a pointer to - the closing parenthesis if there are parens. */ - char *paren_pointer; /* This says whether or not something in *ARGPTR is quoted with completer_quotes (i.e. with single quotes). */ int is_quoted; @@ -711,12 +706,9 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, if (**argptr == '*') return decode_indirect (argptr); - /* Set various flags. 'paren_pointer' is important for overload - checking, where we allow things like: - (gdb) break c::f(int) - */ - - set_flags (*argptr, &is_quoted, &paren_pointer); + is_quoted = (*argptr + && strchr (get_gdb_completer_quote_characters (), + **argptr) != NULL); /* Check to see if it's a multipart linespec (with colons or periods). */ @@ -732,10 +724,7 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, /* Check if this is an Objective-C method (anything that starts with a '+' or '-' and a '['). */ if (is_objc_method_format (p)) - { - is_objc_method = 1; - paren_pointer = NULL; /* Just a category name. Ignore it. */ - } + is_objc_method = 1; /* Check if the symbol could be an Objective-C selector. */ @@ -749,11 +738,11 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, /* Does it look like there actually were two parts? */ - if ((p[0] == ':' || p[0] == '.') && paren_pointer == NULL) + if (p[0] == ':' || p[0] == '.') { if (is_quoted) *argptr = *argptr + 1; - + /* Is it a C++ or Java compound data structure? The check on p[1] == ':' is capturing the case of "::", since p[0]==':' was checked above. @@ -762,48 +751,31 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, can return now. */ if (p[0] == '.' || p[1] == ':') - return decode_compound (argptr, funfirstline, canonical, - saved_arg, p, not_found_ptr); + { + struct symtabs_and_lines values; + + if (is_quote_enclosed) + ++saved_arg; + values = decode_compound (argptr, funfirstline, canonical, + saved_arg, p, not_found_ptr); + if (is_quoted && **argptr == '\'') + *argptr = *argptr + 1; + return values; + } /* No, the first part is a filename; set file_symtab to be that file's symtab. Also, move argptr past the filename. */ file_symtab = symtab_from_filename (argptr, p, is_quote_enclosed, not_found_ptr); - } -#if 0 - /* No one really seems to know why this was added. It certainly - breaks the command line, though, whenever the passed - name is of the form ClassName::Method. This bit of code - singles out the class name, and if funfirstline is set (for - example, you are setting a breakpoint at this function), - you get an error. This did not occur with earlier - verions, so I am ifdef'ing this out. 3/29/99 */ - else - { - /* Check if what we have till now is a symbol name */ - - /* We may be looking at a template instantiation such - as "foo". Check here whether we know about it, - instead of falling through to the code below which - handles ordinary function names, because that code - doesn't like seeing '<' and '>' in a name -- the - skip_quoted call doesn't go past them. So see if we - can figure it out right now. */ - - copy = (char *) alloca (p - *argptr + 1); - memcpy (copy, *argptr, p - *argptr); - copy[p - *argptr] = '\000'; - sym = lookup_symbol (copy, 0, VAR_DOMAIN, 0); - if (sym) + if (file_symtab != NULL) { - *argptr = (*p == '\'') ? p + 1 : p; - return symbol_found (funfirstline, canonical, copy, sym, NULL); + /* Double-check if the remainder of the argument is quoted. + The rbreak command uses syntax like this. */ + if (**argptr == '\'') + is_quoted = 1; } - /* Otherwise fall out from here and go to file/line spec - processing, etc. */ } -#endif /* file_symtab is specified file's symtab, or 0 if no file specified. arg no longer contains the file name. */ @@ -838,10 +810,6 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, /* allow word separators in method names for Obj-C */ p = skip_quoted_chars (*argptr, NULL, ""); } - else if (paren_pointer != NULL) - { - p = paren_pointer + 1; - } else { p = skip_quoted (*argptr); @@ -851,6 +819,15 @@ decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab, if (*p == '<') p = find_template_name_end (p); + /* Keep method overload information. */ + q = strchr (p, '('); + if (q != NULL) + p = strrchr (q, ')') + 1; + + /* Make sure we keep important kewords like "const" */ + if (strncmp (p, " const", 6) == 0) + p += 6; + copy = (char *) alloca (p - *argptr + 1); memcpy (copy, *argptr, p - *argptr); copy[p - *argptr] = '\0'; @@ -926,44 +903,6 @@ initialize_defaults (struct symtab **default_symtab, int *default_line) } } -static void -set_flags (char *arg, int *is_quoted, char **paren_pointer) -{ - char *ii; - int has_if = 0; - - /* 'has_if' is for the syntax: - (gdb) break foo if (a==b) - */ - if ((ii = strstr (arg, " if ")) != NULL || - (ii = strstr (arg, "\tif ")) != NULL || - (ii = strstr (arg, " if\t")) != NULL || - (ii = strstr (arg, "\tif\t")) != NULL || - (ii = strstr (arg, " if(")) != NULL || - (ii = strstr (arg, "\tif( ")) != NULL) - has_if = 1; - /* Temporarily zap out "if (condition)" to not confuse the - parenthesis-checking code below. This is undone below. Do not - change ii!! */ - if (has_if) - { - *ii = '\0'; - } - - *is_quoted = (*arg - && strchr (get_gdb_completer_quote_characters (), - *arg) != NULL); - - *paren_pointer = strchr (arg, '('); - if (*paren_pointer != NULL) - *paren_pointer = strrchr (*paren_pointer, ')'); - - /* Now that we're safely past the paren_pointer check, put back " if - (condition)" so outer layers can see it. */ - if (has_if) - *ii = ' '; -} - /* Decode arg of the form *PC. */ @@ -1264,7 +1203,8 @@ decode_compound (char **argptr, int funfirstline, char ***canonical, /* PASS2: p2->"::fun", p->":fun" */ /* Move pointer ahead to next double-colon. */ - while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\'')) + while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\'') + && (*p != '(')) { if (current_language->la_language == language_cplus) p += cp_validate_operator (p); @@ -1342,8 +1282,10 @@ decode_compound (char **argptr, int funfirstline, char ***canonical, else { /* At this point argptr->"fun". */ + char *a; p = *argptr; - while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':') + while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':' + && *p != '(') p++; /* At this point p->"". String ended. */ /* Nope, C++ operators could have spaces in them @@ -1355,6 +1297,19 @@ decode_compound (char **argptr, int funfirstline, char ***canonical, /* The above loop has already swallowed "operator". */ p += cp_validate_operator (p - 8) - 8; } + + /* Keep any template parameters */ + if (*p == '<') + p = find_template_name_end (p); + + /* Keep method overload information. */ + a = strchr (p, '('); + if (a != NULL) + p = strrchr (a, ')') + 1; + + /* Make sure we keep important kewords like "const" */ + if (strncmp (p, " const", 6) == 0) + p += 6; } /* Allocate our own copy of the substring between argptr and @@ -1509,8 +1464,39 @@ find_method (int funfirstline, char ***canonical, char *saved_arg, } if (i1 > 0) { - /* There is more than one field with that name - (overloaded). Ask the user which one to use. */ + /* If we were given a specific overload instance, use that + (or error if no matches were found). Otherwise ask the user + which one to use. */ + if (strchr (saved_arg, '(') != NULL) + { + int i; + for (i = 0; i < i1; ++i) + { + char *name = saved_arg; + char *canon = cp_canonicalize_string (name); + if (canon != NULL) + name = canon; + + if (strcmp_iw (name, SYMBOL_LINKAGE_NAME (sym_arr[i])) == 0) + { + values.sals = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + values.nelts = 1; + values.sals[0] = find_function_start_sal (sym_arr[i], + funfirstline); + if (canon) + xfree (canon); + return values; + } + + if (canon) + xfree (canon); + } + + error (_("the class `%s' does not have any method instance named %s\n"), + SYMBOL_PRINT_NAME (sym_class), copy); + } + return decode_line_2 (sym_arr, i1, funfirstline, canonical); } else @@ -1815,7 +1801,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 7fc9584..b286dfd 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -2624,6 +2624,39 @@ linux_nat_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) return lp->stopped_data_address_p; } +/* In `set follow-fork-mode child' with multithreaded parent we need to detach + watchpoints from all the LWPs. In such case INFERIOR_PTID will be the + non-threaded new child while LWP_LIST will still contain all the threads of + the parent being detached. */ + +static int +linux_nat_detach_watchpoints (void) +{ + struct lwp_info *lp; + int found = 0, retval = 0; + ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid)); + struct cleanup *old_chain = save_inferior_ptid (); + + for (lp = lwp_list; lp; lp = lp->next) + if (ptid_match (lp->ptid, filter)) + { + inferior_ptid = lp->ptid; + retval |= linux_ops->to_detach_watchpoints (); + found = 1; + } + + do_cleanups (old_chain); + + if (!found) + { + gdb_assert (!is_lwp (inferior_ptid)); + + retval |= linux_ops->to_detach_watchpoints (); + } + + return retval; +} + /* Wait until LP is stopped. */ static int @@ -5500,6 +5533,8 @@ linux_nat_add_target (struct target_ops *t) t->to_thread_address_space = linux_nat_thread_address_space; t->to_stopped_by_watchpoint = linux_nat_stopped_by_watchpoint; t->to_stopped_data_address = linux_nat_stopped_data_address; + if (linux_ops->to_detach_watchpoints) + t->to_detach_watchpoints = linux_nat_detach_watchpoints; t->to_can_async_p = linux_nat_can_async_p; t->to_is_async_p = linux_nat_is_async_p; diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 80e9bf9..3057774 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -356,6 +356,7 @@ const struct exp_descriptor exp_descriptor_modula2 = { print_subexp_standard, operator_length_standard, + operator_check_standard, op_name_standard, dump_subexp_body_standard, evaluate_subexp_modula2 diff --git a/gdb/machoread.c b/gdb/machoread.c index 02b61d3..13ab595 100644 --- a/gdb/machoread.c +++ b/gdb/machoread.c @@ -755,6 +755,7 @@ static struct sym_fns macho_sym_fns = { macho_new_init, /* sym_new_init: init anything gbl to entire symtab */ macho_symfile_init, /* sym_init: read initial info, setup for sym_read() */ macho_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ macho_symfile_finish, /* sym_finish: finished with file, cleanup */ macho_symfile_offsets, /* sym_offsets: xlate external to internal form */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/main.c b/gdb/main.c index e261348..92c63a7 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; @@ -641,7 +651,31 @@ extern int gdbtk_test (char *); /* Now that gdb_init has created the initial inferior, we're in position to set args for that inferior. */ - 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 @@ -867,7 +901,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) { @@ -896,13 +931,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. */ } @@ -934,7 +981,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 (_("\ @@ -972,7 +1024,13 @@ Options:\n\n\ --nw Do not use a window interface.\n\ --nx Do not read "), stream); fputs_unfiltered (gdbinit, stream); - fputs_unfiltered (_(" file.\n\ + fputs_unfiltered (_(" file.\n"), stream); +#if HAVE_PYTHON + fputs_unfiltered (_("\ + --python, -P Following argument is Python script file; remaining\n\ + arguments are passed to script.\n"), stream); +#endif + fputs_unfiltered (_("\ --quiet Do not print version number on startup.\n\ --readnow Fully read symbol files on first access.\n\ "), stream); diff --git a/gdb/maint.c b/gdb/maint.c index 4316d66..fe8a069 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -914,4 +914,12 @@ When enabled GDB is profiled."), show_maintenance_profile_p, &maintenance_set_cmdlist, &maintenance_show_cmdlist); + add_setshow_filename_cmd ("gdb_datadir", class_maintenance, + &gdb_datadir, _("Set GDB's datadir path."), + _("Show GDB's datadir path."), + _("\ +When set, GDB uses the specified path to search for data files."), + NULL, NULL, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); } diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c index b227411..3b932f0 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -697,7 +697,6 @@ mi_cmd_var_update (char *command, char **argv, int argc) } else { - /* Get varobj handle, if a valid var obj name was specified */ struct varobj *var = varobj_get_handle (name); varobj_update_one (var, print_values, 1 /* explicit */); diff --git a/gdb/mipsread.c b/gdb/mipsread.c index 4ef817e..1c53574 100644 --- a/gdb/mipsread.c +++ b/gdb/mipsread.c @@ -394,6 +394,7 @@ static struct sym_fns ecoff_sym_fns = mipscoff_new_init, /* sym_new_init: init anything gbl to entire symtab */ mipscoff_symfile_init, /* sym_init: read initial info, setup for sym_read() */ mipscoff_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ mipscoff_symfile_finish, /* sym_finish: finished with file, cleanup */ default_symfile_offsets, /* sym_offsets: dummy FIXME til implem sym reloc */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/objfiles.c b/gdb/objfiles.c index 0b07e37..5de5300 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -789,6 +789,10 @@ objfile_relocate1 (struct objfile *objfile, struct section_offsets *new_offsets) } } + if (objfile->quick_addrmap) + addrmap_relocate (objfile->quick_addrmap, + ANOFFSET (delta, SECT_OFF_TEXT (objfile))); + { struct partial_symbol **psym; @@ -914,7 +918,7 @@ objfile_relocate (struct objfile *objfile, struct section_offsets *new_offsets) int objfile_has_partial_symbols (struct objfile *objfile) { - return objfile->psymtabs != NULL; + return objfile->psymtabs != NULL || objfile->quick_addrmap; } /* Return non-zero if OBJFILE has full symbols. */ @@ -954,6 +958,20 @@ have_partial_symbols (void) if (objfile_has_partial_symbols (ofp)) return 1; } + + /* Try again, after reading partial symbols. We do this in two + passes because objfiles are always added to the head of the list, + and there might be a later objfile for which we've already read + partial symbols. */ + ALL_OBJFILES (ofp) + { + require_partial_symbols (ofp); + if (ofp->psymtabs != NULL) + { + return 1; + } + } + return 0; } diff --git a/gdb/objfiles.h b/gdb/objfiles.h index c689622..eb3ae10 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -213,6 +213,11 @@ struct objfile struct partial_symtab *psymtabs; + /* An address map that can be used to quickly determine if an + address comes from this objfile. This can be NULL. */ + + struct addrmap *quick_addrmap; + /* Map addresses to the entries of PSYMTABS. It would be more efficient to have a map per the whole process but ADDRMAP cannot selectively remove its items during FREE_OBJFILE. This mapping is already present even for @@ -426,6 +431,15 @@ struct objfile #define OBJF_USERLOADED (1 << 3) /* User loaded */ +/* Set if we have tried to read partial symtabs for this objfile. + This is used to allow lazy reading of partial symtabs. */ + +#define OBJF_SYMTABS_READ (1 << 6) + +/* This flag is set for the main objfile. */ + +#define OBJF_MAIN (1 << 7) + /* The object file that contains the runtime common minimal symbols for SunOS4. Note that this objfile has no associated BFD. */ @@ -606,6 +620,13 @@ extern void gdb_bfd_unref (struct bfd *abfd); ALL_OBJFILES (objfile) \ ALL_OBJFILE_PSYMTABS (objfile, p) +/* Like ALL_PSYMTABS, but ensure that partial symbols have been read + before examining the objfile. */ + +#define ALL_PSYMTABS_REQUIRED(objfile, p) \ + ALL_OBJFILES (objfile) \ + ALL_OBJFILE_PSYMTABS (require_partial_symbols (objfile), p) + #define ALL_PSPACE_PSYMTABS(ss, objfile, p) \ ALL_PSPACE_OBJFILES (ss, objfile) \ ALL_OBJFILE_PSYMTABS (objfile, p) diff --git a/gdb/parse.c b/gdb/parse.c index d5a199b..d2a04c3 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -62,6 +62,7 @@ const struct exp_descriptor exp_descriptor_standard = { print_subexp_standard, operator_length_standard, + operator_check_standard, op_name_standard, dump_subexp_body_standard, evaluate_subexp_standard @@ -841,6 +842,10 @@ operator_length_standard (struct expression *expr, int endpos, 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); @@ -1361,6 +1366,150 @@ parser_fprintf (FILE *x, const char *y, ...) va_end (args); } +/* Implementation of the exp_descriptor method operator_check. */ + +int +operator_check_standard (struct expression *exp, int pos, + int (*type_func) (struct type *type, void *data), + int (*objfile_func) (struct objfile *objfile, + void *data), + void *data) +{ + const union exp_element *const elts = exp->elts; + struct type *type = NULL; + struct objfile *objfile = NULL; + + /* Extended operators should have been already handled by exp_descriptor + iterate method of its specific language. */ + gdb_assert (elts[pos].opcode < OP_EXTENDED0); + + /* Track the callers of write_exp_elt_type for this table. */ + + switch (elts[pos].opcode) + { + case BINOP_VAL: + case OP_COMPLEX: + case OP_DECFLOAT: + case OP_DOUBLE: + case OP_LONG: + case OP_SCOPE: + case OP_TYPE: + case UNOP_CAST: + case UNOP_MAX: + case UNOP_MEMVAL: + case UNOP_MIN: + type = elts[pos + 1].type; + break; + + case UNOP_MEMVAL_TLS: + objfile = elts[pos + 1].objfile; + type = elts[pos + 2].type; + break; + + case OP_VAR_VALUE: + { + const struct block *const block = elts[pos + 1].block; + const struct symbol *const symbol = elts[pos + 2].symbol; + const struct obj_section *const section = SYMBOL_OBJ_SECTION (symbol); + + /* Check objfile where the variable itself is placed. */ + if (section && objfile_func && (*objfile_func) (section->objfile, data)) + return 1; + + /* Check objfile where is placed the code touching the variable. */ + objfile = block_objfile (block); + + type = SYMBOL_TYPE (symbol); + } + break; + } + + /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */ + + if (type && type_func && (*type_func) (type, data)) + return 1; + if (type && TYPE_OBJFILE (type) && objfile_func + && (*objfile_func) (TYPE_OBJFILE (type), data)) + return 1; + if (objfile && objfile_func && (*objfile_func) (objfile, data)) + return 1; + + return 0; +} + +/* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being + referenced by EXP. The functions are never called with NULL TYPE or NULL + OBJFILE. Functions get passed an arbitrary caller supplied DATA pointer. + If any of the functions returns non-zero value then (any other) non-zero + value is immediately returned to the caller. Otherwise zero is returned + after iterating through whole EXP. */ + +static int +exp_iterate (struct expression *exp, + int (*type_func) (struct type *type, void *data), + int (*objfile_func) (struct objfile *objfile, void *data), + void *data) +{ + int endpos; + const union exp_element *const elts = exp->elts; + + for (endpos = exp->nelts; endpos > 0; ) + { + int pos, args, oplen = 0; + + exp->language_defn->la_exp_desc->operator_length (exp, endpos, + &oplen, &args); + gdb_assert (oplen > 0); + + pos = endpos - oplen; + if (exp->language_defn->la_exp_desc->operator_check (exp, pos, type_func, + objfile_func, data)) + return 1; + + endpos = pos; + } + + return 0; +} + +/* Helper for exp_uses_objfile. */ + +static int +exp_uses_objfile_iter (struct objfile *exp_objfile, void *objfile_voidp) +{ + struct objfile *objfile = objfile_voidp; + + return exp_objfile == objfile; +} + +/* Return 1 if EXP uses OBJFILE (and will become dangling when OBJFILE + is unloaded), otherwise return 0. */ + +int +exp_uses_objfile (struct expression *exp, struct objfile *objfile) +{ + return exp_iterate (exp, NULL, exp_uses_objfile_iter, objfile); +} + +/* Helper for exp_types_mark_used. */ + +static int +exp_types_mark_used_iter (struct type *type, void *unused) +{ + type_mark_used (type); + + /* Continue the traversal. */ + return 0; +} + +/* Call type_mark_used for any TYPE contained in EXP. */ + +void +exp_types_mark_used (struct expression *exp) +{ + exp_iterate (exp, exp_types_mark_used_iter, NULL, NULL); +} + void _initialize_parse (void) { diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index 6fcf7ae..3f5efe8 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -190,6 +190,13 @@ extern void operator_length (struct expression *, int, int *, int *); extern void operator_length_standard (struct expression *, int, int *, int *); +extern int operator_check_standard (struct expression *exp, int pos, + int (*type_func) (struct type *type, + void *data), + int (*objfile_func) + (struct objfile *objfile, void *data), + void *data); + extern char *op_name_standard (enum exp_opcode); extern struct type *follow_types (struct type *); @@ -268,6 +275,20 @@ struct exp_descriptor the number of subexpressions it takes. */ void (*operator_length) (struct expression*, int, int*, int *); + /* Call TYPE_FUNC and OBJFILE_FUNC for any TYPE and OBJFILE found being + referenced by the single operator of EXP at position POS. Operator + parameters are located at positive (POS + number) offsets in EXP. + The functions should never be called with NULL TYPE or NULL OBJFILE. + Functions should get passed an arbitrary caller supplied DATA pointer. + If any of the functions returns non-zero value then (any other) non-zero + value should be immediately returned to the caller. Otherwise zero + should be returned. */ + int (*operator_check) (struct expression *exp, int pos, + int (*type_func) (struct type *type, void *data), + int (*objfile_func) (struct objfile *objfile, + void *data), + void *data); + /* Name of this operator for dumping purposes. */ char *(*op_name) (enum exp_opcode); @@ -300,4 +321,8 @@ extern void print_subexp_standard (struct expression *, int *, extern void parser_fprintf (FILE *, const char *, ...) ATTR_FORMAT (printf, 2 ,3); +extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile); + +extern void exp_types_mark_used (struct expression *exp); + #endif /* PARSER_DEFS_H */ diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index 10ff73d..5b68f56 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -1391,6 +1391,24 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw) return 0; } +/* See target_detach_watchpoints. Do not use wrapper + ppc_linux_remove_watchpoint as it would modify the register cache + (saved_dabr_value). */ + +static int +ppc_linux_detach_watchpoints (void) +{ + pid_t tid; + + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); + + if (ptrace (PTRACE_SET_DEBUGREG, tid, NULL, NULL) < 0) + return -1; + return 0; +} + static void ppc_linux_new_thread (ptid_t ptid) { @@ -1648,6 +1666,7 @@ _initialize_ppc_linux_nat (void) t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint; t->to_insert_watchpoint = ppc_linux_insert_watchpoint; t->to_remove_watchpoint = ppc_linux_remove_watchpoint; + t->to_detach_watchpoints = ppc_linux_detach_watchpoints; t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint; t->to_stopped_data_address = ppc_linux_stopped_data_address; t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range; diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 88db08b..18dae9e 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -46,7 +46,6 @@ #include "exceptions.h" #include "observer.h" #include "solist.h" -#include "solib.h" #include "parser-defs.h" #include "charset.h" #include "arch-utils.h" @@ -941,6 +940,11 @@ print_command_1 (char *exp, int inspect, int voidprint) else val = access_value_history (0); + /* Do not try to OBJECT_ADDRESS_SET here anything. We are interested in the + source variable base addresses as found by READ_VAR_VALUE. The value here + can be already a calculated expression address inappropriate for + DW_OP_push_object_address. */ + if (voidprint || (val && value_type (val) && TYPE_CODE (value_type (val)) != TYPE_CODE_VOID)) { @@ -1437,6 +1441,22 @@ x_command (char *exp, int from_tty) set_internalvar (lookup_internalvar ("__"), last_examine_value); } } + +/* Call type_mark_used for any TYPEs referenced from this GDB source file. */ + +static void +print_types_mark_used (void) +{ + struct display *d; + + if (last_examine_value) + type_mark_used (value_type (last_examine_value)); + + for (d = display_chain; d; d = d->next) + if (d->exp) + exp_types_mark_used (d->exp); +} + /* Add an expression to the auto-display chain. @@ -1859,52 +1879,6 @@ disable_display_command (char *args, int from_tty) } } -/* Return 1 if D uses SOLIB (and will become dangling when SOLIB - is unloaded), otherwise return 0. */ - -static int -display_uses_solib_p (const struct display *d, - const struct so_list *solib) -{ - int endpos; - struct expression *const exp = d->exp; - const union exp_element *const elts = exp->elts; - - if (d->block != NULL - && d->pspace == solib->pspace - && solib_contains_address_p (solib, d->block->startaddr)) - return 1; - - for (endpos = exp->nelts; endpos > 0; ) - { - int i, args, oplen = 0; - - exp->language_defn->la_exp_desc->operator_length (exp, endpos, - &oplen, &args); - gdb_assert (oplen > 0); - - i = endpos - oplen; - if (elts[i].opcode == OP_VAR_VALUE) - { - const struct block *const block = elts[i + 1].block; - const struct symbol *const symbol = elts[i + 2].symbol; - const struct obj_section *const section = - SYMBOL_OBJ_SECTION (symbol); - - if (block != NULL - && solib_contains_address_p (solib, - block->startaddr)) - return 1; - - if (section && section->objfile == solib->objfile) - return 1; - } - endpos -= oplen; - } - - return 0; -} - /* display_chain items point to blocks and expressions. Some expressions in turn may point to symbols. Both symbols and blocks are obstack_alloc'd on objfile_stack, and are @@ -1916,18 +1890,20 @@ display_uses_solib_p (const struct display *d, static void clear_dangling_display_expressions (struct so_list *solib) { + struct objfile *objfile = solib->objfile; struct display *d; - struct objfile *objfile = NULL; - for (d = display_chain; d; d = d->next) - { - if (d->exp && display_uses_solib_p (d, solib)) - { - xfree (d->exp); - d->exp = NULL; - d->block = NULL; - } - } + if (objfile == NULL) + return; + + for (d = display_chain; d != NULL; d = d->next) + if (block_objfile (d->block) == objfile + || (d->exp && exp_uses_objfile (d->exp, objfile))) + { + xfree (d->exp); + d->exp = NULL; + d->block = NULL; + } } @@ -2812,4 +2788,6 @@ Show printing of source filename and line number with ."), NULL, NULL, show_print_symbol_filename, &setprintlist, &showprintlist); + + observer_attach_mark_used (print_types_mark_used); } diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py new file mode 100644 index 0000000..5654546 --- /dev/null +++ b/gdb/python/lib/gdb/FrameIterator.py @@ -0,0 +1,33 @@ +# Iterator over frames. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +class FrameIterator: + """An iterator that iterates over frames.""" + + def __init__ (self, frame): + "Initialize a FrameIterator. FRAME is the starting frame." + self.frame = frame + + def __iter__ (self): + return self + + def next (self): + result = self.frame + if result is None: + raise StopIteration + self.frame = result.older () + return result diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py new file mode 100644 index 0000000..b790a54 --- /dev/null +++ b/gdb/python/lib/gdb/FrameWrapper.py @@ -0,0 +1,112 @@ +# Wrapper API for frames. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +# FIXME: arguably all this should be on Frame somehow. +class FrameWrapper: + def __init__ (self, frame): + self.frame = frame; + + def write_symbol (self, stream, sym, block): + if len (sym.linkage_name): + nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) + if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER: + sym = nsym + + stream.write (sym.print_name + "=") + try: + val = self.read_var (sym) + if val != None: + val = str (val) + # FIXME: would be nice to have a more precise exception here. + except RuntimeError, text: + val = text + if val == None: + stream.write ("???") + else: + stream.write (str (val)) + + def print_frame_locals (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if sym.is_argument: + continue; + + self.write_symbol (stream, sym, block) + stream.write ('\n') + + def print_frame_args (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if not sym.is_argument: + continue; + + if not first: + stream.write (", ") + + self.write_symbol (stream, sym, block) + first = False + + # FIXME: this should probably just be a method on gdb.Frame. + # But then we need stream wrappers. + def describe (self, stream, full): + if self.type () == gdb.DUMMY_FRAME: + stream.write (" \n") + elif self.type () == gdb.SIGTRAMP_FRAME: + stream.write (" \n") + else: + sal = self.find_sal () + pc = self.pc () + name = self.name () + if not name: + name = "??" + if pc != sal.pc or not sal.symtab: + stream.write (" 0x%08x in" % pc) + stream.write (" " + name + " (") + + func = self.function () + self.print_frame_args (stream, func) + + stream.write (")") + + if sal.symtab and sal.symtab.filename: + stream.write (" at " + sal.symtab.filename) + stream.write (":" + str (sal.line)) + + if not self.name () or (not sal.symtab or not sal.symtab.filename): + lib = gdb.solib_address (pc) + if lib: + stream.write (" from " + lib) + + stream.write ("\n") + + if full: + self.print_frame_locals (stream, func) + + def __getattr__ (self, name): + return getattr (self.frame, name) diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py new file mode 100644 index 0000000..b375c68 --- /dev/null +++ b/gdb/python/lib/gdb/__init__.py @@ -0,0 +1,19 @@ +# Startup code. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Load the require command by default. +import gdb.command.require diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py new file mode 100644 index 0000000..2baab5f --- /dev/null +++ b/gdb/python/lib/gdb/backtrace.py @@ -0,0 +1,42 @@ +# Filtering backtrace. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import itertools + +# Our only exports. +__all__ = ['push_frame_filter', 'create_frame_filter'] + +frame_filter = None + +def push_frame_filter (constructor): + """Register a new backtrace filter class with the 'backtrace' command. +The filter will be passed an iterator as an argument. The iterator +will return gdb.Frame-like objects. The filter should in turn act as +an iterator returning such objects.""" + global frame_filter + if frame_filter == None: + frame_filter = constructor + else: + frame_filter = lambda iterator: constructor (frame_filter (iterator)) + +def create_frame_filter (iter): + global frame_filter + if frame_filter is None: + return iter + return frame_filter (iter) + diff --git a/gdb/python/lib/gdb/command/__init__.py b/gdb/python/lib/gdb/command/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/command/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/command/alias.py b/gdb/python/lib/gdb/command/alias.py new file mode 100644 index 0000000..96b6618 --- /dev/null +++ b/gdb/python/lib/gdb/command/alias.py @@ -0,0 +1,59 @@ +# Alias command. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class AliasImplementation (gdb.Command): + def __init__ (self, name, real, doc): + # Have to set __doc__ before the super init call. + # It would be nice if gdb's help looked up __doc__ dynamically. + self.__doc__ = doc + # Note: no good way to complete :( + super (AliasImplementation, self).__init__ (name, gdb.COMMAND_NONE) + self.real = real + + def invoke(self, arg, from_tty): + gdb.execute (self.real + ' ' + arg, from_tty) + +class AliasCommand (gdb.Command): + """Alias one command to another. +In the simplest form, the first word is the name of the alias, and +the remaining words are the the expansion. +An '=' by itself can be used to define a multi-word alias; words +before the '=' are the name of the new command.""" + + def __init__ (self): + # Completion is not quite right here. + super (AliasCommand, self).__init__ ("alias", gdb.COMMAND_NONE, + gdb.COMPLETE_COMMAND) + + def invoke (self, arg, from_tty): + self.dont_repeat () + # Without some form of quoting we can't alias a multi-word + # command to another command. + args = arg.split() + try: + start = args.index ('=') + end = start + 1 + except ValueError: + start = 1 + end = 1 + target = " ".join(args[end:]) + AliasImplementation (" ".join (args[0:start]), target, + "This command is an alias for '%s'." % target) + +AliasCommand() diff --git a/gdb/python/lib/gdb/command/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py new file mode 100644 index 0000000..ec9a527 --- /dev/null +++ b/gdb/python/lib/gdb/command/backtrace.py @@ -0,0 +1,106 @@ +# New backtrace command. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import gdb.backtrace +import itertools +from gdb.FrameIterator import FrameIterator +from gdb.FrameWrapper import FrameWrapper +import sys + +class ReverseBacktraceParameter (gdb.Parameter): + """The new-backtrace command can show backtraces in 'reverse' order. +This means that the innermost frame will be printed last. +Note that reverse backtraces are more expensive to compute.""" + + set_doc = "Enable or disable reverse backtraces." + show_doc = "Show whether backtraces will be printed in reverse order." + + def __init__(self): + gdb.Parameter.__init__ (self, "reverse-backtrace", + gdb.COMMAND_STACK, gdb.PARAM_BOOLEAN) + # Default to compatibility with gdb. + self.value = False + +class FilteringBacktrace (gdb.Command): + """Print backtrace of all stack frames, or innermost COUNT frames. +With a negative argument, print outermost -COUNT frames. +Use of the 'full' qualifier also prints the values of the local variables. +Use of the 'raw' qualifier avoids any filtering by loadable modules. +""" + + def __init__ (self): + # FIXME: this is not working quite well enough to replace + # "backtrace" yet. + gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK) + self.reverse = ReverseBacktraceParameter() + + def reverse_iter (self, iter): + result = [] + for item in iter: + result.append (item) + result.reverse() + return result + + def final_n (self, iter, x): + result = [] + for item in iter: + result.append (item) + return result[x:] + + def invoke (self, arg, from_tty): + i = 0 + count = 0 + filter = True + full = False + + for word in arg.split (" "): + if word == '': + continue + elif word == 'raw': + filter = False + elif word == 'full': + full = True + else: + count = int (word) + + # FIXME: provide option to start at selected frame + # However, should still number as if starting from newest + newest_frame = gdb.selected_thread ().newest_frame () + iter = itertools.imap (FrameWrapper, + FrameIterator (newest_frame)) + if filter: + iter = gdb.backtrace.create_frame_filter (iter) + + # Now wrap in an iterator that numbers the frames. + iter = itertools.izip (itertools.count (0), iter) + + # Reverse if the user wanted that. + if self.reverse.value: + iter = self.reverse_iter (iter) + + # Extract sub-range user wants. + if count < 0: + iter = self.final_n (iter, count) + elif count > 0: + iter = itertools.islice (iter, 0, count) + + for pair in iter: + sys.stdout.write ("#%-2d" % pair[0]) + pair[1].describe (sys.stdout, full) + +FilteringBacktrace() diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py new file mode 100644 index 0000000..6fa48ff --- /dev/null +++ b/gdb/python/lib/gdb/command/ignore_errors.py @@ -0,0 +1,37 @@ +# Ignore errors in user commands. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class IgnoreErrorsCommand (gdb.Command): + """Execute a single command, ignoring all errors. +Only one-line commands are supported. +This is primarily useful in scripts.""" + + def __init__ (self): + super (IgnoreErrorsCommand, self).__init__ ("ignore-errors", + gdb.COMMAND_OBSCURE, + # FIXME... + gdb.COMPLETE_COMMAND) + + def invoke (self, arg, from_tty): + try: + gdb.execute (arg, from_tty) + except: + pass + +IgnoreErrorsCommand () diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py new file mode 100644 index 0000000..21a0bf0 --- /dev/null +++ b/gdb/python/lib/gdb/command/pahole.py @@ -0,0 +1,75 @@ +# pahole command for gdb + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class Pahole (gdb.Command): + """Show the holes in a structure. +This command takes a single argument, a type name. +It prints the type and displays comments showing where holes are.""" + + def __init__ (self): + super (Pahole, self).__init__ ("pahole", gdb.COMMAND_NONE, + gdb.COMPLETE_SYMBOL) + + def pahole (self, type, level, name): + if name is None: + name = '' + tag = type.tag + if tag is None: + tag = '' + print '%sstruct %s {' % (' ' * (2 * level), tag) + bitpos = 0 + for field in type.fields (): + # Skip static fields. + if not hasattr (field, ('bitpos')): + continue + + ftype = field.type.strip_typedefs() + + if bitpos != field.bitpos: + hole = field.bitpos - bitpos + print ' /* XXX %d bit hole, try to pack */' % hole + bitpos = field.bitpos + if field.bitsize > 0: + fieldsize = field.bitsize + else: + # TARGET_CHAR_BIT here... + fieldsize = 8 * ftype.sizeof + + # TARGET_CHAR_BIT + print ' /* %3d %3d */' % (int (bitpos / 8), int (fieldsize / 8)), + bitpos = bitpos + fieldsize + + if ftype.code == gdb.TYPE_CODE_STRUCT: + self.pahole (ftype, level + 1, field.name) + else: + print ' ' * (2 + 2 * level), + print '%s %s' % (str (ftype), field.name) + + print ' ' * (14 + 2 * level), + print '} %s' % name + + def invoke (self, arg, from_tty): + type = gdb.lookup_type (arg) + type = type.strip_typedefs () + if type.code != gdb.TYPE_CODE_STRUCT: + raise TypeError, '%s is not a struct type' % arg + print ' ' * 14, + self.pahole (type, 0, '') + +Pahole() diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py new file mode 100644 index 0000000..1fbc1e8 --- /dev/null +++ b/gdb/python/lib/gdb/command/require.py @@ -0,0 +1,57 @@ +# Demand-loading commands. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import os + +class RequireCommand (gdb.Command): + """Prefix command for requiring features.""" + + def __init__ (self): + super (RequireCommand, self).__init__ ("require", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE, + True) + +class RequireSubcommand (gdb.Command): + """Demand-load a command by name.""" + + def __init__ (self, name): + self.__doc__ = "Demand-load a %s by name." % name + super (RequireSubcommand, self).__init__ ("require %s" % name, + gdb.COMMAND_SUPPORT) + self.name = name + + def invoke (self, arg, from_tty): + for cmd in arg.split(): + exec ('import gdb.' + self.name + '.' + cmd, globals ()) + + def complete (self, text, word): + dir = gdb.pythondir + '/gdb/' + self.name + result = [] + for file in os.listdir(dir): + if not file.startswith (word) or not file.endswith ('.py'): + continue + feature = file[0:-3] + if feature == 'require' or feature == '__init__': + continue + result.append (feature) + return result + +RequireCommand() +RequireSubcommand("command") +RequireSubcommand("function") diff --git a/gdb/python/lib/gdb/command/save_breakpoints.py b/gdb/python/lib/gdb/command/save_breakpoints.py new file mode 100644 index 0000000..6143187 --- /dev/null +++ b/gdb/python/lib/gdb/command/save_breakpoints.py @@ -0,0 +1,65 @@ +# Save breakpoints. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import with_statement +import gdb + +class SavePrefixCommand (gdb.Command): + "Prefix command for saving things." + + def __init__ (self): + super (SavePrefixCommand, self).__init__ ("save", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE, True) + +class SaveBreakpointsCommand (gdb.Command): + """Save the current breakpoints to a file. +This command takes a single argument, a file name. +The breakpoints can be restored using the 'source' command.""" + + def __init__ (self): + super (SaveBreakpointsCommand, self).__init__ ("save breakpoints", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_FILENAME) + + def invoke (self, arg, from_tty): + self.dont_repeat () + bps = gdb.breakpoints () + if bps is None: + raise RuntimeError, 'No breakpoints to save' + with open (arg.strip (), 'w') as f: + for bp in bps: + print >> f, "break", bp.location, + if bp.thread is not None: + print >> f, " thread", bp.thread, + if bp.condition is not None: + print >> f, " if", bp.condition, + print >> f + if not bp.enabled: + print >> f, "disable $bpnum" + # Note: we don't save the ignore count; there doesn't + # seem to be much point. + commands = bp.commands + if commands is not None: + print >> f, "commands" + # Note that COMMANDS has a trailing newline. + print >> f, commands, + print >> f, "end" + print >> f + +SavePrefixCommand () +SaveBreakpointsCommand () diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py new file mode 100644 index 0000000..faf54ed --- /dev/null +++ b/gdb/python/lib/gdb/command/upto.py @@ -0,0 +1,129 @@ +# upto command. + +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import re +from gdb.FrameIterator import FrameIterator +from gdb.FrameWrapper import FrameWrapper + +class UptoPrefix (gdb.Command): + def __init__ (self): + super (UptoPrefix, self).__init__ ("upto", gdb.COMMAND_STACK, + prefix = True) + +class UptoImplementation (gdb.Command): + def __init__ (self, subcommand): + super (UptoImplementation, self).__init__ ("upto " + subcommand, + gdb.COMMAND_STACK) + + def search (self): + saved = gdb.selected_frame () + iter = FrameIterator (saved) + found = False + try: + for frame in iter: + frame.select () + try: + if self.filter (frame): + wrapper = FrameWrapper (frame) + wrapper.describe (sys.stdout, False) + return + except: + pass + except: + pass + saved.select () + raise RuntimeError, 'Could not find a matching frame' + + def invoke (self, arg, from_tty): + self.rx = re.compile (arg) + self.search () + +class UptoSymbolCommand (UptoImplementation): + """Select and print some calling stack frame, based on symbol. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose symbol matches the regular +expression.""" + + def __init__ (self): + super (UptoSymbolCommand, self).__init__ ("symbol") + + def filter (self, frame): + name = frame.name () + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoSourceCommand (UptoImplementation): + """Select and print some calling stack frame, based on source file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose source file name matches the +regular expression.""" + + def __init__ (self): + super (UptoSourceCommand, self).__init__ ("source") + + def filter (self, frame): + name = frame.find_sal ().symtab.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoObjectCommand (UptoImplementation): + """Select and print some calling stack frame, based on object file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose object file name matches the +regular expression.""" + + def __init__ (self): + super (UptoObjectCommand, self).__init__ ("object") + + def filter (self, frame): + name = frame.find_sal ().symtab.objfile.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoWhereCommand (UptoImplementation): + """Select and print some calling stack frame, based on expression. +The argument is an expression. This command moves up the stack, +parsing and evaluating the expression in each frame. This stops when +the expression evaluates to a non-zero (true) value.""" + + def __init__ (self): + super (UptoWhereCommand, self).__init__ ("where") + + def filter (self, frame): + try: + if gdb.parse_and_eval (self.expression): + return True + except: + pass + return False + + def invoke (self, arg, from_tty): + self.expression = arg + self.search () + +UptoPrefix () +UptoSymbolCommand () +UptoSourceCommand () +UptoObjectCommand () +UptoWhereCommand () diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/function/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py new file mode 100644 index 0000000..2b9c5c7 --- /dev/null +++ b/gdb/python/lib/gdb/function/caller_is.py @@ -0,0 +1,58 @@ +# Caller-is functions. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb +import re + +class CallerIs (gdb.Function): + """Return True if the calling function's name is equal to a string. +This function takes one or two arguments. +The first argument is the name of a function; if the calling function's +name is equal to this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerIs, self).__init__ ("caller_is") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return frame.name () == name.string () + +class CallerMatches (gdb.Function): + """Return True if the calling function's name matches a string. +This function takes one or two arguments. +The first argument is a regular expression; if the calling function's +name is matched by this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerMatches, self).__init__ ("caller_matches") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return re.match (name.string (), frame.name ()) is not None + +CallerIs() +CallerMatches() diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py new file mode 100644 index 0000000..debb3bb --- /dev/null +++ b/gdb/python/lib/gdb/function/in_scope.py @@ -0,0 +1,47 @@ +# In-scope function. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class InScope (gdb.Function): + """Return True if all the given variables or macros are in scope. +Takes one argument for each variable name to be checked.""" + + def __init__ (self): + super (InScope, self).__init__ ("in_scope") + + def invoke (self, *vars): + if len (vars) == 0: + raise TypeError, "in_scope takes at least one argument" + + # gdb.Value isn't hashable so it can't be put in a map. + # Convert to string first. + wanted = set (map (lambda x: x.string (), vars)) + found = set () + block = gdb.selected_frame ().block () + while block: + for sym in block: + if (sym.is_argument or sym.is_constant + or sym.is_function or sym.is_variable): + if sym.name in wanted: + found.add (sym.name) + + block = block.superblock + + return wanted == found + +InScope () diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c new file mode 100644 index 0000000..8019e9d --- /dev/null +++ b/gdb/python/py-block.c @@ -0,0 +1,265 @@ +/* Python interface to blocks. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "block.h" +#include "dictionary.h" +#include "symtab.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct block *block; +} block_object; + +typedef struct { + PyObject_HEAD + struct dictionary *dict; + struct dict_iterator iter; + int initialized_p; +} block_syms_iterator_object; + +static PyTypeObject block_syms_iterator_object_type; + +static PyObject * +blpy_iter (PyObject *self) +{ + block_syms_iterator_object *block_iter_obj; + + block_iter_obj = PyObject_New (block_syms_iterator_object, + &block_syms_iterator_object_type); + if (block_iter_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate iterator object."); + return NULL; + } + + block_iter_obj->dict = BLOCK_DICT (((block_object *) self)->block); + block_iter_obj->initialized_p = 0; + + return (PyObject *) block_iter_obj; +} + +static PyObject * +blpy_get_start (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_START (self_block->block)); +} + +static PyObject * +blpy_get_end (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + + return PyLong_FromUnsignedLongLong (BLOCK_END (self_block->block)); +} + +static PyObject * +blpy_get_function (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct symbol *sym; + + sym = BLOCK_FUNCTION (self_block->block); + if (sym) + return symbol_to_symbol_object (sym); + + Py_RETURN_NONE; +} + +static PyObject * +blpy_get_superblock (PyObject *self, void *closure) +{ + block_object *self_block = (block_object *) self; + struct block *block; + + block = BLOCK_SUPERBLOCK (self_block->block); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +PyObject * +block_to_block_object (struct block *block) +{ + block_object *block_obj; + + block_obj = PyObject_New (block_object, &block_object_type); + if (block_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate block object."); + return NULL; + } + + block_obj->block = block; + + return (PyObject *) block_obj; +} + +struct block * +block_object_to_block (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &block_object_type)) + return NULL; + return ((block_object *) obj)->block; +} + +static PyObject * +blpy_block_syms_iter (PyObject *self) +{ + return self; +} + +static PyObject * +blpy_block_syms_iternext (PyObject *self) +{ + block_syms_iterator_object *iter_obj = (block_syms_iterator_object *) self; + struct symbol *sym; + + if (!iter_obj->initialized_p) + { + sym = dict_iterator_first (iter_obj->dict, &(iter_obj->iter)); + iter_obj->initialized_p = 1; + } + else + sym = dict_iterator_next (&(iter_obj->iter)); + + return (sym == NULL)? NULL : symbol_to_symbol_object (sym); +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +PyObject * +gdbpy_block_for_pc (PyObject *self, PyObject *args) +{ + unsigned PY_LONG_LONG pc; + struct block *block; + PyObject *sym_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + block = block_for_pc (pc); + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + +void +gdbpy_initialize_blocks (void) +{ + block_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&block_object_type) < 0) + return; + + block_syms_iterator_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&block_syms_iterator_object_type) < 0) + return; + + Py_INCREF (&block_object_type); + PyModule_AddObject (gdb_module, "Block", (PyObject *) &block_object_type); + + Py_INCREF (&block_syms_iterator_object_type); + PyModule_AddObject (gdb_module, "BlockIterator", + (PyObject *) &block_syms_iterator_object_type); +} + + + +static PyGetSetDef block_object_getset[] = { + { "start", blpy_get_start, NULL, "Start address of the block.", NULL }, + { "end", blpy_get_end, NULL, "End address of the block.", NULL }, + { "function", blpy_get_function, NULL, + "Symbol that names the block, or None.", NULL }, + { "superblock", blpy_get_superblock, NULL, + "Block containing the block, or None.", NULL }, + { NULL } /* Sentinel */ +}; + +PyTypeObject block_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Block", /*tp_name*/ + sizeof (block_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB block object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + blpy_iter, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + block_object_getset /* tp_getset */ +}; + +static PyTypeObject block_syms_iterator_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.BlockIterator", /*tp_name*/ + sizeof (block_syms_iterator_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB block syms iterator object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + blpy_block_syms_iter, /* tp_iter */ + blpy_block_syms_iternext, /* tp_iternext */ + 0 /* tp_methods */ +}; diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c new file mode 100644 index 0000000..783385e --- /dev/null +++ b/gdb/python/py-breakpoint.c @@ -0,0 +1,666 @@ +/* Python interface to breakpoints + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "breakpoint.h" +#include "gdbcmd.h" +#include "gdbthread.h" +#include "observer.h" +#include "arch-utils.h" +#include "language.h" + +/* From breakpoint.c. */ +extern struct breakpoint *breakpoint_chain; + + +typedef struct breakpoint_object breakpoint_object; + +static PyTypeObject breakpoint_object_type; + +/* A dynamically allocated vector of breakpoint objects. Each + breakpoint has a number. A breakpoint is valid if its slot in this + vector is non-null. When a breakpoint is deleted, we drop our + reference to it and zero its slot; this is how we let the Python + object have a lifetime which is independent from that of the gdb + breakpoint. */ +static breakpoint_object **bppy_breakpoints; + +/* Number of slots in bppy_breakpoints. */ +static int bppy_slots; + +/* Number of live breakpoints. */ +static int bppy_live; + +/* Variables used to pass information between the Breakpoint + constructor and the breakpoint-created hook function. */ +static breakpoint_object *bppy_pending_object; + +struct breakpoint_object +{ + PyObject_HEAD + + /* The breakpoint number according to gdb. */ + int number; + + /* The gdb breakpoint object, or NULL if the breakpoint has been + deleted. */ + struct breakpoint *bp; +}; + +/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */ +#define BPPY_VALID_P(Num) \ + ((Num) >= 0 \ + && (Num) < bppy_slots \ + && bppy_breakpoints[Num] != NULL) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. */ +#define BPPY_REQUIRE_VALID(Breakpoint) \ + do { \ + if (! BPPY_VALID_P ((Breakpoint)->number)) \ + return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ + (Breakpoint)->number); \ + } while (0) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + exception if it is invalid. This macro is for use in setter functions. */ +#define BPPY_SET_REQUIRE_VALID(Breakpoint) \ + do { \ + if (! BPPY_VALID_P ((Breakpoint)->number)) \ + { \ + PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \ + (Breakpoint)->number); \ + return -1; \ + } \ + } while (0) + +/* Python function which checks the validity of a breakpoint object. */ +static PyObject * +bppy_is_valid (PyObject *self, PyObject *args) +{ + if (((breakpoint_object *) self)->bp) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to test whether or not the breakpoint is enabled. */ +static PyObject * +bppy_get_enabled (PyObject *self, void *closure) +{ + if (! ((breakpoint_object *) self)->bp) + Py_RETURN_FALSE; + /* Not clear what we really want here. */ + if (((breakpoint_object *) self)->bp->enable_state == bp_enabled) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to test whether or not the breakpoint is silent. */ +static PyObject * +bppy_get_silent (PyObject *self, void *closure) +{ + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + if (((breakpoint_object *) self)->bp->silent) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + +/* Python function to set the enabled state of a breakpoint. */ +static int +bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int cmp; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `enabled' attribute"); + return -1; + } + else if (! PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `enabled' must be a boolean"); + return -1; + } + + cmp = PyObject_IsTrue (newvalue); + if (cmp < 0) + return -1; + else if (cmp == 1) + enable_breakpoint (self_bp->bp); + else + disable_breakpoint (self_bp->bp); + return 0; +} + +/* Python function to set the 'silent' state of a breakpoint. */ +static int +bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int cmp; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `silent' attribute"); + return -1; + } + else if (! PyBool_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `silent' must be a boolean"); + return -1; + } + + cmp = PyObject_IsTrue (newvalue); + if (cmp < 0) + return -1; + else + self_bp->bp->silent = cmp; + + return 0; +} + +/* Python function to set the thread of a breakpoint. */ +static int +bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + int id; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `thread' attribute"); + return -1; + } + else if (PyInt_Check (newvalue)) + { + id = (int) PyInt_AsLong (newvalue); + if (! valid_thread_id (id)) + { + PyErr_SetString (PyExc_RuntimeError, "invalid thread id"); + return -1; + } + } + else if (newvalue == Py_None) + id = -1; + else + { + PyErr_SetString (PyExc_TypeError, + "the value of `thread' must be an integer or None"); + return -1; + } + + self_bp->bp->thread = id; + + return 0; +} + +/* Python function to set the ignore count of a breakpoint. */ +static int +bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + long value; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, + "cannot delete `ignore_count' attribute"); + return -1; + } + else if (! PyInt_Check (newvalue)) + { + PyErr_SetString (PyExc_TypeError, + "the value of `ignore_count' must be an integer"); + return -1; + } + + value = PyInt_AsLong (newvalue); + if (value < 0) + value = 0; + set_ignore_count (self_bp->number, (int) value, 0); + + return 0; +} + +/* Python function to set the hit count of a breakpoint. */ +static int +bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `hit_count' attribute"); + return -1; + } + else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0) + { + PyErr_SetString (PyExc_AttributeError, + "the value of `hit_count' must be zero"); + return -1; + } + + self_bp->bp->hit_count = 0; + + return 0; +} + +/* Python function to get the location of a breakpoint. */ +static PyObject * +bppy_get_location (PyObject *self, void *closure) +{ + char *str; + + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + str = ((breakpoint_object *) self)->bp->addr_string; + /* FIXME: watchpoints? tracepoints? */ + if (! str) + str = ""; + return PyString_Decode (str, strlen (str), host_charset (), NULL); +} + +/* Python function to get the condition expression of a breakpoint. */ +static PyObject * +bppy_get_condition (PyObject *self, void *closure) +{ + char *str; + BPPY_REQUIRE_VALID ((breakpoint_object *) self); + + str = ((breakpoint_object *) self)->bp->cond_string; + if (! str) + Py_RETURN_NONE; + return PyString_Decode (str, strlen (str), host_charset (), NULL); +} + +static int +bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure) +{ + char *exp; + breakpoint_object *self_bp = (breakpoint_object *) self; + volatile struct gdb_exception except; + + BPPY_SET_REQUIRE_VALID (self_bp); + + if (newvalue == NULL) + { + PyErr_SetString (PyExc_TypeError, "cannot delete `condition' attribute"); + return -1; + } + else if (newvalue == Py_None) + exp = ""; + else + { + exp = python_string_to_host_string (newvalue); + if (exp == NULL) + return -1; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_breakpoint_condition (self_bp->bp, exp, 0); + } + GDB_PY_SET_HANDLE_EXCEPTION (except); + + return 0; +} + +/* Python function to get the commands attached to a breakpoint. */ +static PyObject * +bppy_get_commands (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + long length; + volatile struct gdb_exception except; + struct ui_file *string_file; + struct cleanup *chain; + PyObject *result; + char *cmdstr; + + BPPY_REQUIRE_VALID (self_bp); + + if (! self_bp->bp->commands) + Py_RETURN_NONE; + + string_file = mem_fileopen (); + chain = make_cleanup_ui_file_delete (string_file); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + /* FIXME: this can fail. Maybe we need to be making a new + ui_out object here? */ + ui_out_redirect (uiout, string_file); + print_command_lines (uiout, self_bp->bp->commands, 0); + ui_out_redirect (uiout, NULL); + } + cmdstr = ui_file_xstrdup (string_file, &length); + GDB_PY_HANDLE_EXCEPTION (except); + + result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL); + do_cleanups (chain); + xfree (cmdstr); + return result; +} + +/* Python function to get the breakpoint's number. */ +static PyObject * +bppy_get_number (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->number); +} + +/* Python function to get the breakpoint's thread ID. */ +static PyObject * +bppy_get_thread (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + if (self_bp->bp->thread == -1) + Py_RETURN_NONE; + + return PyInt_FromLong (self_bp->bp->thread); +} + +/* Python function to get the breakpoint's hit count. */ +static PyObject * +bppy_get_hit_count (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->bp->hit_count); +} + +/* Python function to get the breakpoint's ignore count. */ +static PyObject * +bppy_get_ignore_count (PyObject *self, void *closure) +{ + breakpoint_object *self_bp = (breakpoint_object *) self; + + BPPY_REQUIRE_VALID (self_bp); + + return PyInt_FromLong (self_bp->bp->ignore_count); +} + +/* Python function to create a new breakpoint. */ +static PyObject * +bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) +{ + PyObject *result; + char *spec; + volatile struct gdb_exception except; + + /* FIXME: allow condition, thread, temporary, ... ? */ + if (! PyArg_ParseTuple (args, "s", &spec)) + return NULL; + result = subtype->tp_alloc (subtype, 0); + if (! result) + return NULL; + bppy_pending_object = (breakpoint_object *) result; + bppy_pending_object->number = -1; + bppy_pending_object->bp = NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + set_breakpoint (python_gdbarch, spec, NULL, 0, 0, -1, 0, + AUTO_BOOLEAN_TRUE, 1); + } + if (except.reason < 0) + { + subtype->tp_free (result); + return PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + } + + BPPY_REQUIRE_VALID ((breakpoint_object *) result); + return result; +} + + + +/* Static function to return a tuple holding all breakpoints. */ + +PyObject * +gdbpy_breakpoints (PyObject *self, PyObject *args) +{ + PyObject *result; + + if (bppy_live == 0) + Py_RETURN_NONE; + + result = PyTuple_New (bppy_live); + if (result) + { + int i, out = 0; + for (i = 0; out < bppy_live; ++i) + { + if (! bppy_breakpoints[i]) + continue; + Py_INCREF (bppy_breakpoints[i]); + PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]); + ++out; + } + } + return result; +} + + + +/* Event callback functions. */ + +/* Callback that is used when a breakpoint is created. This function + will create a new Python breakpoint object. */ +static void +gdbpy_breakpoint_created (int num) +{ + breakpoint_object *newbp; + struct breakpoint *bp; + struct cleanup *cleanup; + + if (num < 0) + return; + + for (bp = breakpoint_chain; bp; bp = bp->next) + if (bp->number == num) + break; + if (! bp) + return; + + if (num >= bppy_slots) + { + int old = bppy_slots; + bppy_slots = bppy_slots * 2 + 10; + bppy_breakpoints + = (breakpoint_object **) xrealloc (bppy_breakpoints, + (bppy_slots + * sizeof (breakpoint_object *))); + memset (&bppy_breakpoints[old], 0, + (bppy_slots - old) * sizeof (PyObject *)); + } + + ++bppy_live; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + if (bppy_pending_object) + { + newbp = bppy_pending_object; + bppy_pending_object = NULL; + } + else + newbp = PyObject_New (breakpoint_object, &breakpoint_object_type); + if (newbp) + { + PyObject *hookfn; + + newbp->number = num; + newbp->bp = bp; + bppy_breakpoints[num] = newbp; + + hookfn = gdbpy_get_hook_function ("new_breakpoint"); + if (hookfn) + { + PyObject *result; + result = PyObject_CallFunctionObjArgs (hookfn, newbp, NULL); + if (result) + { + Py_DECREF (result); + } + Py_DECREF (hookfn); + } + } + + /* Just ignore errors here. */ + PyErr_Clear (); + + do_cleanups (cleanup); +} + +/* Callback that is used when a breakpoint is deleted. This will + invalidate the corresponding Python object. */ +static void +gdbpy_breakpoint_deleted (int num) +{ + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + if (BPPY_VALID_P (num)) + { + bppy_breakpoints[num]->bp = NULL; + Py_DECREF (bppy_breakpoints[num]); + bppy_breakpoints[num] = NULL; + --bppy_live; + } + do_cleanups (cleanup); +} + + + +/* Initialize the Python breakpoint code. */ +void +gdbpy_initialize_breakpoints (void) +{ + breakpoint_object_type.tp_new = bppy_new; + if (PyType_Ready (&breakpoint_object_type) < 0) + return; + + Py_INCREF (&breakpoint_object_type); + PyModule_AddObject (gdb_module, "Breakpoint", + (PyObject *) &breakpoint_object_type); + + observer_attach_breakpoint_created (gdbpy_breakpoint_created); + observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted); +} + + + +static PyGetSetDef breakpoint_object_getset[] = { + { "enabled", bppy_get_enabled, bppy_set_enabled, + "Boolean telling whether the breakpoint is enabled.", NULL }, + { "silent", bppy_get_silent, bppy_set_silent, + "Boolean telling whether the breakpoint is silent.", NULL }, + { "thread", bppy_get_thread, bppy_set_thread, + "Thread ID for the breakpoint.\n\ +If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\ +If the value is None, then this breakpoint not thread-specific.\n\ +No other type of value can be used.", NULL }, + { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count, + "Number of times this breakpoint should be automatically continued.", + NULL }, + { "number", bppy_get_number, NULL, + "Breakpoint's number assigned by GDB.", NULL }, + { "hit_count", bppy_get_hit_count, bppy_set_hit_count, + "Number of times the breakpoint has been hit.\n\ +Can be set to zero to clear the count. No other value is valid\n\ +when setting this property.", NULL }, + { "location", bppy_get_location, NULL, + "Location of the breakpoint, as specified by the user.", NULL}, + { "condition", bppy_get_condition, bppy_set_condition, + "Condition of the breakpoint, as specified by the user,\ +or None if no condition set."}, + { "commands", bppy_get_commands, NULL, + "Commands of the breakpoint, as specified by the user."}, + { NULL } /* Sentinel. */ +}; + +static PyMethodDef breakpoint_object_methods[] = +{ + { "is_valid", bppy_is_valid, METH_NOARGS, + "Return true if this breakpoint is valid, false if not." }, + { NULL } /* Sentinel. */ +}; + +static PyTypeObject breakpoint_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Breakpoint", /*tp_name*/ + sizeof (breakpoint_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB breakpoint object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + breakpoint_object_methods, /* tp_methods */ + 0, /* tp_members */ + breakpoint_object_getset /* tp_getset */ +}; diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c index ae462d9..dd364df 100644 --- a/gdb/python/py-cmd.c +++ b/gdb/python/py-cmd.c @@ -49,8 +49,7 @@ static struct cmdpy_completer completers[] = #define N_COMPLETERS (sizeof (completers) / sizeof (completers[0])) -/* A gdb command. For the time being only ordinary commands (not - set/show commands) are allowed. */ +/* A gdb command. */ struct cmdpy_object { PyObject_HEAD @@ -263,10 +262,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 +301,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 +310,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 +401,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) return -1; } - cmd_name = parse_command_name (name, &cmd_list); + cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist); if (! cmd_name) return -1; diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index 334bad9..524353d 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -202,10 +202,59 @@ frapy_pc (PyObject *self, PyObject *args) return PyLong_FromUnsignedLongLong (pc); } +/* Implementation of gdb.Frame.block (self) -> gdb.Block. + Returns the frame's code block. */ + +static PyObject * +frapy_block (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + struct block *block = NULL; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + block = block_for_pc (get_frame_address_in_block (frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (block) + return block_to_block_object (block); + + Py_RETURN_NONE; +} + + +/* Implementation of gdb.Frame.function (self) -> gdb.Symbol. + Returns the symbol for the function corresponding to this frame. */ + +static PyObject * +frapy_function (PyObject *self, PyObject *args) +{ + struct symbol *sym = NULL; + struct frame_info *frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + sym = find_pc_function (get_frame_address_in_block (frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (sym) + return symbol_to_symbol_object (sym); + + Py_RETURN_NONE; +} + /* Convert a frame_info struct to a Python Frame object. Sets a Python exception and returns NULL on error. */ -static frame_object * +PyObject * frame_info_to_frame_object (struct frame_info *frame) { frame_object *frame_obj; @@ -235,7 +284,7 @@ frame_info_to_frame_object (struct frame_info *frame) frame_obj->gdbarch = get_frame_arch (frame); - return frame_obj; + return (PyObject *) frame_obj; } /* Implementation of gdb.Frame.older (self) -> gdb.Frame. @@ -296,7 +345,30 @@ frapy_newer (PyObject *self, PyObject *args) return next_obj; } -/* Implementation of gdb.Frame.read_var_value (self, variable) -> gdb.Value. +/* Implementation of gdb.Frame.find_sal (self) -> gdb.Symtab_and_line. + Returns the frame's symtab and line. */ + +static PyObject * +frapy_find_sal (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + struct symtab_and_line sal; + volatile struct gdb_exception except; + PyObject *sal_obj = NULL; /* Initialize to appease gcc warning. */ + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + + find_frame_sal (frame, &sal); + sal_obj = symtab_and_line_to_sal_object (sal); + } + GDB_PY_HANDLE_EXCEPTION (except); + + return sal_obj; +} + +/* Implementation of gdb.Frame.read_var (self, variable) -> gdb.Value. Returns the value of the given variable in this frame. The argument must be a string. Returns None if GDB can't find the specified variable. */ @@ -312,7 +384,9 @@ frapy_read_var (PyObject *self, PyObject *args) if (!PyArg_ParseTuple (args, "O", &sym_obj)) return NULL; - if (gdbpy_is_string (sym_obj)) + if (PyObject_TypeCheck (sym_obj, &symbol_object_type)) + var = symbol_object_to_symbol (sym_obj); + else if (gdbpy_is_string (sym_obj)) { char *var_name; struct block *block = NULL; @@ -365,6 +439,25 @@ frapy_read_var (PyObject *self, PyObject *args) Py_RETURN_NONE; } +/* Select this frame. */ + +static PyObject * +frapy_select (PyObject *self, PyObject *args) +{ + struct frame_info *fi; + frame_object *frame = (frame_object *) self; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + FRAPY_REQUIRE_VALID (frame, fi); + select_frame (fi); + } + GDB_PY_HANDLE_EXCEPTION (except); + + Py_RETURN_NONE; +} + /* Implementation of gdb.selected_frame () -> gdb.Frame. Returns the selected frame object. */ @@ -372,7 +465,7 @@ PyObject * gdbpy_selected_frame (PyObject *self, PyObject *args) { struct frame_info *frame; - frame_object *frame_obj = NULL; /* Initialize to appease gcc warning. */ + PyObject *frame_obj = NULL; /* Initialize to appease gcc warning. */ volatile struct gdb_exception except; TRY_CATCH (except, RETURN_MASK_ALL) @@ -382,7 +475,7 @@ gdbpy_selected_frame (PyObject *self, PyObject *args) } GDB_PY_HANDLE_EXCEPTION (except); - return (PyObject *) frame_obj; + return frame_obj; } /* Implementation of gdb.stop_reason_string (Integer) -> String. @@ -484,15 +577,26 @@ Return the reason why it's not possible to find frames older than this." }, { "pc", frapy_pc, METH_NOARGS, "pc () -> Long.\n\ Return the frame's resume address." }, + { "block", frapy_block, METH_NOARGS, + "block () -> gdb.Block.\n\ +Return the frame's code block." }, + { "function", frapy_function, METH_NOARGS, + "function () -> gdb.Symbol.\n\ +Returns the symbol for the function corresponding to this frame." }, { "older", frapy_older, METH_NOARGS, "older () -> gdb.Frame.\n\ Return the frame that called this frame." }, { "newer", frapy_newer, METH_NOARGS, "newer () -> gdb.Frame.\n\ Return the frame called by this frame." }, + { "find_sal", frapy_find_sal, METH_NOARGS, + "find_sal () -> gdb.Symtab_and_line.\n\ +Return the frame's symtab and line." }, { "read_var", frapy_read_var, METH_VARARGS, "read_var (variable) -> gdb.Value.\n\ Return the value of the variable in this frame." }, + { "select", frapy_select, METH_NOARGS, + "Select this frame as the user's current frame." }, {NULL} /* Sentinel */ }; diff --git a/gdb/python/py-hooks.c b/gdb/python/py-hooks.c new file mode 100644 index 0000000..a3140bc --- /dev/null +++ b/gdb/python/py-hooks.c @@ -0,0 +1,50 @@ +/* Notifications from gdb to Python + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "cli/cli-decode.h" +#include "charset.h" +#include "python.h" +#include "python-internal.h" +#include "observer.h" + +PyObject * +gdbpy_get_hook_function (const char *name) +{ + PyObject *hooks; + PyObject *result; + + if (! PyObject_HasAttrString (gdb_module, "hooks")) + return NULL; + hooks = PyObject_GetAttrString (gdb_module, "hooks"); + if (! hooks) + return NULL; + /* The cast is because the Python function doesn't declare const argument. + This is a problem in Python version 2.4, but not in 2.5. */ + if (! PyObject_HasAttrString (hooks, (char *) name)) + { + Py_DECREF (hooks); + return NULL; + } + /* The cast is because the Python function doesn't declare const argument. + This is a problem in Python version 2.4, but not in 2.5. */ + result = PyObject_GetAttrString (hooks, (char *) name); + Py_DECREF (hooks); + return result; +} diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c new file mode 100644 index 0000000..b259ab5 --- /dev/null +++ b/gdb/python/py-inferior.c @@ -0,0 +1,934 @@ +/* Python interface to inferiors. + + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "exceptions.h" +#include "gdbcore.h" +#include "gdbthread.h" +#include "inferior.h" +#include "observer.h" +#include "python-internal.h" +#include "arch-utils.h" +#include "language.h" + +struct threadlist_entry { + thread_object *thread_obj; + struct threadlist_entry *next; +}; + +typedef struct +{ + PyObject_HEAD + + /* The inferior we represent. */ + struct inferior *inferior; + + /* thread_object instances under this inferior. This list owns a reference + to each object it contains. */ + struct threadlist_entry *threads; + + /* Number of threads in the list. */ + int nthreads; +} inferior_object; + +static PyTypeObject inferior_object_type; + +typedef struct { + PyObject_HEAD + void *buffer; + + /* These are kept just for mbpy_str. */ + CORE_ADDR addr; + CORE_ADDR length; +} membuf_object; + +static PyTypeObject membuf_object_type; + +/* Require that INFERIOR be a valid inferior ID. */ +#define INFPY_REQUIRE_VALID(Inferior) \ + do { \ + if (!Inferior->inferior) \ + { \ + PyErr_SetString (PyExc_RuntimeError, \ + "inferior no longer exists"); \ + return NULL; \ + } \ + } while (0) + +struct inflist_entry { + inferior_object *inf_obj; + struct inflist_entry *next; +}; + + + +/* Inferior objects list. */ + +/* List containing inferior_objects. This list owns a reference to each + object it contains. */ +static struct inflist_entry *gdbpy_inferior_list; + +static int ninferiors; + + +/* An observer callback function that is called when an inferior has + been created. Creates a corresponding Python object for the inferior + and adds it to the list. */ +static void +add_inferior_object (int pid) +{ + struct inferior *inf = find_inferior_pid (pid); + inferior_object *inf_obj; + struct inflist_entry *entry; + struct cleanup *cleanup; + + if (!inf) + { + warning (_("Can't create Python Inferior object.")); + return; + } + + /* While creating new inferior no inferior thread is available. Therefore + get_current_arch has no valid current frame (and it would crash). */ + + cleanup = ensure_python_env (target_gdbarch, current_language); + + inf_obj = PyObject_New (inferior_object, &inferior_object_type); + if (!inf_obj) + { + warning (_("Can't create Python Inferior object.")); + gdbpy_print_stack (); + do_cleanups (cleanup); + return; + } + + inf_obj->inferior = inf; + inf_obj->threads = NULL; + inf_obj->nthreads = 0; + + entry = xmalloc (sizeof (struct inflist_entry)); + entry->inf_obj = inf_obj; + entry->next = gdbpy_inferior_list; + + gdbpy_inferior_list = entry; + + ninferiors++; + + do_cleanups (cleanup); +} + +/* An observer callback function that is called when an inferior has + been deleted. Removes the corresponding Python object from the + inferior list, and removes the list's reference to the object. */ +static void +delete_inferior_object (int pid) +{ + struct cleanup *cleanup; + struct inflist_entry **inf_entry, *inf_tmp; + struct threadlist_entry *th_entry, *th_tmp; + + /* Find inferior_object for the given PID. */ + for (inf_entry = &gdbpy_inferior_list; *inf_entry != NULL; + inf_entry = &(*inf_entry)->next) + if ((*inf_entry)->inf_obj->inferior->pid == pid) + break; + + if (!*inf_entry) + return; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + inf_tmp = *inf_entry; + inf_tmp->inf_obj->inferior = NULL; + + /* Deallocate threads list. */ + for (th_entry = inf_tmp->inf_obj->threads; th_entry != NULL;) + { + Py_DECREF (th_entry->thread_obj); + + th_tmp = th_entry; + th_entry = th_entry->next; + xfree (th_tmp); + } + + inf_tmp->inf_obj->nthreads = 0; + + *inf_entry = (*inf_entry)->next; + Py_DECREF (inf_tmp->inf_obj); + xfree (inf_tmp); + + ninferiors--; + + do_cleanups (cleanup); +} + +/* Finds the Python Inferior object for the given pid. Returns a borrowed + reference. */ +PyObject * +find_inferior_object (int pid) +{ + struct inflist_entry *p; + + for (p = gdbpy_inferior_list; p != NULL; p = p->next) + if (p->inf_obj->inferior->pid == pid) + return (PyObject *) p->inf_obj; + + return NULL; +} + +/* Finds the Python InferiorThread object for the given ptid. Returns a + borrowed reference. */ +thread_object * +find_thread_object (ptid_t ptid) +{ + int pid; + struct inflist_entry *p; + struct threadlist_entry *q; + + pid = PIDGET (ptid); + for (p = gdbpy_inferior_list; p != NULL; p = p->next) + if (p->inf_obj->inferior->pid == pid) + for (q = p->inf_obj->threads; q != NULL; q = q->next) + if (ptid_equal (q->thread_obj->thread->ptid, ptid)) + return q->thread_obj; + + return NULL; +} + + + +/* Inferior object. */ + +static void +add_thread_object (struct thread_info *tp) +{ + struct cleanup *cleanup; + thread_object *thread_obj; + inferior_object *inf_obj; + struct threadlist_entry *entry; + + /* Note that the arch does not matter here, because we can't run + arbitrary Python code. Calling get_current_arch here will + crash. */ + cleanup = ensure_python_env (target_gdbarch, current_language); + + thread_obj = create_thread_object (tp); + if (!thread_obj) + { + warning (_("Can't create Python InferiorThread object.")); + gdbpy_print_stack (); + do_cleanups (cleanup); + return; + } + + inf_obj = (inferior_object *) thread_obj->inf_obj; + + entry = xmalloc (sizeof (struct threadlist_entry)); + entry->thread_obj = thread_obj; + entry->next = inf_obj->threads; + + inf_obj->threads = entry; + inf_obj->nthreads++; + + do_cleanups (cleanup); +} + +static void +delete_thread_object (struct thread_info *tp, int ignore) +{ + struct cleanup *cleanup; + inferior_object *inf_obj; + thread_object *thread_obj; + struct threadlist_entry **entry, *tmp; + + inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid)); + if (!inf_obj) + return; + + /* Find thread entry in its inferior's thread_list. */ + for (entry = &inf_obj->threads; *entry != NULL; entry = &(*entry)->next) + if ((*entry)->thread_obj->thread == tp) + break; + + if (!*entry) + return; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + tmp = *entry; + tmp->thread_obj->thread = NULL; + + *entry = (*entry)->next; + inf_obj->nthreads--; + + Py_DECREF (tmp->thread_obj); + xfree (tmp); + + + do_cleanups (cleanup); +} + +static PyObject * +infpy_threads (PyObject *self, PyObject *args) +{ + int i; + struct threadlist_entry *entry; + inferior_object *inf_obj = (inferior_object *) self; + PyObject *tuple; + + INFPY_REQUIRE_VALID (inf_obj); + + + tuple = PyTuple_New (inf_obj->nthreads); + if (!tuple) + return NULL; + + /* The list is in reverse order of thread age (i.e., newest comes first), + is this a problem? */ + for (i = 0, entry = inf_obj->threads; i < inf_obj->nthreads; + i++, entry = entry->next) + { + Py_INCREF (entry->thread_obj); + PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->thread_obj); + } + + return tuple; +} + +static PyObject * +infpy_get_num (PyObject *self, void *closure) +{ + inferior_object *inf = (inferior_object *) self; + + INFPY_REQUIRE_VALID (inf); + + return PyLong_FromLong (inf->inferior->num); +} + +static PyObject * +infpy_get_pid (PyObject *self, void *closure) +{ + inferior_object *inf = (inferior_object *) self; + + INFPY_REQUIRE_VALID (inf); + + return PyLong_FromLong (inf->inferior->pid); +} + +static PyObject * +infpy_get_was_attached (PyObject *self, void *closure) +{ + inferior_object *inf = (inferior_object *) self; + INFPY_REQUIRE_VALID (inf); + if (inf->inferior->attach_flag) + Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + + + +/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...). + Returns a list of all inferiors. */ + +PyObject * +gdbpy_inferiors (PyObject *unused, PyObject *unused2) +{ + int i; + struct inflist_entry *entry; + PyObject *tuple; + + tuple = PyTuple_New (ninferiors); + if (!tuple) + return NULL; + + /* The list is in reverse order of inferior age (i.e., newest comes first), + is this a problem? */ + for (i = 0, entry = gdbpy_inferior_list; + i < ninferiors; + i++, entry = entry->next) + { + Py_INCREF (entry->inf_obj); + PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->inf_obj); + } + + return tuple; +} + + + +/* Membuf and memory manipulation. */ + +/* Implementation of gdb.read_memory (address, length). + Returns a Python buffer object with LENGTH bytes of the inferior's memory + at ADDRESS. Both arguments are integers. */ + +static PyObject * +infpy_read_memory (PyObject *self, PyObject *args) +{ + int error = 0; + CORE_ADDR addr, length; + void *buffer = NULL; + membuf_object *membuf_obj; + PyObject *addr_obj, *length_obj; + struct cleanup *cleanups; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "OO", &addr_obj, &length_obj)) + return NULL; + + cleanups = make_cleanup (null_cleanup, NULL); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!get_addr_from_python (addr_obj, &addr) + || !get_addr_from_python (length_obj, &length)) + { + error = 1; + break; + } + + buffer = xmalloc (length); + make_cleanup (xfree, buffer); + + read_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (error) + { + do_cleanups (cleanups); + return NULL; + } + + membuf_obj = PyObject_New (membuf_object, &membuf_object_type); + if (membuf_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate memory buffer object."); + do_cleanups (cleanups); + return NULL; + } + + discard_cleanups (cleanups); + + membuf_obj->buffer = buffer; + membuf_obj->addr = addr; + membuf_obj->length = length; + + return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, + Py_END_OF_BUFFER); +} + +/* Implementation of gdb.write_memory (address, buffer [, length]). + Writes the contents of BUFFER (a Python object supporting the read buffer + protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from + BUFFER, or its entire contents if the argument is not provided. The + function returns nothing. */ + +static PyObject * +infpy_write_memory (PyObject *self, PyObject *args) +{ + int buf_len, error = 0; + const char *buffer; + CORE_ADDR addr, length; + PyObject *addr_obj, *length_obj = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "Os#|O", &addr_obj, &buffer, &buf_len, + &length_obj)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!get_addr_from_python (addr_obj, &addr)) + { + error = 1; + break; + } + + if (!length_obj) + length = buf_len; + else if (!get_addr_from_python (length_obj, &length)) + { + error = 1; + break; + } + + write_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (error) + return NULL; + + Py_RETURN_NONE; +} + +/* Destructor of Membuf objects. */ + +static void +mbpy_dealloc (PyObject *self) +{ + xfree (((membuf_object *) self)->buffer); + self->ob_type->tp_free (self); +} + +/* Return a description of the Membuf object. */ + +static PyObject * +mbpy_str (PyObject *self) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + return PyString_FromFormat ("memory buffer for address %s, %s bytes long", + paddress (python_gdbarch, membuf_obj->addr), + pulongest (membuf_obj->length)); +} + +static Py_ssize_t +get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + if (segment) + { + PyErr_SetString (PyExc_SystemError, + "The memory buffer supports only one segment."); + return -1; + } + + *ptrptr = membuf_obj->buffer; + + return membuf_obj->length; +} + +static Py_ssize_t +get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + return get_read_buffer (self, segment, ptrptr); +} + +static Py_ssize_t +get_seg_count (PyObject *self, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = ((membuf_object *) self)->length; + + return 1; +} + +static Py_ssize_t +get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) +{ + void *ptr = NULL; + Py_ssize_t ret; + + ret = get_read_buffer (self, segment, &ptr); + *ptrptr = (char *) ptr; + + return ret; +} + +/* Adds GDB value V to the pattern buffer in *PATTERN_BUF. If SIZE is not zero, + it specifies the number of bytes from V to copy to *PATTERN_BUF. The + function increases the size of *PATTERN_BUF as necessary, adjusting + *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. */ + +static void +add_value_pattern (struct value *v, int size, char **pattern_buf, + char **pattern_buf_end, ULONGEST *pattern_buf_size) +{ + int val_bytes; + + if (size) + { + LONGEST x = value_as_long (v); + + if (size == 1) + *(*pattern_buf_end)++ = x; + else + { + put_bits (x, *pattern_buf_end, size * 8, + gdbarch_byte_order (python_gdbarch) == BFD_ENDIAN_BIG); + *pattern_buf_end += size; + } + } + else + { + val_bytes = TYPE_LENGTH (value_type (v)); + + increase_pattern_buffer (pattern_buf, pattern_buf_end, + pattern_buf_size, val_bytes); + + memcpy (*pattern_buf_end, value_contents_raw (v), val_bytes); + *pattern_buf_end += val_bytes; + } +} + +/* This function does the actual work of constructing the pattern buffer from + OBJ. If OBJ is an object which implements the read buffer protocol (such + as a string, a byte array or gdb.Membuf), then its contents are directly + copied to *PATTERN_BUF. If it is a list, then this function is recursively + called for each of its elements. If OBJ is an object which can be converted + to a GDB value, then the contents of the value are copied to PATTERN_BUF. + If SIZE is different than zero, then it limits the number of bytes which + are copied to the buffer in case OBJ is converted to a GDB value. That + means that SIZE influences only Python scalars and gdb.Value objects. + The function increases the size of *PATTERN_BUF as necessary, adjusting + *PATTERN_BUF_END and *PATTERN_BUF_SIZE in the process. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +static int +add_pattern_element (PyObject *obj, int size, char **pattern_buf, + char **pattern_buf_end, ULONGEST *pattern_buf_size) +{ + if (PyObject_CheckReadBuffer (obj)) + { + /* Handle string, Unicode string, byte array, gdb.Membuf and any other + object implementing the buffer protocol. The SIZE parameter is + ignored in this case. */ + + Py_ssize_t val_bytes; + const void *buffer; + + if (PyObject_AsReadBuffer (obj, &buffer, &val_bytes) == -1) + return 0; + + increase_pattern_buffer (pattern_buf, pattern_buf_end, + pattern_buf_size, val_bytes); + + memcpy (*pattern_buf_end, buffer, val_bytes); + *pattern_buf_end += val_bytes; + } + else if (gdbpy_is_value_object (obj)) + add_value_pattern (value_object_to_value (obj), size, pattern_buf, + pattern_buf_end, pattern_buf_size); + else if (PySequence_Check (obj)) + { + /* Handle lists and tuples. */ + + Py_ssize_t i, num_objs; + + num_objs = PySequence_Size (obj); + for (i = 0; i < num_objs; i++) + if (!add_pattern_element (PySequence_GetItem (obj, i), size, + pattern_buf, pattern_buf_end, + pattern_buf_size)) + return 0; + } + else + { + /* See if we can convert from a Python object to a GDB value. */ + + struct value *v = convert_value_from_python (obj); + + if (v) + add_value_pattern (v, size, pattern_buf, pattern_buf_end, + pattern_buf_size); + else + return 0; + } + + return 1; +} + +/* Constructs the search pattern from OBJ, putting it in *PATTERN_BUFP, and its + size in *PATTERN_LENP. See the function add_pattern_element to learn how + the search pattern is obtained from OBJ. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +static int +get_search_pattern (PyObject *obj, int size, char **pattern_bufp, + ULONGEST *pattern_lenp) +{ + /* Buffer to hold the search pattern. */ + char *pattern_buf; + /* Current size of search pattern buffer. + We realloc space as needed. */ + ULONGEST pattern_buf_size; + /* Pointer to one past the last in-use part of pattern_buf. */ + char *pattern_buf_end; + struct cleanup *old_cleanups; + + allocate_pattern_buffer (&pattern_buf, &pattern_buf_end, &pattern_buf_size); + old_cleanups = make_cleanup (free_current_contents, &pattern_buf); + + if (!add_pattern_element (obj, size, &pattern_buf, &pattern_buf_end, + &pattern_buf_size)) + { + do_cleanups (old_cleanups); + + return 0; + } + + *pattern_bufp = pattern_buf; + *pattern_lenp = pattern_buf_end - pattern_buf; + + discard_cleanups (old_cleanups); + + return 1; +} + +/* Implementation of + gdb.search_memory (address, length, pattern [, size] [, max_count]). + The third argument may be either a pattern, or a list or tupple of patterns + to be searched. Size is the size in bytes of each search query value, either + 1, 2, 4 or 8. Returns a list of the addresses where matches were found. */ + +static PyObject * +infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw) +{ + int size = 0; + unsigned int found_count = 0; + long max_count = 0; + CORE_ADDR start_addr, length; + char *pattern_buf; + static char *keywords[] = { "address", "length", "pattern", "size", + "max_count", NULL }; + ULONGEST pattern_len, search_space_len; + PyObject *pattern, *list = NULL, *start_addr_obj, *length_obj; + volatile struct gdb_exception except; + + if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO|il", keywords, + &start_addr_obj, &length_obj, &pattern, + &size, &max_count)) + return NULL; + + if (!max_count) + max_count = LONG_MAX; + + if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8) + { + PyErr_SetString (PyExc_ValueError, "invalid pattern size"); + return NULL; + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (get_addr_from_python (start_addr_obj, &start_addr) + && get_addr_from_python (length_obj, &length)) + { + if (!length) + { + PyErr_SetString (PyExc_ValueError, "empty search range"); + break; + } + /* Watch for overflows. */ + else if (length > CORE_ADDR_MAX + || (start_addr + length - 1) < start_addr) + { + PyErr_SetString (PyExc_ValueError, "search range too large"); + break; + } + + search_space_len = length; + + if (get_search_pattern (pattern, size, &pattern_buf, &pattern_len)) + { + /* Any cleanups get automatically executed on an exception. */ + struct cleanup *cleanups = make_cleanup (xfree, pattern_buf); + + list = PyList_New (0); + + while (search_space_len >= pattern_len && found_count < max_count) + { + CORE_ADDR found_addr; + int found; + + found = search_memory (&start_addr, &search_space_len, + pattern_buf, pattern_len, &found_addr); + if (found <= 0) + break; + + PyList_Append (list, PyLong_FromUnsignedLong (found_addr)); + ++found_count; + } + + do_cleanups (cleanups); + } + } + } + GDB_PY_HANDLE_EXCEPTION (except); + + return list; +} + + + +void +gdbpy_initialize_inferior (void) +{ + if (PyType_Ready (&inferior_object_type) < 0) + return; + + Py_INCREF (&inferior_object_type); + PyModule_AddObject (gdb_module, "Inferior", + (PyObject *) &inferior_object_type); + + gdbpy_inferior_list = NULL; + ninferiors = 0; + + observer_attach_inferior_appeared (add_inferior_object); + observer_attach_inferior_exit (delete_inferior_object); + observer_attach_new_thread (add_thread_object); + observer_attach_thread_exit (delete_thread_object); + + if (PyType_Ready (&membuf_object_type) < 0) + return; + + Py_INCREF (&membuf_object_type); + PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type); +} + + + +static PyGetSetDef inferior_object_getset[] = +{ + { "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL }, + { "pid", infpy_get_pid, NULL, "PID of inferior, as assigned by the OS.", + NULL }, + { "was_attached", infpy_get_was_attached, NULL, + "True if the inferior was created using 'attach'.", NULL }, + + { NULL } +}; + +static PyMethodDef inferior_object_methods[] = +{ + { "threads", infpy_threads, METH_NOARGS, + "Return all the threads of this inferior." }, + + { "read_memory", infpy_read_memory, METH_VARARGS, + "read_memory (address, length) -> buffer\n\ +Return a buffer object for reading from the inferior's memory." }, + { "write_memory", infpy_write_memory, METH_VARARGS, + "write_memory (address, buffer [, length])\n\ +Write the given buffer object to the inferior's memory." }, + { "search_memory", (PyCFunction) infpy_search_memory, METH_VARARGS | METH_KEYWORDS, + "search_memory (address, length, pattern [, size] [, max_count]) -> list\n\ +Return a list with the addresses where matches were found." }, + + { NULL } +}; + +static PyTypeObject inferior_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /* ob_size */ + "gdb.Inferior", /* tp_name */ + sizeof (inferior_object), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ + "GDB inferior object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + inferior_object_methods, /* tp_methods */ + 0, /* tp_members */ + inferior_object_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0 /* tp_alloc */ +}; + + + +/* Python doesn't provide a decent way to get compatibility here. */ +#if HAVE_LIBPYTHON2_4 +#define CHARBUFFERPROC_NAME getcharbufferproc +#else +#define CHARBUFFERPROC_NAME charbufferproc +#endif + +static PyBufferProcs buffer_procs = { + get_read_buffer, + get_write_buffer, + get_seg_count, + /* The cast here works around a difference between Python 2.4 and + Python 2.5. */ + (CHARBUFFERPROC_NAME) get_char_buffer +}; + +static PyTypeObject membuf_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Membuf", /*tp_name*/ + sizeof (membuf_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + mbpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + mbpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &buffer_procs, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB memory buffer object", /*tp_doc*/ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/py-infthread.c b/gdb/python/py-infthread.c new file mode 100644 index 0000000..21e4eab --- /dev/null +++ b/gdb/python/py-infthread.c @@ -0,0 +1,285 @@ +/* Python interface to inferior threads. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "exceptions.h" +#include "gdbthread.h" +#include "inferior.h" +#include "python-internal.h" + +static PyTypeObject thread_object_type; + +/* Require that INFERIOR be a valid inferior ID. */ +#define THPY_REQUIRE_VALID(Thread) \ + do { \ + if (!Thread->thread) \ + { \ + PyErr_SetString (PyExc_RuntimeError, \ + "thread no longer exists"); \ + return NULL; \ + } \ + } while (0) + + + +thread_object * +create_thread_object (struct thread_info *tp) +{ + thread_object *thread_obj; + + thread_obj = PyObject_New (thread_object, &thread_object_type); + if (!thread_obj) + return NULL; + + thread_obj->thread = tp; + thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid)); + Py_INCREF (thread_obj->inf_obj); + + return thread_obj; +} + + + +static void +thpy_dealloc (PyObject *self) +{ + Py_DECREF (((thread_object *) self)->inf_obj); + self->ob_type->tp_free (self); +} + +static PyObject * +thpy_get_num (PyObject *self, void *closure) +{ + thread_object *thread_obj = (thread_object *) self; + + THPY_REQUIRE_VALID (thread_obj); + + return PyLong_FromLong (thread_obj->thread->num); +} + + + +/* Implementation of Inferior.frames () -> (gdb.Frame, ...). + Returns a tuple of all frame objects. */ +PyObject * +thpy_frames (PyObject *self, PyObject *args) +{ + int result = 0; + struct frame_info *frame; + PyObject *frame_obj; + PyObject *list, *tuple; + thread_object *thread_obj = (thread_object *) self; + struct cleanup *cleanup; + volatile struct gdb_exception except; + + THPY_REQUIRE_VALID (thread_obj); + + list = PyList_New (0); + if (list == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate frames list."); + return NULL; + } + + cleanup = make_cleanup_restore_current_thread (); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch_to_thread (thread_obj->thread->ptid); + + for (frame = get_current_frame (); frame; frame = get_prev_frame (frame)) + { + frame_obj = frame_info_to_frame_object (frame); + if (frame_obj == NULL) + { + Py_DECREF (list); + list = NULL; + break; + } + + PyList_Append (list, frame_obj); + } + } + if (except.reason < 0) + { + Py_DECREF (list); + return PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + } + + do_cleanups (cleanup); + + if (list) + { + tuple = PyList_AsTuple (list); + Py_DECREF (list); + } + else + tuple = NULL; + + return tuple; +} + +/* Implementation of InferiorThread.newest_frame () -> gdb.Frame. + Returns the newest frame object. */ +PyObject * +thpy_newest_frame (PyObject *self, PyObject *args) +{ + struct frame_info *frame; + PyObject *frame_obj = NULL; /* Initialize to appease gcc warning. */ + thread_object *thread_obj = (thread_object *) self; + struct cleanup *cleanup; + volatile struct gdb_exception except; + + THPY_REQUIRE_VALID (thread_obj); + + cleanup = make_cleanup_restore_current_thread (); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch_to_thread (thread_obj->thread->ptid); + + frame = get_current_frame (); + frame_obj = frame_info_to_frame_object (frame); + } + GDB_PY_HANDLE_EXCEPTION (except); + + do_cleanups (cleanup); + + return frame_obj; +} + +/* Implementation of InferiorThread.switch (). + Makes this the GDB selected thread. */ +static PyObject * +thpy_switch (PyObject *self, PyObject *args) +{ + thread_object *thread_obj = (thread_object *) self; + struct cleanup *cleanup; + volatile struct gdb_exception except; + + THPY_REQUIRE_VALID (thread_obj); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch_to_thread (thread_obj->thread->ptid); + } + GDB_PY_HANDLE_EXCEPTION (except); + + Py_RETURN_NONE; +} + + + +/* Implementation of gdb.selected_thread () -> gdb.InferiorThread. + Returns the selected thread object. */ +PyObject * +gdbpy_selected_thread (PyObject *self, PyObject *args) +{ + PyObject *thread_obj; + + thread_obj = (PyObject *) find_thread_object (inferior_ptid); + if (thread_obj) + { + Py_INCREF (thread_obj); + return thread_obj; + } + + Py_RETURN_NONE; +} + + + +void +gdbpy_initialize_thread (void) +{ + if (PyType_Ready (&thread_object_type) < 0) + return; + + Py_INCREF (&thread_object_type); + PyModule_AddObject (gdb_module, "InferiorThread", + (PyObject *) &thread_object_type); +} + + + +static PyGetSetDef thread_object_getset[] = +{ + { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL }, + + { NULL } +}; + +static PyMethodDef thread_object_methods[] = +{ + { "frames", thpy_frames, METH_NOARGS, + "frames () -> (gdb.Frame, ...)\n\ +Return a tuple containing all frames in the thread." }, + { "newest_frame", thpy_newest_frame, METH_NOARGS, + "newest_frame () -> gdb.Frame\n\ +Return the newest frame in the thread." }, + { "switch", thpy_switch, METH_NOARGS, + "switch ()\n\ +Makes this the GDB selected thread." }, + + { NULL } +}; + +static PyTypeObject thread_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.InferiorThread", /*tp_name*/ + sizeof (thread_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + thpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + "GDB thread object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + thread_object_methods, /* tp_methods */ + 0, /* tp_members */ + thread_object_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0 /* tp_alloc */ +}; diff --git a/gdb/python/py-membuf.c b/gdb/python/py-membuf.c new file mode 100644 index 0000000..7bc294c --- /dev/null +++ b/gdb/python/py-membuf.c @@ -0,0 +1,268 @@ +/* Python interface to the inferior memory. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "exceptions.h" +#include "gdbcore.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + void *buffer; + + /* These are kept just for mbpy_str. */ + CORE_ADDR addr; + CORE_ADDR length; +} membuf_object; + +static PyTypeObject membuf_object_type; + +/* Implementation of gdb.read_memory (address, length). + Returns a Python buffer object with LENGTH bytes of the inferior's memory + at ADDRESS. Both arguments are integers. */ + +PyObject * +gdbpy_read_memory (PyObject *self, PyObject *args) +{ + int error = 0; + CORE_ADDR addr, length; + void *buffer = NULL; + membuf_object *membuf_obj; + PyObject *addr_obj, *length_obj; + struct cleanup *cleanups = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "OO", &addr_obj, &length_obj)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!get_addr_from_python (addr_obj, &addr) + || !get_addr_from_python (length_obj, &length)) + { + error = 1; + break; + } + + buffer = xmalloc (length); + cleanups = make_cleanup (xfree, buffer); + + read_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (error) + return NULL; + + discard_cleanups (cleanups); + + membuf_obj = PyObject_New (membuf_object, &membuf_object_type); + if (membuf_obj == NULL) + { + xfree (buffer); + PyErr_SetString (PyExc_MemoryError, + "Could not allocate memory buffer object."); + return NULL; + } + + membuf_obj->buffer = buffer; + membuf_obj->addr = addr; + membuf_obj->length = length; + + return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0, + Py_END_OF_BUFFER); +} + +/* Implementation of gdb.write_memory (address, buffer [, length]). + Writes the contents of BUFFER (a Python object supporting the read buffer + protocol) at ADDRESS in the inferior's memory. Write LENGTH bytes from + BUFFER, or its entire contents if the argument is not provided. The + function returns nothing. */ + +PyObject * +gdbpy_write_memory (PyObject *self, PyObject *args) +{ + int buf_len, error = 0; + const char *buffer; + CORE_ADDR addr, length; + PyObject *addr_obj, *length_obj = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "Os#|O", &addr_obj, &buffer, &buf_len, + &length_obj)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (!get_addr_from_python (addr_obj, &addr)) + { + error = 1; + break; + } + + if (!length_obj) + length = buf_len; + else if (!get_addr_from_python (length_obj, &length)) + { + error = 1; + break; + } + + write_memory (addr, buffer, length); + } + GDB_PY_HANDLE_EXCEPTION (except); + + if (error) + return NULL; + + Py_RETURN_NONE; +} + +/* Destructor of Membuf objects. */ + +static void +mbpy_dealloc (PyObject *self) +{ + xfree (((membuf_object *) self)->buffer); + self->ob_type->tp_free (self); +} + +/* Return a description of the Membuf object. */ + +static PyObject * +mbpy_str (PyObject *self) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + return PyString_FromFormat ("memory buffer for address %s, %s bytes long", + paddress (membuf_obj->addr), + pulongest (membuf_obj->length)); +} + +static Py_ssize_t +get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + membuf_object *membuf_obj = (membuf_object *) self; + + if (segment) + { + PyErr_SetString (PyExc_SystemError, + "The memory buffer supports only one segment."); + return -1; + } + + *ptrptr = membuf_obj->buffer; + + return membuf_obj->length; +} + +static Py_ssize_t +get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr) +{ + return get_read_buffer (self, segment, ptrptr); +} + +static Py_ssize_t +get_seg_count (PyObject *self, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = ((membuf_object *) self)->length; + + return 1; +} + +static Py_ssize_t +get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) +{ + void *ptr = NULL; + Py_ssize_t ret; + + ret = get_read_buffer (self, segment, &ptr); + *ptrptr = (char *) ptr; + + return ret; +} + +/* Python doesn't provide a decent way to get compatibility here. */ +#if HAVE_LIBPYTHON2_4 +#define CHARBUFFERPROC_NAME getcharbufferproc +#else +#define CHARBUFFERPROC_NAME charbufferproc +#endif + +static PyBufferProcs buffer_procs = { + get_read_buffer, + get_write_buffer, + get_seg_count, + /* The cast here works around a difference between Python 2.4 and + Python 2.5. */ + (CHARBUFFERPROC_NAME) get_char_buffer +}; + +static PyTypeObject membuf_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Membuf", /*tp_name*/ + sizeof (membuf_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + mbpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + mbpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &buffer_procs, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB memory buffer object", /*tp_doc*/ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; + +void +gdbpy_initialize_membuf (void) +{ + if (PyType_Ready (&membuf_object_type) < 0) + return; + + Py_INCREF (&membuf_object_type); + PyModule_AddObject (gdb_module, "Membuf", (PyObject *) &membuf_object_type); +} diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c new file mode 100644 index 0000000..1f591a8 --- /dev/null +++ b/gdb/python/py-param.c @@ -0,0 +1,606 @@ +/* gdb parameters implemented in Python + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +#include "defs.h" +#include "value.h" +#include "exceptions.h" +#include "python-internal.h" +#include "charset.h" +#include "gdbcmd.h" +#include "cli/cli-decode.h" +#include "completer.h" + +/* Parameter constants and their values. */ +struct parm_constant +{ + char *name; + int value; +}; + +struct parm_constant parm_constants[] = +{ + { "PARAM_BOOLEAN", var_boolean }, + { "PARAM_AUTO_BOOLEAN", var_auto_boolean }, + { "PARAM_UINTEGER", var_uinteger }, + { "PARAM_INTEGER", var_integer }, + { "PARAM_STRING", var_string }, + { "PARAM_STRING_NOESCAPE", var_string_noescape }, + { "PARAM_OPTIONAL_FILENAME", var_optional_filename }, + { "PARAM_FILENAME", var_filename }, + { "PARAM_ZINTEGER", var_zinteger }, + { "PARAM_ENUM", var_enum }, + { NULL, 0 } +}; + +/* A union that can hold anything described by enum var_types. */ +union parmpy_variable +{ + /* Hold an integer value, for boolean and integer types. */ + int intval; + + /* Hold an auto_boolean. */ + enum auto_boolean autoboolval; + + /* Hold an unsigned integer value, for uinteger. */ + unsigned int uintval; + + /* Hold a string, for the various string types. */ + char *stringval; + + /* Hold a string, for enums. */ + const char *cstringval; +}; + +/* A gdb parameter. */ +struct parmpy_object +{ + PyObject_HEAD + + /* The type of the parameter. */ + enum var_types type; + + /* The value of the parameter. */ + union parmpy_variable value; + + /* For an enum command, the possible values. The vector is + allocated with xmalloc, as is each element. It is + NULL-terminated. */ + const char **enumeration; +}; + +typedef struct parmpy_object parmpy_object; + +static PyTypeObject parmpy_object_type; + +/* Some handy string constants. */ +static PyObject *set_doc_cst; +static PyObject *show_doc_cst; + + + +/* Get an attribute. */ +static PyObject * +get_attr (PyObject *obj, PyObject *attr_name) +{ + if (PyString_Check (attr_name) + && ! strcmp (PyString_AsString (attr_name), "value")) + { + parmpy_object *self = (parmpy_object *) obj; + return gdbpy_parameter_value (self->type, &self->value); + } + + return PyObject_GenericGetAttr (obj, attr_name); +} + +/* Set a parameter value from a Python value. Return 0 on success, -1 + on failure. */ +static int +set_parameter_value (parmpy_object *self, PyObject *value) +{ + int cmp; + + switch (self->type) + { + case var_string: + case var_string_noescape: + case var_optional_filename: + case var_filename: + if (! gdbpy_is_string (value) + && (self->type == var_filename + || value != Py_None)) + { + PyErr_SetString (PyExc_RuntimeError, "string required"); + return -1; + } + if (self->value.stringval) + xfree (self->value.stringval); + if (value == Py_None) + { + if (self->type == var_optional_filename) + self->value.stringval = xstrdup (""); + else + self->value.stringval = NULL; + } + else + self->value.stringval = python_string_to_host_string (value); + break; + + case var_enum: + { + int i; + char *str; + + if (! gdbpy_is_string (value)) + { + PyErr_SetString (PyExc_RuntimeError, "string required"); + return -1; + } + + str = python_string_to_host_string (value); + for (i = 0; self->enumeration[i]; ++i) + if (! strcmp (self->enumeration[i], str)) + break; + xfree (str); + if (! self->enumeration[i]) + { + PyErr_SetString (PyExc_RuntimeError, + "value must be member of enumeration"); + return -1; + } + self->value.cstringval = self->enumeration[i]; + break; + } + + case var_boolean: + if (! PyBool_Check (value)) + { + PyErr_SetString (PyExc_RuntimeError, "boolean required"); + return -1; + } + cmp = PyObject_IsTrue (value); + if (cmp < 0) + return -1; + self->value.intval = cmp; + break; + + case var_auto_boolean: + if (! PyBool_Check (value) && value != Py_None) + { + PyErr_SetString (PyExc_RuntimeError, + "boolean or None required"); + return -1; + } + + if (value == Py_None) + self->value.autoboolval = AUTO_BOOLEAN_AUTO; + else + { + cmp = PyObject_IsTrue (value); + if (cmp < 0 ) + return -1; + if (cmp == 1) + self->value.autoboolval = AUTO_BOOLEAN_TRUE; + else + self->value.autoboolval = AUTO_BOOLEAN_FALSE; + + break; + } + + case var_integer: + case var_zinteger: + case var_uinteger: + { + long l; + int ok; + + if (! PyInt_Check (value)) + { + PyErr_SetString (PyExc_RuntimeError, "value must be integer"); + return -1; + } + + l = PyInt_AsLong (value); + if (self->type == var_uinteger) + { + ok = (l >= 0 && l <= UINT_MAX); + if (l == 0) + l = UINT_MAX; + } + else if (self->type == var_integer) + { + ok = (l >= INT_MIN && l <= INT_MAX); + if (l == 0) + l = INT_MAX; + } + else + ok = (l >= INT_MIN && l <= INT_MAX); + + if (! ok) + { + PyErr_SetString (PyExc_RuntimeError, "range exceeded"); + return -1; + } + + self->value.intval = (int) l; + break; + } + + default: + PyErr_SetString (PyExc_RuntimeError, "programmer error: unhandled type"); + return -1; + } + + return 0; +} + +/* Set an attribute. */ +static int +set_attr (PyObject *obj, PyObject *attr_name, PyObject *val) +{ + if (PyString_Check (attr_name) + && ! strcmp (PyString_AsString (attr_name), "value")) + { + if (!val) + { + PyErr_SetString (PyExc_RuntimeError, + "cannot delete a parameter's value"); + return -1; + } + return set_parameter_value ((parmpy_object *) obj, val); + } + + return PyObject_GenericSetAttr (obj, attr_name, val); +} + + + +/* A helper function that dispatches to the appropriate add_setshow + function. */ +static void +add_setshow_generic (int parmclass, enum command_class cmdclass, + char *cmd_name, parmpy_object *self, + char *set_doc, char *show_doc, char *help_doc, + struct cmd_list_element **set_list, + struct cmd_list_element **show_list) +{ + switch (parmclass) + { + case var_boolean: + add_setshow_boolean_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_auto_boolean: + add_setshow_auto_boolean_cmd (cmd_name, cmdclass, + &self->value.autoboolval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_uinteger: + add_setshow_uinteger_cmd (cmd_name, cmdclass, &self->value.uintval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_integer: + add_setshow_integer_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_string: + add_setshow_string_cmd (cmd_name, cmdclass, &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_string_noescape: + add_setshow_string_noescape_cmd (cmd_name, cmdclass, + &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_optional_filename: + add_setshow_optional_filename_cmd (cmd_name, cmdclass, + &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_filename: + add_setshow_filename_cmd (cmd_name, cmdclass, &self->value.stringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_zinteger: + add_setshow_zinteger_cmd (cmd_name, cmdclass, &self->value.intval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + break; + + case var_enum: + add_setshow_enum_cmd (cmd_name, cmdclass, self->enumeration, + &self->value.cstringval, + set_doc, show_doc, help_doc, + NULL, NULL, set_list, show_list); + /* Initialize the value, just in case. */ + self->value.cstringval = self->enumeration[0]; + break; + } +} + +/* A helper which computes enum values. Returns 1 on success, 0 on + error. */ +static int +compute_enum_values (parmpy_object *self, PyObject *enum_values) +{ + Py_ssize_t size, i; + + if (! enum_values) + { + PyErr_SetString (PyExc_RuntimeError, + "enumeration required for PARAM_ENUM"); + return 0; + } + + if (! PySequence_Check (enum_values)) + { + PyErr_SetString (PyExc_RuntimeError, "enumeration is not a sequence"); + return 0; + } + + size = PySequence_Size (enum_values); + if (size < 0) + return 0; + if (size == 0) + { + PyErr_SetString (PyExc_RuntimeError, "empty enumeration"); + return 0; + } + + self->enumeration = xmalloc ((size + 1) * sizeof (char *)); + memset (self->enumeration, 0, (size + 1) * sizeof (char *)); + + for (i = 0; i < size; ++i) + { + PyObject *item = PySequence_GetItem (enum_values, i); + if (! item) + return 0; + if (! gdbpy_is_string (item)) + { + PyErr_SetString (PyExc_RuntimeError, "enumeration item not a string"); + return 0; + } + self->enumeration[i] = python_string_to_host_string (item); + } + + return 1; +} + +/* A helper function which returns a documentation string for an + object. */ +static char * +get_doc_string (PyObject *object, PyObject *attr) +{ + char *result = NULL; + if (PyObject_HasAttr (object, attr)) + { + PyObject *ds_obj = PyObject_GetAttr (object, attr); + if (ds_obj && gdbpy_is_string (ds_obj)) + result = python_string_to_host_string (ds_obj); + } + if (! result) + result = xstrdup ("This command is not documented."); + return result; +} + +/* Object initializer; sets up gdb-side structures for command. + + Use: __init__(NAME, CMDCLASS, PARMCLASS, [ENUM]) + + NAME is the name of the parameter. It may consist of multiple + words, in which case the final word is the name of the new command, + and earlier words must be prefix commands. + + CMDCLASS is the kind of command. It should be one of the COMMAND_* + constants defined in the gdb module. + + PARMCLASS is the type of the parameter. It should be one of the + PARAM_* constants defined in the gdb module. + + If PARMCLASS is PARAM_ENUM, then the final argument should be a + collection of strings. These strings are the valid values for this + parameter. + + The documentation for the parameter is taken from the doc string + for the python class. + +*/ +static int +parmpy_init (PyObject *self, PyObject *args, PyObject *kwds) +{ + parmpy_object *obj = (parmpy_object *) self; + char *name; + char *set_doc, *show_doc, *doc; + char *cmd_name; + int parmclass, cmdtype; + PyObject *enum_values = NULL; + struct cmd_list_element *cmd_list; + struct cmd_list_element **set_list, **show_list; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "sii|O", &name, &cmdtype, &parmclass, + &enum_values)) + return -1; + + if (cmdtype != no_class && cmdtype != class_run + && cmdtype != class_vars && cmdtype != class_stack + && cmdtype != class_files && cmdtype != class_support + && cmdtype != class_info && cmdtype != class_breakpoint + && cmdtype != class_trace && cmdtype != class_obscure + && cmdtype != class_maintenance) + { + PyErr_Format (PyExc_RuntimeError, "invalid command class argument"); + return -1; + } + + if (parmclass != var_boolean && parmclass != var_auto_boolean + && parmclass != var_uinteger && parmclass != var_integer + && parmclass != var_string && parmclass != var_string_noescape + && parmclass != var_optional_filename && parmclass != var_filename + && parmclass != var_zinteger && parmclass != var_enum) + { + PyErr_SetString (PyExc_RuntimeError, "invalid parameter class argument"); + return -1; + } + + if (enum_values && parmclass != var_enum) + { + PyErr_SetString (PyExc_RuntimeError, + "only PARAM_ENUM accepts a fourth argument"); + return -1; + } + if (parmclass == var_enum) + { + if (! compute_enum_values (obj, enum_values)) + return -1; + } + + obj->type = (enum var_types) parmclass; + memset (&obj->value, 0, sizeof (obj->value)); + obj->enumeration = NULL; + + cmd_name = gdbpy_parse_command_name (name, &set_list, &setlist); + if (! cmd_name) + return -1; + xfree (cmd_name); + cmd_name = gdbpy_parse_command_name (name, &show_list, &showlist); + if (! cmd_name) + return -1; + + /* FIXME: there is no way to register a destructor function for + set/show commands. So, these are leaked. */ + set_doc = get_doc_string (self, set_doc_cst); + show_doc = get_doc_string (self, show_doc_cst); + doc = get_doc_string (self, gdbpy_doc_cst); + + Py_INCREF (self); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + add_setshow_generic (parmclass, (enum command_class) cmdtype, + cmd_name, obj, + set_doc, show_doc, + doc, set_list, show_list); + } + if (except.reason < 0) + { + xfree (cmd_name); + xfree (set_doc); + xfree (show_doc); + xfree (doc); + Py_DECREF (self); + PyErr_Format (except.reason == RETURN_QUIT + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, + "%s", except.message); + return -1; + } + return 0; +} + + + +/* Initialize the 'parameters' module. */ +void +gdbpy_initialize_parameters (void) +{ + int i; + + if (PyType_Ready (&parmpy_object_type) < 0) + return; + + set_doc_cst = PyString_FromString ("set_doc"); + if (! set_doc_cst) + return; + show_doc_cst = PyString_FromString ("show_doc"); + if (! show_doc_cst) + return; + + for (i = 0; parm_constants[i].name; ++i) + { + if (PyModule_AddIntConstant (gdb_module, + parm_constants[i].name, + parm_constants[i].value) < 0) + return; + } + + Py_INCREF (&parmpy_object_type); + PyModule_AddObject (gdb_module, "Parameter", + (PyObject *) &parmpy_object_type); +} + + + +static PyTypeObject parmpy_object_type = +{ + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Parameter", /*tp_name*/ + sizeof (parmpy_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + get_attr, /*tp_getattro*/ + set_attr, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "GDB parameter object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + parmpy_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c index 193f97c..2f2b365 100644 --- a/gdb/python/py-prettyprint.c +++ b/gdb/python/py-prettyprint.c @@ -143,10 +143,15 @@ pretty_print_one_value (PyObject *printer, struct value **out_value) if (! gdbpy_is_string (result) && ! gdbpy_is_lazy_string (result)) { *out_value = convert_value_from_python (result); - if (PyErr_Occurred ()) - *out_value = NULL; - Py_DECREF (result); - result = NULL; + if (PyErr_Occurred ()) + *out_value = NULL; + else + /* We must increment the value's refcount, because we + are about to decref RESULT, and this may result in + the value being destroyed. */ + value_incref (*out_value); + Py_DECREF (result); + result = NULL; } } } @@ -604,14 +609,7 @@ gdbpy_get_varobj_pretty_printer (struct value *value) { PyObject *val_obj; PyObject *pretty_printer = NULL; - volatile struct gdb_exception except; - TRY_CATCH (except, RETURN_MASK_ALL) - { - value = value_copy (value); - } - GDB_PY_HANDLE_EXCEPTION (except); - val_obj = value_to_value_object (value); if (! val_obj) return NULL; diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c new file mode 100644 index 0000000..03d43c1 --- /dev/null +++ b/gdb/python/py-symbol.c @@ -0,0 +1,336 @@ +/* Python interface to symbols. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "block.h" +#include "exceptions.h" +#include "frame.h" +#include "symtab.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct symbol *symbol; +} symbol_object; + + +static PyObject * +sympy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol for %s", + SYMBOL_PRINT_NAME (((symbol_object *) self)->symbol)); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +sympy_get_value (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + switch (SYMBOL_CLASS (self_sym->symbol)) + { + case LOC_BLOCK: + return block_to_block_object (SYMBOL_BLOCK_VALUE (self_sym->symbol)); + } + + PyErr_SetString (PyExc_NotImplementedError, + "Symbol type not yet supported in Python scripts."); + return NULL; +} + +static PyObject * +sympy_get_symtab (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return symtab_to_symtab_object (SYMBOL_SYMTAB (self_sym->symbol)); +} + +static PyObject * +sympy_get_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_NATURAL_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_linkage_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_LINKAGE_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_print_name (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyString_FromString (SYMBOL_PRINT_NAME (self_sym->symbol)); +} + +static PyObject * +sympy_get_addr_class (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyInt_FromLong (SYMBOL_CLASS (self_sym->symbol)); +} + +static PyObject * +sympy_is_argument (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + + return PyBool_FromLong (SYMBOL_IS_ARGUMENT (self_sym->symbol)); +} + +static PyObject * +sympy_is_constant (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_CONST || class == LOC_CONST_BYTES); +} + +static PyObject * +sympy_is_function (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (class == LOC_BLOCK); +} + +static PyObject * +sympy_is_variable (PyObject *self, void *closure) +{ + symbol_object *self_sym = (symbol_object *) self; + enum address_class class = SYMBOL_CLASS (self_sym->symbol); + + return PyBool_FromLong (!SYMBOL_IS_ARGUMENT (self_sym->symbol) + && (class == LOC_LOCAL || class == LOC_REGISTER || class == LOC_STATIC + || class == LOC_COMPUTED || class == LOC_OPTIMIZED_OUT)); +} + +PyObject * +symbol_to_symbol_object (struct symbol *sym) +{ + symbol_object *sym_obj; + + sym_obj = PyObject_New (symbol_object, &symbol_object_type); + if (sym_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate symbol object."); + return NULL; + } + + sym_obj->symbol = sym; + + return (PyObject *) sym_obj; +} + +struct symbol * +symbol_object_to_symbol (PyObject *obj) +{ + if (! PyObject_TypeCheck (obj, &symbol_object_type)) + return NULL; + return ((symbol_object *) obj)->symbol; +} + +/* Implementation of + gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this) + A tuple with 2 elements is always returned. The first is the symbol + object or None, the second is a boolean with the value of + is_a_field_of_this (see comment in lookup_symbol_in_language). */ + +PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw) +{ + int domain = VAR_DOMAIN, is_a_field_of_this = 0; + const char *name; + static char *keywords[] = { "name", "block", "domain", NULL }; + struct symbol *symbol; + PyObject *block_obj = NULL, *ret_tuple, *sym_obj, *bool_obj; + struct block *block = NULL; + + if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O!i", keywords, &name, + &block_object_type, &block_obj, &domain)) + return NULL; + + if (block_obj) + block = block_object_to_block (block_obj); + else + { + struct frame_info *selected_frame; + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + selected_frame = get_selected_frame (_("No frame selected.")); + block = block_for_pc (get_frame_address_in_block (selected_frame)); + } + GDB_PY_HANDLE_EXCEPTION (except); + } + + symbol = lookup_symbol (name, block, domain, &is_a_field_of_this); + + ret_tuple = PyTuple_New (2); + if (!ret_tuple) + { + PyErr_SetString (PyExc_MemoryError, "Could not allocate tuple object."); + return NULL; + } + + if (symbol) + { + sym_obj = symbol_to_symbol_object (symbol); + if (!sym_obj) + { + Py_DECREF (ret_tuple); + return NULL; + } + } + else + { + sym_obj = Py_None; + Py_INCREF (Py_None); + } + PyTuple_SET_ITEM (ret_tuple, 0, sym_obj); + + bool_obj = is_a_field_of_this? Py_True : Py_False; + Py_INCREF (bool_obj); + PyTuple_SET_ITEM (ret_tuple, 1, bool_obj); + + return ret_tuple; +} + +void +gdbpy_initialize_symbols (void) +{ + if (PyType_Ready (&symbol_object_type) < 0) + return; + + /* FIXME: These would probably be best exposed as class attributes of Symbol, + but I don't know how to do it except by messing with the type's dictionary. + That seems too messy. */ + /* FIXME 2: Some of these were removed from GDB since I first wrote this code, + so it's probably a good idea not to expose them to Python. */ + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNDEF", LOC_UNDEF); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST", LOC_CONST); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_STATIC", LOC_STATIC); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGISTER", LOC_REGISTER); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_ARG", LOC_ARG); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REF_ARG", LOC_REF_ARG); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LOCAL", LOC_LOCAL); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_TYPEDEF", LOC_TYPEDEF); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_LABEL", LOC_LABEL); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_BLOCK", LOC_BLOCK); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_CONST_BYTES", + LOC_CONST_BYTES); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_UNRESOLVED", LOC_UNRESOLVED); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_OPTIMIZED_OUT", + LOC_OPTIMIZED_OUT); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_COMPUTED", LOC_COMPUTED); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LOC_REGPARM_ADDR", + LOC_REGPARM_ADDR); + PyModule_AddIntConstant (gdb_module, "SYMBOL_UNDEF_DOMAIN", UNDEF_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_VAR_DOMAIN", VAR_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_STRUCT_DOMAIN", STRUCT_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_LABEL_DOMAIN", LABEL_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_VARIABLES_DOMAIN", + VARIABLES_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_FUNCTIONS_DOMAIN", + FUNCTIONS_DOMAIN); + PyModule_AddIntConstant (gdb_module, "SYMBOL_TYPES_DOMAIN", TYPES_DOMAIN); + + Py_INCREF (&symbol_object_type); + PyModule_AddObject (gdb_module, "Symbol", (PyObject *) &symbol_object_type); +} + + + +static PyGetSetDef symbol_object_getset[] = { + { "value", sympy_get_value, NULL, "Value of the symbol.", NULL }, + { "symtab", sympy_get_symtab, NULL, + "Symbol table in which the symbol appears.", NULL }, + { "name", sympy_get_name, NULL, + "Name of the symbol, as it appears in the source code.", NULL }, + { "linkage_name", sympy_get_linkage_name, NULL, + "Name of the symbol, as used by the linker (i.e., may be mangled).", NULL }, + { "print_name", sympy_get_print_name, NULL, + "Name of the symbol in a form suitable for output.\n\ +This is either name or linkage_name, depending on whether the user asked GDB\n\ +to display demangled or mangled names.", NULL }, + { "addr_class", sympy_get_addr_class, NULL, "Address class of the symbol." }, + { "is_argument", sympy_is_argument, NULL, + "True if the symbol is an argument of a function." }, + { "is_constant", sympy_is_constant, NULL, + "True if the symbol is a constant." }, + { "is_function", sympy_is_function, NULL, + "True if the symbol is a function or method." }, + { "is_variable", sympy_is_variable, NULL, + "True if the symbol is a variable." }, + { NULL } /* Sentinel */ +}; + +PyTypeObject symbol_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symbol", /*tp_name*/ + sizeof (symbol_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + sympy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symbol object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + symbol_object_getset /* tp_getset */ +}; diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c new file mode 100644 index 0000000..830e586 --- /dev/null +++ b/gdb/python/py-symtab.c @@ -0,0 +1,322 @@ +/* Python interface to symbol tables. + + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "charset.h" +#include "symtab.h" +#include "source.h" +#include "python-internal.h" + +typedef struct { + PyObject_HEAD + struct symtab *symtab; +} symtab_object; + +static PyTypeObject symtab_object_type; + +typedef struct { + PyObject_HEAD + symtab_object *symtab; + struct symtab_and_line *sal; +} sal_object; + +static PyTypeObject sal_object_type; + + +static PyObject * +stpy_str (PyObject *self) +{ + int ret; + char *s; + PyObject *result; + + ret = asprintf (&s, "symbol table for %s", + ((symtab_object *) self)->symtab->filename); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +stpy_get_filename (PyObject *self, void *closure) +{ + symtab_object *self_symtab = (symtab_object *) self; + PyObject *str_obj; + + /* FIXME: Can symtab->filename really be NULL? */ + if (self_symtab->symtab->filename) + str_obj = PyString_Decode (self_symtab->symtab->filename, + strlen (self_symtab->symtab->filename), + host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +static PyObject * +stpy_get_objfile (PyObject *self, void *closure) +{ + symtab_object *self_symtab = (symtab_object *) self; + PyObject *result = objfile_to_objfile_object (self_symtab->symtab->objfile); + Py_INCREF (result); + return result; +} + +static PyObject * +stpy_fullname (PyObject *self, PyObject *args) +{ + char *fullname; + + fullname = symtab_to_fullname (((symtab_object *) self)->symtab); + if (fullname) + return PyString_Decode (fullname, strlen (fullname), host_charset (), NULL); + + Py_RETURN_NONE; +} + +static PyObject * +salpy_str (PyObject *self) +{ + int ret; + char *s, *filename; + sal_object *sal_obj; + PyObject *result; + + sal_obj = (sal_object *) self; + filename = (sal_obj->symtab == (symtab_object *) Py_None)? "" : + sal_obj->symtab->symtab->filename; + ret = asprintf (&s, "symbol and line for %s, line %d", filename, + sal_obj->sal->line); + if (ret < 0) + Py_RETURN_NONE; + + result = PyString_FromString (s); + xfree (s); + + return result; +} + +static PyObject * +salpy_get_pc (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->pc); +} + +static PyObject * +salpy_get_line (PyObject *self, void *closure) +{ + return PyLong_FromUnsignedLongLong (((sal_object *) self)->sal->line); +} + +static PyObject * +salpy_get_symtab (PyObject *self, void *closure) +{ + sal_object *self_sal = (sal_object *) self; + + Py_INCREF (self_sal->symtab); + + return (PyObject *) self_sal->symtab; +} + +static void +salpy_dealloc (PyObject *self) +{ + sal_object *self_sal = (sal_object *) self; + + Py_DECREF (self_sal->symtab); + xfree (self_sal->sal); + self_sal->ob_type->tp_free (self); +} + +PyObject * +symtab_and_line_to_sal_object (struct symtab_and_line sal) +{ + sal_object *sal_obj; + symtab_object *symtab_obj; + + sal_obj = PyObject_New (sal_object, &sal_object_type); + if (sal_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab_and_line object."); + return NULL; + } + + if (sal.symtab) + { + symtab_obj = (symtab_object *) symtab_to_symtab_object (sal.symtab); + if (symtab_obj == NULL) + { + Py_DECREF (sal_obj); + return NULL; + } + + symtab_obj->symtab = sal.symtab; + } + else + { + symtab_obj = (symtab_object *) Py_None; + Py_INCREF (Py_None); + } + + sal_obj->sal = (struct symtab_and_line *) + xmalloc (sizeof (struct symtab_and_line)); + *(sal_obj->sal) = sal; + sal_obj->symtab = symtab_obj; + + return (PyObject *) sal_obj; +} + +PyObject * +symtab_to_symtab_object (struct symtab *symtab) +{ + symtab_object *symtab_obj; + + symtab_obj = PyObject_New (symtab_object, &symtab_object_type); + if (symtab_obj == NULL) + { + PyErr_SetString (PyExc_MemoryError, + "Could not allocate Symtab object."); + + return NULL; + } + + symtab_obj->symtab = symtab; + + return (PyObject *) symtab_obj; +} + +void +gdbpy_initialize_symtabs (void) +{ + symtab_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&symtab_object_type) < 0) + return; + + sal_object_type.tp_new = PyType_GenericNew; + if (PyType_Ready (&sal_object_type) < 0) + return; + + Py_INCREF (&symtab_object_type); + PyModule_AddObject (gdb_module, "Symtab", (PyObject *) &symtab_object_type); + + Py_INCREF (&sal_object_type); + PyModule_AddObject (gdb_module, "Symtab_and_line", + (PyObject *) &sal_object_type); +} + + + +static PyGetSetDef symtab_object_getset[] = { + { "filename", stpy_get_filename, NULL, + "The symbol table's source filename.", NULL }, + { "objfile", stpy_get_objfile, NULL, "The symtab's objfile.", + NULL }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef symtab_object_methods[] = { + { "fullname", stpy_fullname, METH_NOARGS, + "Return the symtab's full source filename." }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject symtab_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symtab", /*tp_name*/ + sizeof (symtab_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + stpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symtab object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + symtab_object_methods, /* tp_methods */ + 0, /* tp_members */ + symtab_object_getset /* tp_getset */ +}; + +static PyGetSetDef sal_object_getset[] = { + { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL }, + { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL }, + { "line", salpy_get_line, NULL, + "Return the symtab_and_line's line.", NULL }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject sal_object_type = { + PyObject_HEAD_INIT (NULL) + 0, /*ob_size*/ + "gdb.Symtab_and_line", /*tp_name*/ + sizeof (sal_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + salpy_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + salpy_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "GDB symtab_and_line object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + sal_object_getset /* tp_getset */ +}; diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index a97c125..ac366bb 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -27,6 +27,8 @@ #include "demangle.h" #include "objfiles.h" #include "language.h" +#include "observer.h" +#include "gdb_assert.h" typedef struct pyty_type_object { @@ -35,11 +37,17 @@ typedef struct pyty_type_object /* If a Type object is associated with an objfile, it is kept on a doubly-linked list, rooted in the objfile. This lets us copy the - underlying struct type when the objfile is deleted. */ + underlying struct type when the objfile is deleted. + + With NULL objfile Type still can be doubly-linked in the list + PYTY_OBJECTS_DISCARDABLE. */ struct pyty_type_object *prev; struct pyty_type_object *next; } type_object; +/* First element of a doubly-linked list of TYPE_DISCARDABLE Types. */ +static type_object *pyty_objects_discardable; + static PyTypeObject type_object_type; /* A Field object. */ @@ -434,7 +442,7 @@ typy_get_sizeof (PyObject *self, void *closure) } static struct type * -typy_lookup_typename (char *type_name) +typy_lookup_typename (char *type_name, struct block *block) { struct type *type = NULL; volatile struct gdb_exception except; @@ -448,7 +456,7 @@ typy_lookup_typename (char *type_name) type = lookup_enum (type_name + 5, NULL); else type = lookup_typename (python_language, python_gdbarch, - type_name, NULL, 0); + type_name, block, 0); } if (except.reason < 0) { @@ -462,7 +470,8 @@ typy_lookup_typename (char *type_name) } static struct type * -typy_lookup_type (struct demangle_component *demangled) +typy_lookup_type (struct demangle_component *demangled, + struct block *block) { struct type *type; char *type_name; @@ -477,7 +486,7 @@ typy_lookup_type (struct demangle_component *demangled) || demangled_type == DEMANGLE_COMPONENT_CONST || demangled_type == DEMANGLE_COMPONENT_VOLATILE) { - type = typy_lookup_type (demangled->u.s_binary.left); + type = typy_lookup_type (demangled->u.s_binary.left, block); if (! type) return NULL; @@ -495,7 +504,7 @@ typy_lookup_type (struct demangle_component *demangled) } type_name = cp_comp_to_string (demangled, 10); - type = typy_lookup_typename (type_name); + type = typy_lookup_typename (type_name, block); xfree (type_name); return type; @@ -509,10 +518,23 @@ typy_template_argument (PyObject *self, PyObject *args) struct demangle_component *demangled; const char *err; struct type *argtype; + struct block *block = NULL; + PyObject *block_obj = NULL; - if (! PyArg_ParseTuple (args, "i", &argno)) + if (! PyArg_ParseTuple (args, "i|O", &argno, &block_obj)) return NULL; + if (block_obj) + { + block = block_object_to_block (block_obj); + if (! block) + { + PyErr_SetString (PyExc_RuntimeError, + "second argument must be block"); + return NULL; + } + } + type = check_typedef (type); if (TYPE_CODE (type) == TYPE_CODE_REF) type = check_typedef (TYPE_TARGET_TYPE (type)); @@ -555,7 +577,7 @@ typy_template_argument (PyObject *self, PyObject *args) return NULL; } - argtype = typy_lookup_type (demangled->u.s_binary.left); + argtype = typy_lookup_type (demangled->u.s_binary.left, block); if (! argtype) return NULL; @@ -597,8 +619,59 @@ typy_str (PyObject *self) +/* Key associated with each objfile pointing to the first element of + a doubly-linked list of Types associated with this objfile. */ static const struct objfile_data *typy_objfile_data_key; +/* Link TYPE_OBJ to its appropriate list. Either to its objfile associated one + or at least to the global list for TYPE_DISCARDABLE Types. Permanent types + do not get linked anywhere. */ +static void +typy_link (type_object *type_obj) +{ + type_obj->prev = NULL; + + if (type_obj->type && TYPE_OBJFILE (type_obj->type)) + { + struct objfile *objfile = TYPE_OBJFILE (type_obj->type); + + type_obj->next = objfile_data (objfile, typy_objfile_data_key); + if (type_obj->next) + type_obj->next->prev = type_obj; + set_objfile_data (objfile, typy_objfile_data_key, type_obj); + } + else if (type_obj->type && TYPE_DISCARDABLE (type_obj->type)) + { + type_obj->next = pyty_objects_discardable; + if (type_obj->next) + type_obj->next->prev = type_obj; + pyty_objects_discardable = type_obj; + } + else + type_obj->next = NULL; +} + +/* Unlink TYPE_OBJ from its current list. Permanent types are not linked + anywhere and this function has no effect on them. */ +static void +typy_unlink (type_object *type_obj) +{ + if (type_obj->prev) + type_obj->prev->next = type_obj->next; + else if (type_obj->type && TYPE_OBJFILE (type_obj->type)) + { + /* Must reset head of list. */ + struct objfile *objfile = TYPE_OBJFILE (type_obj->type); + + set_objfile_data (objfile, typy_objfile_data_key, type_obj->next); + } + else if (pyty_objects_discardable == type_obj) + pyty_objects_discardable = type_obj->next; + + if (type_obj->next) + type_obj->next->prev = type_obj->prev; +} + static void save_objfile_types (struct objfile *objfile, void *datum) { @@ -616,12 +689,13 @@ save_objfile_types (struct objfile *objfile, void *datum) { type_object *next = obj->next; - htab_empty (copied_types); + gdb_assert (TYPE_OBJFILE (obj->type) == objfile); + typy_unlink (obj); - obj->type = copy_type_recursive (objfile, obj->type, copied_types); + obj->type = copy_type_recursive (obj->type, copied_types); - obj->next = NULL; - obj->prev = NULL; + gdb_assert (TYPE_OBJFILE (obj->type) == NULL); + typy_link (obj); obj = next; } @@ -632,41 +706,25 @@ save_objfile_types (struct objfile *objfile, void *datum) } static void -set_type (type_object *obj, struct type *type) +typy_dealloc (PyObject *obj) { - obj->type = type; - obj->prev = NULL; - if (type && TYPE_OBJFILE (type)) - { - struct objfile *objfile = TYPE_OBJFILE (type); + type_object *type_obj = (type_object *) obj; - obj->next = objfile_data (objfile, typy_objfile_data_key); - if (obj->next) - obj->next->prev = obj; - set_objfile_data (objfile, typy_objfile_data_key, obj); - } - else - obj->next = NULL; + typy_unlink (type_obj); + + type_obj->ob_type->tp_free (obj); } +/* Call type_mark_used for any TYPEs referenced from this GDB source file. */ static void -typy_dealloc (PyObject *obj) +typy_types_mark_used (void) { - type_object *type = (type_object *) obj; - - if (type->prev) - type->prev->next = type->next; - else if (type->type && TYPE_OBJFILE (type->type)) - { - /* Must reset head of list. */ - struct objfile *objfile = TYPE_OBJFILE (type->type); - if (objfile) - set_objfile_data (objfile, typy_objfile_data_key, type->next); - } - if (type->next) - type->next->prev = type->prev; + type_object *type_obj; - type->ob_type->tp_free (type); + for (type_obj = pyty_objects_discardable; + type_obj != NULL; + type_obj = type_obj->next) + type_mark_used (type_obj->type); } /* Create a new Type referring to TYPE. */ @@ -677,7 +735,10 @@ type_to_type_object (struct type *type) type_obj = PyObject_New (type_object, &type_object_type); if (type_obj) - set_type (type_obj, type); + { + type_obj->type = type; + typy_link (type_obj); + } return (PyObject *) type_obj; } @@ -696,14 +757,28 @@ type_object_to_type (PyObject *obj) PyObject * gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw) { - static char *keywords[] = { "name", NULL }; + static char *keywords[] = { "name", "block", NULL }; char *type_name = NULL; struct type *type = NULL; + PyObject *block_obj = NULL; + struct block *block = NULL; - if (! PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, &type_name)) + if (! PyArg_ParseTupleAndKeywords (args, kw, "s|O", keywords, + &type_name, &block_obj)) return NULL; - type = typy_lookup_typename (type_name); + if (block_obj) + { + block = block_object_to_block (block_obj); + if (! block) + { + PyErr_SetString (PyExc_RuntimeError, + "'block' argument must be a Block"); + return NULL; + } + } + + type = typy_lookup_typename (type_name, block); if (! type) return NULL; @@ -737,6 +812,8 @@ gdbpy_initialize_types (void) Py_INCREF (&field_object_type); PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); + + observer_attach_mark_used (typy_types_mark_used); } diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c index 4ccf97f..87cde73 100644 --- a/gdb/python/py-utils.c +++ b/gdb/python/py-utils.c @@ -19,6 +19,7 @@ #include "defs.h" #include "charset.h" +#include "value.h" #include "python-internal.h" @@ -219,3 +220,48 @@ gdbpy_is_string (PyObject *obj) { return PyString_Check (obj) || PyUnicode_Check (obj); } + +/* Converts OBJ to a CORE_ADDR value. + + Returns 1 on success or 0 on failure, with a Python exception set. This + function can also throw GDB exceptions. */ + +int +get_addr_from_python (PyObject *obj, CORE_ADDR *addr) +{ + if (gdbpy_is_value_object (obj)) + *addr = value_as_address (value_object_to_value (obj)); + else if (PyLong_Check (obj)) + { + /* Assume CORE_ADDR corresponds to unsigned long. */ + *addr = PyLong_AsUnsignedLong (obj); + if (PyErr_Occurred () != NULL) + return 0; + } + else if (PyInt_Check (obj)) + { + long val; + + /* Assume CORE_ADDR corresponds to unsigned long. */ + val = PyInt_AsLong (obj); + + if (val >= 0) + *addr = val; + else + { + /* If no error ocurred, VAL is indeed negative. */ + if (PyErr_Occurred () != NULL) + return 0; + + PyErr_SetString (PyExc_ValueError, "negative address"); + return 0; + } + } + else + { + PyErr_SetString (PyExc_TypeError, "invalid type for address"); + return 0; + } + + return 1; +} diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index a792819..bdac80e 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -25,6 +25,7 @@ #include "language.h" #include "dfp.h" #include "valprint.h" +#include "observer.h" #ifdef HAVE_PYTHON @@ -43,6 +44,10 @@ /* Python's long type corresponds to C's long long type. */ #define builtin_type_pylong builtin_type (python_gdbarch)->builtin_long_long +/* Python's long type corresponds to C's long long type. Unsigned version. */ +#define builtin_type_upylong builtin_type \ + (python_gdbarch)->builtin_unsigned_long_long + #define builtin_type_pybool \ language_bool_type (python_language, python_gdbarch) @@ -945,7 +950,34 @@ convert_value_from_python (PyObject *obj) { LONGEST l = PyLong_AsLongLong (obj); - if (! PyErr_Occurred ()) + if (PyErr_Occurred ()) + { + /* If the error was an overflow, we can try converting to + ULONGEST instead. */ + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + { + PyObject *etype, *evalue, *etraceback, *zero; + + PyErr_Fetch (&etype, &evalue, &etraceback); + zero = PyInt_FromLong (0); + + /* Check whether obj is positive. */ + if (PyObject_RichCompareBool (obj, zero, Py_GT) > 0) + { + ULONGEST ul; + + ul = PyLong_AsUnsignedLongLong (obj); + if (! PyErr_Occurred ()) + value = value_from_ulongest (builtin_type_upylong, ul); + } + else + /* There's nothing we can do. */ + PyErr_Restore (etype, evalue, etraceback); + + Py_DECREF (zero); + } + } + else value = value_from_longest (builtin_type_pylong, l); } else if (PyFloat_Check (obj)) @@ -1011,6 +1043,25 @@ gdbpy_history (PyObject *self, PyObject *args) return value_to_value_object (res_val); } +/* Call type_mark_used for any TYPEs referenced from this GDB source file. */ + +static void +python_types_mark_used (void) +{ + value_object *iter; + + for (iter = values_in_python; iter; iter = iter->next) + type_mark_used (value_type (iter->value)); +} + +/* Returns 1 in OBJ is a gdb.Value object, 0 otherwise. */ + +int +gdbpy_is_value_object (PyObject *obj) +{ + return PyObject_TypeCheck (obj, &value_object_type); +} + void gdbpy_initialize_values (void) { @@ -1021,6 +1072,8 @@ gdbpy_initialize_values (void) PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type); values_in_python = NULL; + + observer_attach_mark_used (python_types_mark_used); } diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 9196f08..5230a8c 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -61,36 +61,79 @@ typedef int Py_ssize_t; #define PyEval_ReleaseLock() 0 #endif +#include "command.h" + +struct block; +struct symbol; +struct symtab_and_line; struct value; struct language_defn; extern PyObject *gdb_module; +extern PyTypeObject block_object_type; extern PyTypeObject value_object_type; +extern PyTypeObject symbol_object_type; + +/* Used in python-inferior.c. */ +typedef struct +{ + PyObject_HEAD + + /* The thread we represent. */ + struct thread_info *thread; + + /* The Inferior object to which this thread belongs. */ + PyObject *inf_obj; +} thread_object; PyObject *gdbpy_history (PyObject *self, PyObject *args); +PyObject *gdbpy_breakpoints (PyObject *, PyObject *); PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *); +PyObject *gdbpy_lookup_symbol (PyObject *self, PyObject *args, PyObject *kw); PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args); +PyObject *gdbpy_block_for_pc (PyObject *self, PyObject *args); PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw); PyObject *gdbpy_create_lazy_string_object (CORE_ADDR address, long length, const char *encoding, struct type *type); +PyObject *gdbpy_inferiors (PyObject *unused, PyObject *unused2); +PyObject *gdbpy_selected_thread (PyObject *self, PyObject *args); +PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal); +PyObject *symtab_to_symtab_object (struct symtab *symtab); +PyObject *symbol_to_symbol_object (struct symbol *sym); +PyObject *block_to_block_object (struct block *block); PyObject *value_to_value_object (struct value *v); PyObject *type_to_type_object (struct type *); PyObject *objfile_to_objfile_object (struct objfile *); +PyObject *frame_info_to_frame_object (struct frame_info *frame); +thread_object *create_thread_object (struct thread_info *tp); +thread_object *find_thread_object (ptid_t ptid); +PyObject *find_inferior_object (int pid); PyObject *objfpy_get_printers (PyObject *, void *); +struct block *block_object_to_block (PyObject *obj); +struct symbol *symbol_object_to_symbol (PyObject *obj); struct value *value_object_to_value (PyObject *self); struct value *convert_value_from_python (PyObject *obj); struct type *type_object_to_type (PyObject *obj); +PyObject *gdbpy_get_hook_function (const char *); + void gdbpy_initialize_values (void); +void gdbpy_initialize_breakpoints (void); void gdbpy_initialize_frames (void); +void gdbpy_initialize_symtabs (void); void gdbpy_initialize_commands (void); +void gdbpy_initialize_symbols (void); void gdbpy_initialize_types (void); +void gdbpy_initialize_blocks (void); void gdbpy_initialize_functions (void); void gdbpy_initialize_objfile (void); void gdbpy_initialize_lazy_string (void); +void gdbpy_initialize_parameters (void); +void gdbpy_initialize_thread (void); +void gdbpy_initialize_inferior (void); struct cleanup *make_cleanup_py_decref (PyObject *py); @@ -100,6 +143,12 @@ struct cleanup *ensure_python_env (struct gdbarch *gdbarch, extern struct gdbarch *python_gdbarch; extern const struct language_defn *python_language; +char *gdbpy_parse_command_name (char *text, + struct cmd_list_element ***base_list, + struct cmd_list_element **start_list); + +PyObject *gdbpy_parameter_value (enum var_types, void *); + /* Use this after a TRY_EXCEPT to throw the appropriate Python exception. */ #define GDB_PY_HANDLE_EXCEPTION(Exception) \ @@ -110,6 +159,19 @@ extern const struct language_defn *python_language; "%s", Exception.message); \ } while (0) +/* Use this after a TRY_EXCEPT to throw the appropriate Python + exception. This macro is for use inside setter functions. */ +#define GDB_PY_SET_HANDLE_EXCEPTION(Exception) \ + do { \ + if (Exception.reason < 0) \ + { \ + PyErr_Format (Exception.reason == RETURN_QUIT \ + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError, \ + "%s", Exception.message); \ + return -1; \ + } \ + } while (0) + void gdbpy_print_stack (void); @@ -125,17 +187,22 @@ gdb_byte *gdbpy_extract_lazy_string (PyObject *string, struct type **str_type, long *length, char **encoding); +int gdbpy_is_value_object (PyObject *obj); + /* Note that these are declared here, and not in python.h with the other pretty-printer functions, because they refer to PyObject. */ PyObject *apply_varobj_pretty_printer (PyObject *print_obj, struct value **replacement); PyObject *gdbpy_get_varobj_pretty_printer (struct value *value); +PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value); char *gdbpy_get_display_hint (PyObject *printer); PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args); -extern PyObject *gdbpy_doc_cst; extern PyObject *gdbpy_children_cst; extern PyObject *gdbpy_to_string_cst; extern PyObject *gdbpy_display_hint_cst; +extern PyObject *gdbpy_doc_cst; + +int get_addr_from_python (PyObject *obj, CORE_ADDR *addr); #endif /* GDB_PYTHON_INTERNAL_H */ diff --git a/gdb/python/python.c b/gdb/python/python.c index 29386c9..195dace 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -28,6 +28,7 @@ #include "value.h" #include "language.h" #include "exceptions.h" +#include "event-loop.h" #include @@ -46,10 +47,17 @@ static int gdbpy_auto_load = 1; #include "cli/cli-decode.h" #include "charset.h" #include "top.h" +#include "solib.h" #include "python-internal.h" +#include "linespec.h" +#include "symtab.h" +#include "source.h" #include "version.h" +#include "inferior.h" +#include "gdbthread.h" #include "target.h" #include "gdbthread.h" +#include "event-top.h" static PyMethodDef GdbMethods[]; @@ -197,10 +205,10 @@ python_command (char *arg, int from_tty) NULL (and set a Python exception) on error. Helper function for get_parameter. */ -static PyObject * -parameter_to_python (struct cmd_list_element *cmd) +PyObject * +gdbpy_parameter_value (enum var_types type, void *var) { - switch (cmd->var_type) + switch (type) { case var_string: case var_string_noescape: @@ -208,7 +216,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_filename: case var_enum: { - char *str = * (char **) cmd->var; + char *str = * (char **) var; if (! str) str = ""; return PyString_Decode (str, strlen (str), host_charset (), NULL); @@ -216,7 +224,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_boolean: { - if (* (int *) cmd->var) + if (* (int *) var) Py_RETURN_TRUE; else Py_RETURN_FALSE; @@ -224,7 +232,7 @@ parameter_to_python (struct cmd_list_element *cmd) case var_auto_boolean: { - enum auto_boolean ab = * (enum auto_boolean *) cmd->var; + enum auto_boolean ab = * (enum auto_boolean *) var; if (ab == AUTO_BOOLEAN_TRUE) Py_RETURN_TRUE; else if (ab == AUTO_BOOLEAN_FALSE) @@ -234,15 +242,15 @@ parameter_to_python (struct cmd_list_element *cmd) } case var_integer: - if ((* (int *) cmd->var) == INT_MAX) + if ((* (int *) var) == INT_MAX) Py_RETURN_NONE; /* Fall through. */ case var_zinteger: - return PyLong_FromLong (* (int *) cmd->var); + return PyLong_FromLong (* (int *) var); case var_uinteger: { - unsigned int val = * (unsigned int *) cmd->var; + unsigned int val = * (unsigned int *) var; if (val == UINT_MAX) Py_RETURN_NONE; return PyLong_FromUnsignedLong (val); @@ -280,7 +288,7 @@ gdbpy_parameter (PyObject *self, PyObject *args) if (! cmd->var) return PyErr_Format (PyExc_RuntimeError, "`%s' is not a parameter", arg); - return parameter_to_python (cmd); + return gdbpy_parameter_value (cmd->var_type, cmd->var); } /* A Python function which evaluates a string using the gdb CLI. */ @@ -323,6 +331,105 @@ execute_gdb_command (PyObject *self, PyObject *args) Py_RETURN_NONE; } +/* Implementation of gdb.solib_address (Long) -> String. + Returns the name of the shared library holding a given address, or None. */ + +static PyObject * +gdbpy_solib_address (PyObject *self, PyObject *args) +{ + unsigned long long pc; + char *soname; + PyObject *str_obj; + + if (!PyArg_ParseTuple (args, "K", &pc)) + return NULL; + + soname = solib_name_from_address (current_program_space, pc); + if (soname) + str_obj = PyString_Decode (soname, strlen (soname), host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +/* A Python function which is a wrapper for decode_line_1. */ + +static PyObject * +gdbpy_decode_line (PyObject *self, PyObject *args) +{ + struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to appease gcc. */ + struct symtab_and_line sal; + char *arg = NULL; + int free_sals = 0, i; + PyObject *result = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "|s", &arg)) + return NULL; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (arg) + { + char *copy; + + arg = strdup (arg); + copy = arg; + + sals = decode_line_1 (©, 0, 0, 0, 0, 0); + free_sals = 1; + } + else + { + set_default_source_symtab_and_line (); + sal = get_current_source_symtab_and_line (); + sals.sals = &sal; + sals.nelts = 1; + } + } + if (arg) + xfree (arg); + + if (except.reason < 0) + { + if (free_sals) + xfree (sals.sals); + /* We know this will always throw. */ + GDB_PY_HANDLE_EXCEPTION (except); + } + + if (sals.nelts) + { + result = PyTuple_New (sals.nelts); + for (i = 0; i < sals.nelts; ++i) + { + PyObject *obj; + char *str; + + obj = symtab_and_line_to_sal_object (sals.sals[i]); + if (! obj) + { + Py_DECREF (result); + result = NULL; + break; + } + + PyTuple_SetItem (result, i, obj); + } + } + + if (free_sals) + xfree (sals.sals); + + if (result) + return result; + Py_RETURN_NONE; +} + /* Parse a string and evaluate it as an expression. */ static PyObject * gdbpy_parse_and_eval (PyObject *self, PyObject *args) @@ -361,6 +468,114 @@ source_python_script (FILE *stream, char *file) +/* Posting and handling events. */ + +/* A single event. */ +struct gdbpy_event +{ + /* The Python event. This is just a callable object. */ + PyObject *event; + /* The next event. */ + struct gdbpy_event *next; +}; + +/* All pending events. */ +static struct gdbpy_event *gdbpy_event_list; +/* The final link of the event list. */ +static struct gdbpy_event **gdbpy_event_list_end; + +/* We use a file handler, and not an async handler, so that we can + wake up the main thread even when it is blocked in poll(). */ +static int gdbpy_event_fds[2]; + +/* The file handler callback. This reads from the internal pipe, and + then processes the Python event queue. This will always be run in + the main gdb thread. */ +static void +gdbpy_run_events (int err, gdb_client_data ignore) +{ + struct cleanup *cleanup; + char buffer[100]; + int r; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + /* Just read whatever is available on the fd. It is relatively + harmless if there are any bytes left over. */ + r = read (gdbpy_event_fds[0], buffer, sizeof (buffer)); + + while (gdbpy_event_list) + { + /* Dispatching the event might push a new element onto the event + loop, so we update here "atomically enough". */ + struct gdbpy_event *item = gdbpy_event_list; + gdbpy_event_list = gdbpy_event_list->next; + if (gdbpy_event_list == NULL) + gdbpy_event_list_end = &gdbpy_event_list; + + /* Ignore errors. */ + PyObject_CallObject (item->event, NULL); + + Py_DECREF (item->event); + xfree (item); + } + + do_cleanups (cleanup); +} + +/* Submit an event to the gdb thread. */ +static PyObject * +gdbpy_post_event (PyObject *self, PyObject *args) +{ + struct gdbpy_event *event; + PyObject *func; + int wakeup; + + if (!PyArg_ParseTuple (args, "O", &func)) + return NULL; + + if (!PyCallable_Check (func)) + { + PyErr_SetString (PyExc_RuntimeError, "Posted event is not callable"); + return NULL; + } + + Py_INCREF (func); + + /* From here until the end of the function, we have the GIL, so we + can operate on our global data structures without worrying. */ + wakeup = gdbpy_event_list == NULL; + + event = XNEW (struct gdbpy_event); + event->event = func; + event->next = NULL; + *gdbpy_event_list_end = event; + gdbpy_event_list_end = &event->next; + + /* Wake up gdb when needed. */ + if (wakeup) + { + char c = 'q'; /* Anything. */ + if (write (gdbpy_event_fds[1], &c, 1) != 1) + return PyErr_SetFromErrno (PyExc_IOError); + } + + Py_RETURN_NONE; +} + +/* Initialize the Python event handler. */ +static void +gdbpy_initialize_events (void) +{ + if (!pipe (gdbpy_event_fds)) + { + gdbpy_event_list_end = &gdbpy_event_list; + add_file_handler (gdbpy_event_fds[0], gdbpy_run_events, NULL); + } +} + + + /* Printing. */ /* A python function to write a single string using gdb's filtered @@ -397,6 +612,55 @@ gdbpy_print_stack (void) +/* Script interface. */ + +/* True if 'gdb -P' was used, false otherwise. */ +static int running_python_script; + +/* True if we are currently in a call to 'gdb.cli', false otherwise. */ +static int in_cli; + +/* Enter the command loop. */ + +static PyObject * +gdbpy_cli (PyObject *unused1, PyObject *unused2) +{ + if (! running_python_script || in_cli) + return PyErr_Format (PyExc_RuntimeError, "cannot invoke CLI recursively"); + + in_cli = 1; + cli_command_loop (); + in_cli = 0; + + Py_RETURN_NONE; +} + +/* Set up the Python argument vector and evaluate a script. This is + used to implement 'gdb -P'. */ + +void +run_python_script (int argc, char **argv) +{ + FILE *input; + + /* We never free this, since we plan to exit at the end. */ + ensure_python_env (get_current_arch (), current_language); + + running_python_script = 1; + PySys_SetArgv (argc - 1, argv + 1); + input = fopen (argv[0], "r"); + if (! input) + { + fprintf (stderr, "could not open %s: %s\n", argv[0], strerror (errno)); + exit (1); + } + PyRun_SimpleFile (input, argv[0]); + fclose (input); + exit (0); +} + + + /* 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. */ @@ -640,14 +904,28 @@ Enables or disables auto-loading of Python code when an object is opened."), PyModule_AddStringConstant (gdb_module, "VERSION", (char*) version); PyModule_AddStringConstant (gdb_module, "HOST_CONFIG", (char*) host_name); PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name); +#ifdef PYTHONDIR + PyModule_AddStringConstant (gdb_module, "pythondir", PYTHONDIR); +#else + if (gdb_datadir) + PyModule_AddStringConstant (gdb_module, "datadir", gdb_datadir); +#endif gdbpy_initialize_values (); + gdbpy_initialize_breakpoints (); gdbpy_initialize_frames (); + gdbpy_initialize_symtabs (); gdbpy_initialize_commands (); + gdbpy_initialize_symbols (); + gdbpy_initialize_blocks (); gdbpy_initialize_functions (); gdbpy_initialize_types (); + gdbpy_initialize_parameters (); gdbpy_initialize_objfile (); gdbpy_initialize_lazy_string (); + gdbpy_initialize_thread (); + gdbpy_initialize_inferior (); + gdbpy_initialize_events (); PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers = []"); @@ -683,6 +961,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. */ @@ -702,9 +989,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." }, @@ -725,11 +1017,39 @@ Return a string explaining unwind stop reason." }, "lookup_type (name [, block]) -> type\n\ Return a Type corresponding to the given name." }, + { "lookup_symbol", (PyCFunction) gdbpy_lookup_symbol, + METH_VARARGS | METH_KEYWORDS, + "lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this)\n\ +Return a tuple with the symbol corresponding to the given name (or None) and\n\ +a boolean indicating if name is a field of the current implied argument\n\ +`this' (when the current language is object-oriented)." }, + { "solib_address", gdbpy_solib_address, METH_VARARGS, + "solib_address (Long) -> String.\n\ +Return the name of the shared library holding a given address, or None." }, + + { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS, + "Return the block containing the given pc value, or None." }, + + { "decode_line", gdbpy_decode_line, METH_VARARGS, + "Decode a string argument the way that 'break' or 'edit' does.\n\ +Return a tuple holding the file name (or None) and line number (or None).\n\ +Note: may later change to return an object." }, + + { "selected_thread", gdbpy_selected_thread, METH_NOARGS, + "selected_thread () -> gdb.InferiorThread.\n\ +Return the selected thread object." }, + { "inferiors", gdbpy_inferiors, METH_NOARGS, + "inferiors () -> (gdb.Inferior, ...).\n\ +Return a tuple containing all inferiors." }, + { "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS, "parse_and_eval (String) -> Value.\n\ Parse String as an expression, evaluate it, and return the result as a Value." }, + { "post_event", gdbpy_post_event, METH_VARARGS, + "Post an event into gdb's event loop." }, + { "write", gdbpy_write, METH_VARARGS, "Write a string using gdb's filtered stream." }, { "flush", gdbpy_flush, METH_NOARGS, diff --git a/gdb/python/python.h b/gdb/python/python.h index 5d93f67..1a5b9a8 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -26,6 +26,8 @@ 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 5898aad..23e5f22 100644 --- a/gdb/scm-lang.c +++ b/gdb/scm-lang.c @@ -231,6 +231,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 1e8d48e..95185d4 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 3c70089..0ee7d85 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -408,7 +408,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 94a77fb..7ea68d2 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -326,16 +326,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 826f8bf..4def88d 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1960,7 +1960,6 @@ 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) { bfd *abfd; @@ -1978,8 +1977,7 @@ elf_lookup_lib_symbol (const struct objfile *objfile, if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, 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 842b27c..ac1c407 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1154,13 +1154,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 573f736..51bfce9 100644 --- a/gdb/solist.h +++ b/gdb/solist.h @@ -117,7 +117,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 @@ -157,7 +156,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 c7beaba..e31164c 100644 --- a/gdb/somread.c +++ b/gdb/somread.c @@ -432,6 +432,7 @@ static struct sym_fns som_sym_fns = som_new_init, /* sym_new_init: init anything gbl to entire symtab */ som_symfile_init, /* sym_init: read initial info, setup for sym_read() */ som_symfile_read, /* sym_read: read a symbol file into symtab */ + NULL, /* sym_read_psymbols */ som_symfile_finish, /* sym_finish: finished with file, cleanup */ som_symfile_offsets, /* sym_offsets: Translate ext. to int. relocation */ default_symfile_segments, /* sym_segments: Get segment information from diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c index c6db8dc..7359b50 100644 --- a/gdb/spu-tdep.c +++ b/gdb/spu-tdep.c @@ -1841,7 +1841,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/stack.c b/gdb/stack.c index 2caf9d2..7adc399 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1309,24 +1309,24 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty) else count = -1; - if (info_verbose) - { - struct partial_symtab *ps; - - /* Read in symbols for all of the frames. Need to do this in a - separate pass so that "Reading in symbols for xxx" messages - don't screw up the appearance of the backtrace. Also if - people have strong opinions against reading symbols for - backtrace this may have to be an option. */ - i = count; - for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) - { - QUIT; - ps = find_pc_psymtab (get_frame_address_in_block (fi)); - if (ps) - PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ - } - } + { + struct partial_symtab *ps; + + /* Read in symbols for all of the frames. Need to do this + unconditionally to ensure that psymbols are read. Also need to + do this in a separate pass so that "Reading in symbols for xxx" + messages don't screw up the appearance of the backtrace. Also + if people have strong opinions against reading symbols for + backtrace this may have to be an option. */ + i = count; + for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi)) + { + QUIT; + ps = find_pc_psymtab (get_frame_address_in_block (fi)); + if (info_verbose && ps) + PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in. */ + } + } for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi)) { diff --git a/gdb/symfile.c b/gdb/symfile.c index bc52406..5d5d83f 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -966,13 +966,16 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, /* Give user a chance to burp if we'd be interactively wiping out any existing symbols. */ - if ((have_full_symbols () || have_partial_symbols ()) - && (add_flags & SYMFILE_MAINLINE) + if ((add_flags & SYMFILE_MAINLINE) + && (have_full_symbols () || have_partial_symbols ()) && from_tty + && (have_full_symbols () || have_partial_symbols ()) && !query (_("Load new symbol table from \"%s\"? "), name)) error (_("Not confirmed.")); objfile = allocate_objfile (abfd, flags); + if (add_flags & SYMFILE_MAINLINE) + objfile->flags |= OBJF_MAIN; discard_cleanups (my_cleanups); /* We either created a new mapped symbol table, mapped an existing @@ -999,6 +1002,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, if ((flags & OBJF_READNOW) || readnow_symbol_files) { + require_partial_symbols (objfile); + if (from_tty || info_verbose) { printf_unfiltered (_("expanding to full symbols...")); @@ -2321,6 +2326,7 @@ reread_symbols (void) objfile->symtabs = NULL; objfile->psymtabs = NULL; objfile->psymtabs_addrmap = NULL; + objfile->quick_addrmap = NULL; objfile->free_psymtabs = NULL; objfile->cp_namespace_symtab = NULL; objfile->msymbols = NULL; @@ -2331,6 +2337,8 @@ reread_symbols (void) memset (&objfile->msymbol_demangled_hash, 0, sizeof (objfile->msymbol_demangled_hash)); + objfile->flags &= ~OBJF_SYMTABS_READ; + objfile->psymbol_cache = bcache_xmalloc (); objfile->macro_cache = bcache_xmalloc (); objfile->filename_cache = bcache_xmalloc (); diff --git a/gdb/symfile.h b/gdb/symfile.h index efa069e..b520b93 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -139,6 +139,12 @@ struct sym_fns void (*sym_read) (struct objfile *, int); + /* Read the partial symbols for an objfile. This may be NULL, in + which case gdb assumes that sym_read already read the partial + symbols. */ + + void (*sym_read_psymbols) (struct objfile *); + /* Called when we are finished with an objfile. Should do all cleanup that is specific to the object file format for the particular objfile. */ @@ -315,8 +321,7 @@ extern int auto_solib_limit; extern void set_initial_language (void); -extern struct partial_symtab *allocate_psymtab (const char *, - struct objfile *); +extern struct partial_symtab *allocate_psymtab (const char *, struct objfile *); extern void discard_psymtab (struct partial_symtab *); @@ -387,7 +392,7 @@ void free_symfile_segment_data (struct symfile_segment_data *data); /* From dwarf2read.c */ extern int dwarf2_has_info (struct objfile *); - +extern void dwarf2_create_quick_addrmap (struct objfile *); extern void dwarf2_build_psymtabs (struct objfile *); extern void dwarf2_build_frame_info (struct objfile *); diff --git a/gdb/symmisc.c b/gdb/symmisc.c index 1f3eb9e..d096d5c 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -1143,7 +1143,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 `"); @@ -1160,7 +1160,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 426326d..20d90de 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; } @@ -498,7 +498,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; @@ -695,6 +695,7 @@ symbol_natural_name (const struct general_symbol_info *gsymbol) case language_cplus: case language_java: case language_objc: + case language_fortran: if (gsymbol->language_specific.cplus_specific.demangled_name != NULL) return gsymbol->language_specific.cplus_specific.demangled_name; break; @@ -720,6 +721,7 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol) case language_cplus: case language_java: case language_objc: + case language_fortran: if (gsymbol->language_specific.cplus_specific.demangled_name != NULL) return gsymbol->language_specific.cplus_specific.demangled_name; break; @@ -931,7 +933,13 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) than the later used TEXTLOW/TEXTHIGH one. */ ALL_OBJFILES (objfile) - if (objfile->psymtabs_addrmap != NULL) + { + if (objfile->quick_addrmap) + { + if (!addrmap_find (objfile->quick_addrmap, pc)) + continue; + } + if (require_partial_symbols (objfile)->psymtabs_addrmap != NULL) { struct partial_symtab *pst; @@ -964,6 +972,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section) return pst; } } + } /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs which still have no corresponding full SYMTABs read. But it is not @@ -1231,6 +1240,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. @@ -1257,10 +1282,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 @@ -1270,7 +1299,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); } @@ -1292,7 +1320,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); } @@ -1311,8 +1338,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; @@ -1336,9 +1363,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; @@ -1354,55 +1381,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; @@ -1412,11 +1403,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; @@ -1427,30 +1418,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 (language == language_cplus ) + { + sym = cp_lookup_symbol_imports (block_scope (block_iterator), name, + block_iterator, domain, 1, 1); - if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block)) - break; - block = BLOCK_SUPERBLOCK (block); + 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; } @@ -1484,13 +1526,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; @@ -1506,7 +1547,6 @@ lookup_symbol_aux_block (const char *name, const char *linkage_name, struct symbol * lookup_global_symbol_from_objfile (const struct objfile *main_objfile, const char *name, - const char *linkage_name, const domain_enum domain) { const struct objfile *objfile; @@ -1525,7 +1565,7 @@ lookup_global_symbol_from_objfile (const struct objfile *main_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; @@ -1534,16 +1574,16 @@ lookup_global_symbol_from_objfile (const struct objfile *main_objfile, } /* Now go through psymtabs. */ + require_partial_symbols ((struct objfile *) objfile); ALL_OBJFILE_PSYMTABS (objfile, ps) { if (!ps->readin - && 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); } } @@ -1558,8 +1598,7 @@ lookup_global_symbol_from_objfile (const struct objfile *main_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; @@ -1572,7 +1611,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; @@ -1590,7 +1629,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; @@ -1601,16 +1639,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 @@ -1627,7 +1664,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", @@ -1646,7 +1683,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) { @@ -1680,11 +1716,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 @@ -1692,14 +1728,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; } @@ -1709,7 +1744,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) { @@ -1719,15 +1753,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 @@ -1751,14 +1785,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; @@ -1810,9 +1841,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)) @@ -1829,15 +1858,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); } } @@ -1879,22 +1902,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 @@ -1903,7 +1929,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\ @@ -1927,21 +1953,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 @@ -1950,7 +1981,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\ @@ -1975,9 +2006,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); } @@ -1995,14 +2040,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; @@ -2015,9 +2056,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; @@ -2037,9 +2076,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)) @@ -3261,7 +3298,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[], matching the regexp. That way we don't have to reproduce all of the machinery below. */ - ALL_PSYMTABS (objfile, ps) + ALL_PSYMTABS_REQUIRED (objfile, ps) { struct partial_symbol **bound, **gbound, **sbound; int keep_going = 1; diff --git a/gdb/symtab.h b/gdb/symtab.h index 800ffd8..4253f9d 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -396,7 +396,10 @@ typedef enum domain_enum_tag FUNCTIONS_DOMAIN, /* All defined types */ - TYPES_DOMAIN + TYPES_DOMAIN, + + /* Fortran module. Their naming must be separate. */ + MODULE_DOMAIN } domain_enum; @@ -993,7 +996,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); @@ -1004,7 +1006,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); @@ -1012,7 +1013,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); @@ -1021,21 +1021,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 */ @@ -1065,6 +1062,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 *); @@ -1367,7 +1366,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 e6659c9..eabd9fc 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -120,6 +120,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 *); @@ -583,6 +585,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); @@ -710,6 +713,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); @@ -3277,6 +3283,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) { @@ -3524,6 +3543,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 7103ab2..741b2e5 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -422,6 +422,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; @@ -1274,6 +1275,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) @@ -1314,6 +1324,20 @@ extern int target_search_memory (CORE_ADDR start_addr, ULONGEST pattern_len, CORE_ADDR *found_addrp); +/* Utility functions which can be used by search_memory implementations. */ + +void allocate_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, + ULONGEST *pattern_buf_size); + +void increase_pattern_buffer (char **pattern_bufp, char **pattern_buf_end, + ULONGEST *pattern_buf_size, int val_bytes); + +int search_memory (CORE_ADDR *start_addr, ULONGEST *search_space_len, + const char *pattern_buf, ULONGEST pattern_len, + CORE_ADDR *found_addr); + +void put_bits (bfd_uint64_t data, char *buf, int bits, bfd_boolean big_p); + /* Tracepoint-related operations. */ #define target_trace_init() \ diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S new file mode 100644 index 0000000..83faaf6 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S @@ -0,0 +1,457 @@ + .file "x86_64-vla-pointer.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl foo + .type foo, @function +foo: +.LFB2: + .file 1 "x86_64-vla-pointer.c" + .loc 1 22 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $64, %rsp +.LCFI2: + movl %edi, -36(%rbp) + .loc 1 22 0 + movq %rsp, %rax + movq %rax, -48(%rbp) + .loc 1 23 0 + movl -36(%rbp), %edx + movslq %edx,%rax + subq $1, %rax + movq %rax, -24(%rbp) + .loc 1 24 0 + movslq %edx,%rax + addq $15, %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + subq %rax, %rsp + movq %rsp, -56(%rbp) + movq -56(%rbp), %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + movq %rax, -56(%rbp) + movq -56(%rbp), %rax + movq %rax, -16(%rbp) + .loc 1 27 0 + movl $0, -4(%rbp) + jmp .L2 +.L3: + .loc 1 28 0 + movl -4(%rbp), %esi + movl -4(%rbp), %eax + movl %eax, %ecx + movq -16(%rbp), %rdx + movslq %esi,%rax + movb %cl, (%rdx,%rax) + .loc 1 27 0 + addl $1, -4(%rbp) +.L2: + movl -4(%rbp), %eax + cmpl -36(%rbp), %eax + jl .L3 + .loc 1 30 0 + .globl break_here +break_here: + movq -16(%rbp), %rax + movb $0, (%rax) + movq -48(%rbp), %rsp + .loc 1 31 0 + leave + ret +.LFE2: + .size foo, .-foo + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE0: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .text +.Letext0: + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB2-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad 0x0 + .quad 0x0 + .section .debug_info +.Ldebug_relative: + .long .Ldebug_end - .Ldebug_start +.Ldebug_start: + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .string "foo" + .byte 0x1 + .byte 0x16 + .byte 0x1 + .quad .LFB2 + .quad .LFE2 + .long .LLST0 + .long .Ltype_int - .Ldebug_relative + .uleb128 0x3 + .long .LASF5 + .byte 0x1 + .byte 0x15 + .long .Ltype_int - .Ldebug_relative + .byte 0x2 + .byte 0x91 + .sleb128 -52 +.Ltag_pointer: + .uleb128 0x4 + .byte 0x8 /* DW_AT_byte_size */ + .long .Ltag_array_type - .debug_info /* DW_AT_type */ + .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ + .long .LASF0 + .byte 0x1 + .byte 0x18 +#if 1 + .long .Ltag_pointer - .debug_info +#else + /* Debugging only: Skip the typedef indirection. */ + .long .Ltag_array_type - .debug_info +#endif + /* DW_AT_location: DW_FORM_block1: start */ + .byte 0x3 + .byte 0x91 + .sleb128 -32 +#if 0 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif + /* DW_AT_location: DW_FORM_block1: end */ + .uleb128 0x6 + .string "i" + .byte 0x1 + .byte 0x19 + .long .Ltype_int - .Ldebug_relative + .byte 0x2 + .byte 0x91 + .sleb128 -20 + .byte 0x0 +.Ltype_int: + .uleb128 0x7 + .byte 0x4 + .byte 0x5 + .string "int" +.Ltag_array_type: + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .long .Ltype_char - .Ldebug_relative + .long .Ltype_ulong - .Ldebug_relative /* DW_AT_sibling: DW_FORM_ref4 */ +1: /* DW_AT_data_location: DW_FORM_block1: start */ + .byte 2f - 3f /* length */ +3: + .byte 0x97 /* DW_OP_push_object_address */ +#if 1 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif +2: /* DW_AT_data_location: DW_FORM_block1: end */ + .uleb128 0x9 + .long .Ltype_char - .Ldebug_relative /* DW_AT_type: DW_FORM_ref4 */ + .byte 0x3 + .byte 0x91 + .sleb128 -40 + .byte 0x6 + .byte 0x0 +.Ltype_ulong: + .uleb128 0xa + .byte 0x8 + .byte 0x7 +.Ltype_char: + .uleb128 0xb + .byte 0x1 + .byte 0x6 + .long .LASF1 + .byte 0x0 +.Ldebug_end: + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 /* .Ltag_pointer abbrev */ + .uleb128 0x0f /* DW_TAG_pointer_type */ + .byte 0x0 + .uleb128 0x0b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x6 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .uleb128 0x1 + .byte 0x1 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x1 /* DW_AT_sibling */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x50 /* DW_AT_data_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 + .byte 0x0 + .uleb128 0x9 + .uleb128 0x21 + .byte 0x0 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2f + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0xa + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0xb + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .long 0x16 + .value 0x2 + .long .Ldebug_info0 + .long 0xa8 + .long 0x2d + .string "foo" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0x0 + .value 0x0 + .value 0x0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0x0 + .quad 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "array" +.LASF5: + .string "size" +.LASF3: + .string "x86_64-vla-pointer.c" +.LASF6: + .string "array_t" +.LASF1: + .string "char" +.LASF4: + .string "gdb.arch" +.LASF2: + .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" + .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c new file mode 100644 index 0000000..fe2c8f7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#if 0 + +void +foo (int size) +{ + typedef char array_t[size]; + array_t array; + int i; + + for (i = 0; i < size; i++) + array[i] = i; + + array[0] = 0; /* break-here */ +} + +#else + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp new file mode 100644 index 0000000..d243cf1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp @@ -0,0 +1,66 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if ![istarget "x86_64-*-*"] then { + verbose "Skipping over gdb.arch/x86_64-vla-pointer.exp test made only for x86_64." + return +} + +set testfile x86_64-vla-pointer +set srcasmfile ${testfile}-foo.S +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set binobjfile ${objdir}/${subdir}/${testfile}-foo.o +if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { + untested "Couldn't compile test program" + return -1 +} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested x86_64-vla-pointer + return -1 +} + +gdb_breakpoint "break_here" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "first: whatis array" +gdb_test "ptype array" "type = char \\(\\*\\)\\\[26\\\]" "first: ptype array" + +gdb_test "whatis *array" "type = char \\\[26\\\]" "first: whatis *array" +gdb_test "ptype *array" "type = char \\\[26\\\]" "first: ptype *array" + +gdb_test "p (*array)\[1\]" "\\$\[0-9\] = 1 '\\\\001'" +gdb_test "p (*array)\[2\]" "\\$\[0-9\] = 2 '\\\\002'" +gdb_test "p (*array)\[3\]" "\\$\[0-9\] = 3 '\\\\003'" +gdb_test "p (*array)\[4\]" "\\$\[0-9\] = 4 '\\\\004'" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "second: whatis array" +gdb_test "ptype array" "type = char \\(\\*\\)\\\[78\\\]" "second: ptype array" + +gdb_test "whatis *array" "type = char \\\[78\\\]" "second: whatis *array" +gdb_test "ptype *array" "type = char \\\[78\\\]" "second: ptype *array" diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S new file mode 100644 index 0000000..66f7a39 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S @@ -0,0 +1,455 @@ + .file "x86_64-vla-typedef.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl foo + .type foo, @function +foo: +.LFB2: + .file 1 "x86_64-vla-typedef.c" + .loc 1 22 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $64, %rsp +.LCFI2: + movl %edi, -36(%rbp) + .loc 1 22 0 + movq %rsp, %rax + movq %rax, -48(%rbp) + .loc 1 23 0 + movl -36(%rbp), %edx + movslq %edx,%rax + subq $1, %rax + movq %rax, -24(%rbp) + .loc 1 24 0 + movslq %edx,%rax + addq $15, %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + subq %rax, %rsp + movq %rsp, -56(%rbp) + movq -56(%rbp), %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + movq %rax, -56(%rbp) + movq -56(%rbp), %rax + movq %rax, -16(%rbp) + .loc 1 27 0 + movl $0, -4(%rbp) + jmp .L2 +.L3: + .loc 1 28 0 + movl -4(%rbp), %esi + movl -4(%rbp), %eax + movl %eax, %ecx + movq -16(%rbp), %rdx + movslq %esi,%rax + movb %cl, (%rdx,%rax) + .loc 1 27 0 + addl $1, -4(%rbp) +.L2: + movl -4(%rbp), %eax + cmpl -36(%rbp), %eax + jl .L3 + .loc 1 30 0 + .globl break_here +break_here: + movq -16(%rbp), %rax + movb $0, (%rax) + movq -48(%rbp), %rsp + .loc 1 31 0 + leave + ret +.LFE2: + .size foo, .-foo + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE0: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .text +.Letext0: + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB2-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad 0x0 + .quad 0x0 + .section .debug_info + .long .Ldebug_end - .Ldebug_start +.Ldebug_start: + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .string "foo" + .byte 0x1 + .byte 0x16 + .byte 0x1 + .quad .LFB2 + .quad .LFE2 + .long .LLST0 + .long 0x83 + .uleb128 0x3 + .long .LASF5 + .byte 0x1 + .byte 0x15 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -52 +.Ltag_typedef: + .uleb128 0x4 + .long .LASF6 + .byte 0x1 + .byte 0x17 + .long .Ltag_array_type - .debug_info + .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ + .long .LASF0 + .byte 0x1 + .byte 0x18 +#if 1 + .long .Ltag_typedef - .debug_info +#else + /* Debugging only: Skip the typedef indirection. */ + .long .Ltag_array_type - .debug_info +#endif + /* DW_AT_location: DW_FORM_block1: start */ + .byte 0x3 + .byte 0x91 + .sleb128 -32 +#if 0 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif + /* DW_AT_location: DW_FORM_block1: end */ + .uleb128 0x6 + .string "i" + .byte 0x1 + .byte 0x19 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -20 + .byte 0x0 + .uleb128 0x7 + .byte 0x4 + .byte 0x5 + .string "int" +.Ltag_array_type: + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */ + .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */ +1: /* DW_AT_data_location: DW_FORM_block1: start */ + .byte 2f - 3f /* length */ +3: + .byte 0x97 /* DW_OP_push_object_address */ + .byte 0x6 /* DW_OP_deref */ +2: /* DW_AT_data_location: DW_FORM_block1: end */ + .uleb128 0x9 + .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */ + .byte 0x3 + .byte 0x91 + .sleb128 -40 + .byte 0x6 + .byte 0x0 + .uleb128 0xa + .byte 0x8 + .byte 0x7 + .uleb128 0xb + .byte 0x1 + .byte 0x6 + .long .LASF1 + .byte 0x0 +.Ldebug_end: + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 + .uleb128 0x16 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x6 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .uleb128 0x1 + .byte 0x1 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x1 /* DW_AT_sibling */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x50 /* DW_AT_data_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 + .byte 0x0 + .uleb128 0x9 + .uleb128 0x21 + .byte 0x0 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2f + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0xa + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0xb + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .long 0x16 + .value 0x2 + .long .Ldebug_info0 + .long 0xa8 + .long 0x2d + .string "foo" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0x0 + .value 0x0 + .value 0x0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0x0 + .quad 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "array" +.LASF5: + .string "size" +.LASF3: + .string "x86_64-vla-typedef.c" +.LASF6: + .string "array_t" +.LASF1: + .string "char" +.LASF4: + .string "gdb.arch" +.LASF2: + .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" + .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c new file mode 100644 index 0000000..b809c4e --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#if 0 + +void +foo (int size) +{ + typedef char array_t[size]; + array_t array; + int i; + + for (i = 0; i < size; i++) + array[i] = i; + + array[0] = 0; /* break-here */ +} + +#else + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp new file mode 100644 index 0000000..b05411e --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp @@ -0,0 +1,64 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate. + +if ![istarget "x86_64-*-*"] then { + verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64." + return +} + +set testfile x86_64-vla-typedef +set srcasmfile ${testfile}-foo.S +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set binobjfile ${objdir}/${subdir}/${testfile}-foo.o +if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { + untested "Couldn't compile test program" + return -1 +} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested x86_64-vla-typedef + return -1 +} + +gdb_breakpoint "break_here" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = array_t" "first: whatis array" + +gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array" + +gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\001'" +gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\002'" +gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\003'" +gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\004'" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = array_t" "second: whatis array" + +gdb_test "ptype array" "type = char \\\[78\\\]" "second: ptype array" diff --git a/gdb/testsuite/gdb.base/arrayidx.c b/gdb/testsuite/gdb.base/arrayidx.c index ecc3289..f79ad40 100644 --- a/gdb/testsuite/gdb.base/arrayidx.c +++ b/gdb/testsuite/gdb.base/arrayidx.c @@ -17,6 +17,13 @@ int array[] = {1, 2, 3, 4}; +#ifdef __GNUC__ +struct + { + int a[0]; + } unbound; +#endif + int main (void) { diff --git a/gdb/testsuite/gdb.base/arrayidx.exp b/gdb/testsuite/gdb.base/arrayidx.exp index 0ef6c4b..330ed87 100644 --- a/gdb/testsuite/gdb.base/arrayidx.exp +++ b/gdb/testsuite/gdb.base/arrayidx.exp @@ -59,4 +59,12 @@ gdb_test "print array" \ "\\{\\\[0\\\] = 1, \\\[1\\\] = 2, \\\[2\\\] = 3, \\\[3\\\] = 4\\}" \ "Print array with array-indexes on" - +set test "p unbound.a == &unbound.a\[0\]" +gdb_test_multiple $test $test { + -re " = 1\r\n$gdb_prompt $" { + pass $test + } + -re "No symbol \"unbound\" in current context.\r\n$gdb_prompt $" { + unsupported "$test (no GCC)" + } +} diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.c b/gdb/testsuite/gdb.base/internal-var-field-address.c new file mode 100644 index 0000000..eeb7b85 --- /dev/null +++ b/gdb/testsuite/gdb.base/internal-var-field-address.c @@ -0,0 +1,20 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +struct { + int field; +} staticstruct = { 1 }; diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.exp b/gdb/testsuite/gdb.base/internal-var-field-address.exp new file mode 100644 index 0000000..6d82e73 --- /dev/null +++ b/gdb/testsuite/gdb.base/internal-var-field-address.exp @@ -0,0 +1,26 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set test internal-var-field-address +set binfile ${test}.x +if { [gdb_compile "${srcdir}/${subdir}/${test}.c" "${objdir}/${subdir}/${binfile}" object {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +clean_restart $binfile + +gdb_test {set $varstruct = staticstruct} +gdb_test {p $varstruct.field} " = 1" diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c new file mode 100644 index 0000000..c5d5ee0 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int +main (int argc, char **argv) +{ + int array[argc]; + + array[0] = array[0]; + + abort (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp new file mode 100644 index 0000000..7203a48 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.exp @@ -0,0 +1,108 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# We could crash in: +# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69 +# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97 +# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL)); +# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496 +# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156 +# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206 +# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430 +# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840 +# ... +# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292 +# ... +# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273 + +set testfile vla-overflow +set shfile ${objdir}/${subdir}/${testfile}-gdb.sh +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +set f [open "|getconf PAGESIZE" "r"] +gets $f pagesize +close $f + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set pid_of_gdb [exp_pid -i [board_info host fileid]] + +if { [runto_main] < 0 } { + untested vla-overflow + return -1 +} + +# Get the GDB memory size when we stay at main. + +proc memory_v_pages_get {} { + global pid_of_gdb pagesize + set fd [open "/proc/$pid_of_gdb/statm"] + gets $fd line + close $fd + # number of pages of virtual memory + scan $line "%d" drs + return $drs +} + +set pages_found [memory_v_pages_get] + +set mb_reserve 10 +verbose -log "pages_found = $pages_found, mb_reserve = $mb_reserve" +set kb_found [expr $pages_found * $pagesize / 1024] +set kb_permit [expr $kb_found + 1 * 1024 + $mb_reserve * 1024] +verbose -log "kb_found = $kb_found, kb_permit = $kb_permit" + +# Create the ulimit wrapper. +set f [open $shfile "w"] +puts $f "#! /bin/sh" +puts $f "ulimit -v $kb_permit" +puts $f "exec $GDB \"\$@\"" +close $f +remote_exec host "chmod +x $shfile" + +gdb_exit +set GDBold $GDB +set GDB "$shfile" +gdb_start +set GDB $GDBold + +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set pid_of_gdb [exp_pid -i [board_info host fileid]] + +# Check the size again after the second run. +# We must not stop in main as it would cache `array' and never crash later. + +gdb_run_cmd + +verbose -log "kb_found before abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" + +gdb_test "" "Program received signal SIGABRT, Aborted..*" "Enter abort()" + +verbose -log "kb_found in abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" + +# `abort' can get expressed as `*__GI_abort'. +gdb_test "bt" "in \[^ \]*abort \\(.* in main \\(.*" "Backtrace after abort()" + +verbose -log "kb_found in bt after abort() = [expr [memory_v_pages_get] * $pagesize / 1024]" diff --git a/gdb/testsuite/gdb.base/vla.c b/gdb/testsuite/gdb.base/vla.c new file mode 100644 index 0000000..e1f3ed1 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla.c @@ -0,0 +1,55 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +void +marker (void) +{ +} + +void +bar (char *a, char *b, char *c, int size) +{ + memset (a, '1', size); + memset (b, '2', size); + memset (c, '3', 48); +} + +void +foo (int size) +{ + char temp1[size]; + char temp3[48]; + + temp1[size - 1] = '\0'; + { + char temp2[size]; + + bar (temp1, temp2, temp3, size); + + marker (); /* break-here */ + } +} + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp new file mode 100644 index 0000000..5da7378 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla.exp @@ -0,0 +1,62 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile vla +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested vla + return -1 +} + +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3" + +gdb_test "p temp1" " = '1' " "first: print temp1" +gdb_test "p temp2" " = '2' " "first: print temp2" +gdb_test "p temp3" " = '3' " "first: print temp3" + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3" + +gdb_test "p temp1" " = '1' " "second: print temp1" +gdb_test "p temp2" " = '2' " "second: print temp2" +gdb_test "p temp3" " = '3' " "second: print temp3" diff --git a/gdb/testsuite/gdb.cp/Makefile.in b/gdb/testsuite/gdb.cp/Makefile.in index c990a64..c964db9 100644 --- a/gdb/testsuite/gdb.cp/Makefile.in +++ b/gdb/testsuite/gdb.cp/Makefile.in @@ -4,7 +4,7 @@ srcdir = @srcdir@ EXECUTABLES = ambiguous annota2 anon-union cplusfuncs cttiadd \ derivation inherit local member-ptr method misc \ overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \ - ref-types ref-params method2 pr9594 gdb2495 virtfunc2 + ref-types ref-params method2 pr9594 gdb2495 gdb9593 virtfunc2 all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." diff --git a/gdb/testsuite/gdb.cp/cp-relocate.exp b/gdb/testsuite/gdb.cp/cp-relocate.exp index f81a212..30d362a 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 f4f78a6..11dba06 100644 --- a/gdb/testsuite/gdb.cp/cplusfuncs.cc +++ b/gdb/testsuite/gdb.cp/cplusfuncs.cc @@ -195,6 +195,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 f322586..443af7a 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 "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*($dm_type_void)\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)" + } + } } # @@ -351,8 +492,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 @@ -410,8 +552,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);" } @@ -426,6 +568,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)" @@ -479,7 +622,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)" } # @@ -489,17 +632,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)" @@ -522,17 +669,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/ctti.exp b/gdb/testsuite/gdb.cp/ctti.exp index 454c6f4..8f88ad7 100644 --- a/gdb/testsuite/gdb.cp/ctti.exp +++ b/gdb/testsuite/gdb.cp/ctti.exp @@ -85,11 +85,6 @@ gdb_test "print c" "\\$\[0-9\]+ = 194 .*" gdb_test "print f" "\\$\[0-9\]+ = 9" gdb_test "print i" "\\$\[0-9\]+ = 4" -# TODO: this needs more work before actually deploying it. -# So bail out here. - -if { [ test_compiler_info gcc-*] } then { continue } - gdb_test_multiple "print add(2,2)" "print add(2,2)" { -re "\\$\[0-9\]+ = 4\r\n$gdb_prompt $" { pass "print add(2,2)" diff --git a/gdb/testsuite/gdb.cp/expand-sals.exp b/gdb/testsuite/gdb.cp/expand-sals.exp index 25ec4a9..e4fd59b 100644 --- a/gdb/testsuite/gdb.cp/expand-sals.exp +++ b/gdb/testsuite/gdb.cp/expand-sals.exp @@ -46,7 +46,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/gdb9593.cc b/gdb/testsuite/gdb.cp/gdb9593.cc new file mode 100644 index 0000000..783c962 --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb9593.cc @@ -0,0 +1,180 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include + +using namespace std; + +class NextOverThrowDerivates +{ + +public: + + + // Single throw an exception in this function. + void function1() + { + throw 20; + } + + // Throw an exception in another function. + void function2() + { + function1(); + } + + // Throw an exception in another function, but handle it + // locally. + void function3 () + { + { + try + { + function1 (); + } + catch (...) + { + cout << "Caught and handled function1 exception" << endl; + } + } + } + + void rethrow () + { + try + { + function1 (); + } + catch (...) + { + throw; + } + } + + void finish () + { + // We use this to test that a "finish" here does not end up in + // this frame, but in the one above. + try + { + function1 (); + } + catch (int x) + { + } + function1 (); // marker for until + } + + void until () + { + function1 (); + function1 (); // until here + } + +}; +NextOverThrowDerivates next_cases; + + +int main () +{ + try + { + next_cases.function1 (); + } + catch (...) + { + // Discard + } + + try + { + next_cases.function2 (); + } + catch (...) + { + // Discard + } + + try + { + // This is duplicated so we can next over one but step into + // another. + next_cases.function2 (); + } + catch (...) + { + // Discard + } + + next_cases.function3 (); + + try + { + next_cases.rethrow (); + } + catch (...) + { + // Discard + } + + try + { + // Another duplicate so we can test "finish". + next_cases.function2 (); + } + catch (...) + { + // Discard + } + + // Another test for "finish". + try + { + next_cases.finish (); + } + catch (...) + { + } + + // Test of "until". + try + { + next_cases.finish (); + } + catch (...) + { + } + + // Test of "until" with an argument. + try + { + next_cases.until (); + } + catch (...) + { + } + + // Test of "advance". + try + { + next_cases.until (); + } + catch (...) + { + } +} + diff --git a/gdb/testsuite/gdb.cp/gdb9593.exp b/gdb/testsuite/gdb.cp/gdb9593.exp new file mode 100644 index 0000000..ee9aeff --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb9593.exp @@ -0,0 +1,185 @@ +# Copyright 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +if $tracelevel then { + strace $tracelevel +} + +if { [skip_cplus_tests] } { continue } + +set prms_id 9593 +set bug_id 0 + +set testfile "gdb9593" +set srcfile ${testfile}.cc +set binfile $objdir/$subdir/$testfile + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info ${binfile} "c++"] { + untested gdb9593.exp + return -1 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested gdb9593.exp + return -1 +} + +# Some targets can't do function calls, so don't even bother with this +# test. +if [target_info exists gdb,cannot_call_functions] { + setup_xfail "*-*-*" 9593 + fail "This target can not call functions" + continue +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] then { + perror "couldn't run to main" + continue +} + +# See whether we have the needed unwinder hooks. +set ok 1 +gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" { + -re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" { + pass "check for unwinder hook" + } + -re "No symbol .* in current context.\r\n$gdb_prompt $" { + # Pass the test so we don't get bogus fails in the results. + pass "check for unwinder hook" + set ok 0 + } +} +if {!$ok} { + untested gdb9593.exp + return -1 +} + +# See http://sourceware.org/bugzilla/show_bug.cgi?id=9593 + +gdb_test "next" \ + ".*catch (...).*" \ + "next over a throw 1" + +gdb_test "next" \ + ".*next_cases.function2.*" \ + "next past catch 1" + +gdb_test "next" \ + ".*catch (...).*" \ + "next over a throw 2" + +gdb_test "next" \ + ".*next_cases.function2.*" \ + "next past catch 2" + +gdb_test "step" \ + ".*function1().*" \ + "step into function2 1" + +gdb_test "next" \ + ".*catch (...).*" \ + "next over a throw 3" + +gdb_test "next" \ + ".*next_cases.function3.*" \ + "next past catch 3" + +gdb_test "next" \ + ".*next_cases.rethrow.*" \ + "next over a throw 4" + +gdb_test "next" \ + ".*catch (...).*" \ + "next over a rethrow" + +gdb_test "next" \ + ".*next_cases.function2.*" \ + "next after a rethrow" + +gdb_test "step" \ + ".*function1().*" \ + "step into function2 2" + +gdb_test "finish" \ + ".*catch (...).*" \ + "finish 1" + +gdb_test "next" \ + ".*next_cases.finish ().*" \ + "next past catch 4" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into finish method" + +gdb_test "finish" \ + ".*catch (...).*" \ + "finish 2" + +gdb_test "next" \ + ".*next_cases.finish ().*" \ + "next past catch 5" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into finish, for until" + +gdb_test "until" \ + ".*catch .int x.*" \ + "until with no argument 1" + +set line [gdb_get_line_number "marker for until" $testfile.cc] + +gdb_test "until $line" \ + ".*function1 ().*" \ + "next past catch 6" + +gdb_test "until" \ + ".*catch (...).*" \ + "until with no argument 2" + +set line [gdb_get_line_number "until here" $testfile.cc] + +gdb_test "next" \ + ".*next_cases.until ().*" \ + "next past catch 6" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into until" + +gdb_test "until $line" \ + ".*catch (...).*" \ + "until-over-throw" + +gdb_test "next" \ + ".*next_cases.until ().*" \ + "next past catch 7" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into until, for advance" + +gdb_test "advance $line" \ + ".*catch (...).*" \ + "advance-over-throw" diff --git a/gdb/testsuite/gdb.cp/member-ptr.cc b/gdb/testsuite/gdb.cp/member-ptr.cc index ffffb4c..b406a59 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 6832f3b..baf08d7 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..46d4c18 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-recursive.cc @@ -0,0 +1,47 @@ +namespace A{ + int ax = 9; +} + +namespace B{ + using namespace A; +} + +namespace C{ + using namespace B; +} + +using namespace C; + +//--------------- +namespace D{ + using namespace D; + int dx = 99; +} +using namespace D; + +//--------------- +namespace{ + namespace{ + int xx = 999; + } +} + +//--------------- +namespace E{ + int ex = 9999; +} + +namespace F{ + namespace FE = E; +} + +namespace G{ + namespace GF = F; +} + +//---------------- +int main(){ + using namespace D; + namespace GX = G; + return ax + dx + xx + G::GF::FE::ex; +} diff --git a/gdb/testsuite/gdb.cp/namespace-recursive.exp b/gdb/testsuite/gdb.cp/namespace-recursive.exp new file mode 100644 index 0000000..5543757 --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-recursive.exp @@ -0,0 +1,75 @@ +# 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" + +############################################ +# Test printing using recursive namespace +# aliases. + +setup_kfail "gdb/10541" "*-*-*" +gdb_test "ptype G::GF" "= namespace F" + +setup_kfail "gdb/10541" "*-*-*" +gdb_test "print G::GF::FE::ex" "= 9999" diff --git a/gdb/testsuite/gdb.cp/namespace-stress-declarations.cc b/gdb/testsuite/gdb.cp/namespace-stress-declarations.cc new file mode 100644 index 0000000..173e49b --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-stress-declarations.cc @@ -0,0 +1,93 @@ +int a; +int b; +int c; +int d; +int e; +int f; +int g; +int h; +int i; +int j; +int k; +int l; +int m; +int n; +int o; +int p; +int q; +int r; +int s; +int t; +int u; +int v; +int w; +int x; +int y; +int z; + +namespace A +{ + int xyz; + + using ::a; + using ::b; + using ::c; + using ::d; + using ::e; + using ::f; + using ::g; + using ::h; + using ::i; + using ::j; + using ::k; + using ::l; + using ::m; + using ::n; + using ::o; + using ::p; + using ::q; + using ::r; + using ::s; + using ::t; + using ::u; + using ::v; + using ::w; + using ::x; + using ::y; + using ::z; + +} + +using A::a; +using A::b; +using A::c; +using A::d; +using A::e; +using A::f; +using A::g; +using A::h; +using A::i; +using A::j; +using A::k; +using A::l; +using A::m; +using A::n; +using A::o; +using A::p; +using A::q; +using A::r; +using A::s; +using A::t; +using A::u; +using A::v; +using A::w; +using A::x; +using A::y; +using A::z; + +using namespace A; + +int main () +{ + return 0; +} \ No newline at end of file diff --git a/gdb/testsuite/gdb.cp/namespace-stress-declarations.exp b/gdb/testsuite/gdb.cp/namespace-stress-declarations.exp new file mode 100644 index 0000000..f22a14e --- /dev/null +++ b/gdb/testsuite/gdb.cp/namespace-stress-declarations.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-declarations +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 fakex" "No symbol \"fakex\" in current context." 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 319552b..0673088 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,42 +51,155 @@ 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 -setup_kfail "gdb/7935" "*-*-*" if ![runto marker2] then { perror "couldn't run to breakpoint marker2" 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 -setup_kfail "gdb/7936" "*-*-*" if ![runto marker4] then { perror "couldn't run to breakpoint marker4" 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 4362fd8..f7cfd57 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 @@ -241,11 +242,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\"." @@ -255,8 +261,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 1bfa0f3..9fd31a8 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 5b06b31..3e47c77 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/realcpp.cc b/gdb/testsuite/gdb.cp/realcpp.cc new file mode 100644 index 0000000..8e4f72a --- /dev/null +++ b/gdb/testsuite/gdb.cp/realcpp.cc @@ -0,0 +1,409 @@ +#include +#include + +// Forward decls +class base; +class derived; + +// A simple template with specializations +template +class tclass +{ +public: + void do_something () { } // tclass::do_something +}; + +template <> +void tclass::do_something () { } // tclass::do_something + +template <> +void tclass::do_something () { } // tclass::do_something + +template<> +void tclass::do_something () { } // tclass::do_something + +template<> +void tclass::do_something () { } // tclass::do_something + +// A simple template with multiple template parameters +template +void flubber (void) // flubber +{ + A a; + B b; + C c; + D d; + E e; + + ++a; + ++b; + ++c; + ++d; + ++e; +} + +// Some contrived policies +template +struct operation_1 +{ + static void function (void) { } // operation_1::function +}; + +template +struct operation_2 +{ + static void function (void) { } // operation_2::function +}; + +template +struct operation_3 +{ + static void function (void) { } // operation_3::function +}; + +template +struct operation_4 +{ + static void function (void) { } // operation_4::function +}; + +// A policy-based class w/ and w/o default policy +template +class policy : public Policy +{ +public: + policy (T obj) : obj_ (obj) { } // policy::policy + +private: + T obj_; +}; + +template > +class policyd : public Policy +{ +public: + policyd (T obj) : obj_ (obj) { } // policyd::policyd + ~policyd (void) { } // policyd::~policyd + +private: + T obj_; +}; + +typedef policy > policy1; +typedef policy > policy2; +typedef policy > policy3; +typedef policy > policy4; + +typedef policyd policyd1; +typedef policyd policyd2; +typedef policyd policyd3; +typedef policyd policyd4; +typedef policyd > policyd5; + +class fluff { }; +static fluff *g_fluff = new fluff (); + +class base +{ +protected: + int foo_; + +public: + base (void) : foo_ (42) { } // base::base(void) + base (int foo) : foo_ (foo) { } // base::base(int) + ~base (void) { } // base::~base + + // Some overloaded methods + int overload (void) const { return 0; } // base::overload(void) const + int overload (int i) const { return 1; } // base::overload(int) const + int overload (short s) const { return 2; } // base::overload(short) const + int overload (long l) const { return 3; } // base::overload(long) const + int overload (char* a) const { return 4; } // base::overload(char*) const + int overload (base& b) const { return 5; } // base::overload(base&) const + + // Operators + int operator+ (base const& o) const // base::operator+ + { return foo_ + o.foo_; } + + base operator++ (void) // base::operator++ + { ++foo_; return *this; } + + base operator+=(base const& o) // base::operator+= + { foo_ += o.foo_; return *this; } + + int operator- (base const& o) const // base::operator- + { return foo_ - o.foo_; } + + base operator-- (void) // base::operator-- + { --foo_; return *this; } + + base operator-= (base const& o) // base::operator-= + { foo_ -= o.foo_; return *this; } + + int operator* (base const& o) const // base::operator* + { return foo_ * o.foo_; } + + base operator*= (base const& o) // base::operator*= + { foo_ *= o.foo_; return *this; } + + int operator/ (base const& o) const // base::operator/ + { return foo_ / o.foo_; } + + base operator/= (base const& o) // base::operator/= + { foo_ /= o.foo_; return *this; } + + int operator% (base const& o) const // base::operator% + { return foo_ % o.foo_; } + + base operator%= (base const& o) // base::operator%= + { foo_ %= o.foo_; return *this; } + + bool operator< (base const& o) const // base::operator< + { return foo_ < o.foo_; } + + bool operator<= (base const& o) const // base::operator<= + { return foo_ <= o.foo_; } + + bool operator> (base const& o) const // base::operator> + { return foo_ > o.foo_; } + + bool operator>= (base const& o) const // base::operator>= + { return foo_ >= o.foo_; } + + bool operator!= (base const& o) const // base::operator!= + { return foo_ != o.foo_; } + + bool operator== (base const& o) const // base::operator== + { return foo_ == o.foo_; } + + bool operator! (void) const // base::operator! + { return !foo_; } + + bool operator&& (base const& o) const // base::operator&& + { return foo_ && o.foo_; } + + bool operator|| (base const& o) const // base::operator|| + { return foo_ || o.foo_; } + + int operator<< (int value) const // base::operator<< + { return foo_ << value; } + + base operator<<= (int value) // base::operator<<= + { foo_ <<= value; return *this; } + + int operator>> (int value) const // base::operator>> + { return foo_ >> value; } + + base operator>>= (int value) // base::operator>>= + { foo_ >>= value; return *this; } + + int operator~ (void) const // base::operator~ + { return ~foo_; } + + int operator& (base const& o) const // base::operator& + { return foo_ & o.foo_; } + + base operator&= (base const& o) // base::operator&= + { foo_ &= o.foo_; return *this; } + + int operator| (base const& o) const // base::operator| + { return foo_ | o.foo_; } + + base operator|= (base const& o) // base::operator|= + { foo_ |= o.foo_; return *this; } + + int operator^ (base const& o) const // base::operator^ + { return foo_ ^ o.foo_; } + + base operator^= (base const& o) // base::operator^= + { foo_ ^= o.foo_; return *this; } + + base operator= (base const& o) // base::operator= + { foo_ = o.foo_; return *this; } + + void operator() (void) const // base::operator() + { return; } + + int operator[] (int idx) const // base::operator[] + { return idx; } + + void* operator new (size_t size) throw () // base::operator new + { return malloc (size); } + + void operator delete (void* ptr) // base::operator delete + { free (ptr); } + + void* operator new[] (size_t size) throw () // base::operator new[] + { return malloc (size); } + + void operator delete[] (void* ptr) // base::operator delete[] + { free (ptr); } + + base const* operator-> (void) const // base::opeartor-> + { return this; } + + int operator->* (base const& b) const // base::operator->* + { return foo_ * b.foo_; } + + operator char* () const { return const_cast ("hello"); } // base::operator char* + operator int () const { return 21; } // base::operator int + operator fluff* () const { return new fluff (); } // base::operator fluff* + operator fluff** () const { return &g_fluff; } // base::operator fluff** +}; + +class base1 : public virtual base +{ +public: + base1 (void) : foo_ (21) { } // base1::base1(void) + base1 (int a) : foo_(a) { } // base1::base1(int) + void a_function (void) const { } // base1::a_function + +protected: + int foo_; +}; + +class base2 : public virtual base +{ +public: + base2 () : foo_ (3) { } // base2::base2 + +protected: + void a_function (void) const { } // base2::a_function + int foo_; +}; + +class derived : public base1, public base2 +{ + public: + derived(void) : foo_ (4) { } // derived::derived + void a_function (void) const // derived::a_function + { + this->base1::a_function (); + this->base2::a_function (); + } + + protected: + int foo_; +}; + +int +main (int argc, char* argv[]) // main +{ // main + derived d; + void (derived::*pfunc) (void) const = &derived::a_function; + (d.*pfunc) (); + + base a (1), b (3), c (8); + (void) a.overload (); + (void) a.overload (static_cast (0)); + (void) a.overload (static_cast (0)); + (void) a.overload (static_cast (0)); + (void) a.overload (static_cast (0)); + (void) a.overload (a); + + int r; + r = b + c; + ++a; + a += b; + r = b - c; + --a; + a -= b; + r = b * c; + a *= b; + r = b / c; + a /= b; + r = b % c; + a %= b; + bool x = (b < c); + x = (b <= c); + x = (b > c); + x = (b >= c); + x = (b != c); + x = (b == c); + x = (!b); + x = (b && c); + x = (b || c); + r = b << 2; + a <<= 1; + r = b >> 2; + a >>= 1; + r = ~b; + r = b & c; + a &= c; + r = b | c; + a |= c; + r = b ^ c; + a ^= c; + a = c; + a (); + int i = a[3]; + derived* f = new derived (); + derived* g = new derived[3]; + delete f; + delete[] g; + a->overload (); + r = a->*b; + + tclass char_tclass; + tclass int_tclass; + tclass short_tclass; + tclass long_tclass; + tclass base_tclass; + char_tclass.do_something (); + int_tclass.do_something (); + short_tclass.do_something (); + long_tclass.do_something (); + base_tclass.do_something (); + + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + flubber (); + + policy1 p1 (1); + p1.function (); + policy2 p2 (2); + p2.function (); + policy3 p3 (3); + p3.function (); + policy4 p4 (4); + p4.function (); + + policyd1 pd1 (5); + pd1.function (); + policyd2 pd2 (6); + pd2.function (); + policyd3 pd3 (7); + pd3.function (); + policyd4 pd4 (d); + pd4.function (); + policyd5 pd5 (int_tclass); + pd5.function (); + + base1 b1 (3); + + r = a; + char* str = a; + fluff* flp = a; + fluff** flpp = a; +} + diff --git a/gdb/testsuite/gdb.cp/realcpp.exp b/gdb/testsuite/gdb.cp/realcpp.exp new file mode 100644 index 0000000..4e92e75 --- /dev/null +++ b/gdb/testsuite/gdb.cp/realcpp.exp @@ -0,0 +1,891 @@ +# 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 . + +# This file is part of the gdb testsuite. + +### +# +# SOME IMPORTANT NOTES +# +### + +# The "info func" tests here aren't complete. I've commented them +# out for now. + +# A helper proc which sets a breakpoint at FUNC and attempts to +# run to the breakpoint. +proc test_breakpoint {func} { + global DEC + + # Restart every time + if {![runto_main]} { + perror "could not run to main when attempting to break at $func" + continue + } else { + gdb_breakpoint "$func" + set i [expr {[string last : $func] + 1}] + set efunc [escape [string range $func $i end]] + gdb_test "continue" \ + "Continuing.\r\n\r\nBreakpoint $DEC+,.*$efunc.*" \ + "continue to $func" + } +} + +# Escape expect-reserved characters in the string +proc escape {string} { + regsub -all {\*} $string {\*} string + regsub -all {\(} $string {\(} string + regsub -all {\)} $string {\)} string + regsub -all {\]} $string {\]} string + regsub -all {\[} $string {\[} string + regsub -all {\+} $string {\+} string + regsub -all {\^} $string {\^} string + regsub -all {\!} $string {\!} string + return $string +} + +# Add a function to the list of tested functions +# FUNC is the name of the function (which will be passed to gdb commands) +# TYPE is the type of the function, as expected from the "print" command +# PRINT is the name of the function, as expected result of the print command +# *OR* "-", indicating that FUNC should be used (needed for virtual/inherited +# funcs) +# LST is either the expected result of the list command (the comment from +# the source code) *OR* "-", in which case FUNC will be used +# INF is the expected result of "info func" +# +# If any of PRINT, LST, or INF is "", the test will be skipped +# +# Usage: +# add NAME TYPE PRINT LST INFO +# add NAME TYPE PRINT - INFO +proc add {func type print lst inf} { + global all_functions CONVAR ADDR + + set all_functions($func,type) $type + if {$print == "-"} { + set print $func + } + + # An exception: since gdb canonicalizes C++ output, + # "(void)" must be mutated to "()". + set print [regsub {\(void\)} $print {()}] + + set all_functions($func,print) \ + "$CONVAR = {[escape $type]} $ADDR <[escape $print].*>" + if {$lst == "-"} { + set lst "$func" + } + set all_functions($func,list) ".*// [escape $lst]" + set all_functions($func,info_func) $inf +} + +proc get {func cmd} { + global all_functions + return $all_functions($func,$cmd) +} + +# Returns a list of function names for a given command +proc get_functions {cmd} { + global all_functions + set result {} + foreach i [array names all_functions *,$cmd] { + if {$all_functions($i) != ""} { + set idx [string last , $i] + if {$idx != -1} { + lappend result [string range $i 0 [expr {$idx - 1}]] + } + } + } + + return [lsort $result] +} + +# Some convenience variables for this test +set DEC {[0-9]}; # a decimal number +set HEX {[0-9a-fA-F]}; # a hexidecimal number +set CONVAR "\\\$$DEC+"; # convenience variable regexp +set ADDR "0x$HEX+"; # address + +# An array of functions/methods that we are testing... +# Each element consists is indexed by NAME,COMMAND, where +# NAME is the function name and COMMAND is the gdb command that +# we are testing. The value of the array for any index pair is +# the expected result of running COMMAND with the NAME as argument. +# If the value is blank, the test will be skipped for the given function. + +# The array holding all functions/methods to test. Valid subindexes +# are (none need character escaping -- "add" will take care of that): + +# add name type print_name list info_func +# NAME,type: value is type of function +# NAME,print: value is print name of function (careful w/inherited/virtual!) +# NAME,list: value is comment in source code on first line of function +# (without the leading "//") +# NAME,info_func: value is the expected result of "info func" +array set all_functions {} + +# "Normal" functions/methods +add {main} \ + {int (int, char **)} \ + - \ + - \ + {int main(int, char **);} +add {derived::a_function} \ + {void (const derived * const)} \ + - \ + - \ + {void derived::a_function();} +add {base1::a_function} \ + {void (const base1 * const)} \ + - \ + - \ + {void base1::a_function();} +add {base2::a_function} \ + {void (const base2 * const)} \ + - \ + - \ + {void base2::a_function();} + +# Constructors +add {derived::derived} \ + {void (derived * const)} \ + - \ + - \ + {void derived::derived();} +add {base1::base1(void)} \ + {void (base1 * const, const void ** const)} \ + - \ + - \ + {void base1::base1();} +add {base1::base1(int)} \ + {void (base1 * const, int)} \ + - \ + - \ + {void base1::base1(int);} +add {base2::base2} \ + {void (base2 * const, const void ** const)} \ + - \ + - \ + {void base2::base2();} +add {base::base(void)} \ + {void (base * const)} \ + - \ + - \ + {void base::base();} +add {base::base(int)} \ + {void (base * const, int)} \ + - \ + - \ + {void base::base();} + +# Destructors +add {base::~base} \ + {void (base * const)} \ + - \ + - \ + {void base::~base();} + +# Overloaded methods (all are const -- we try to use the void +# method with and without specifying "const") +add {base::overload(void)} \ + {int (const base * const)} \ + - \ + {base::overload(void) const} \ + {int base::overload() const;} +add {base::overload(void) const} \ + {int (const base * const)} \ + - \ + {base::overload(void) const} \ + {int base::overload() const;} +add {base::overload(int) const} \ + {int (const base * const, int)} \ + - \ + - \ + {int base::overload(int) const;} +add {base::overload(short) const} \ + {int (const base * const, short)} \ + - \ + - \ + {int base::overload(short) const;} +add {base::overload(long) const} \ + {int (const base * const, long)} \ + - \ + - \ + {int base::overload(long) const;} +add {base::overload(char*) const} \ + {int (const base * const, char *)} \ + - \ + - \ + {int base::overload(char *) const;} +add {base::overload(base&) const} \ + {int (const base * const, base &)} \ + - \ + - \ + {int base::overload(base &) const;} + +# Operators +add {base::operator+} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator++} \ + {base (base * const)} \ + - \ + - \ + - +add {base::operator+=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator-} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator--} \ + {base (base * const)} \ + - \ + - \ + - +add {base::operator-=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator*} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator*=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator/} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator/=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator%} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator%=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator<} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator<=} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator>} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator>=} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator!=} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator==} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator!} \ + {bool (const base * const)} \ + - \ + - \ + - +add {base::operator&&} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator||} \ + {bool (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator<<} \ + {int (const base * const, int)} \ + - \ + - \ + - +add {base::operator<<=} \ + {base (base * const, int)} \ + - \ + - \ + - +add {base::operator>>} \ + {int (const base * const, int)} \ + - \ + - \ + - +add {base::operator>>=} \ + {base (base * const, int)} \ + - \ + - \ + - +add {base::operator~} \ + {int (const base * const)} \ + - \ + - \ + - +add {base::operator&} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator&=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator|} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator|=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator^} \ + {int (const base * const, const base &)} \ + - \ + - \ + - +add {base::operator^=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator=} \ + {base (base * const, const base &)} \ + - \ + - \ + - +add {base::operator()} \ + {void (const base * const)} \ + - \ + - \ + - +add {base::operator[]} \ + {int (const base * const, int)} \ + - \ + - \ + - +add {base::operator new} \ + {void *(size_t)} \ + - \ + - \ + - +add {base::operator delete} \ + {void (void *)} \ + - \ + - \ + - +add {base::operator new[]} \ + {void *(size_t)} \ + - \ + - \ + - +add {base::operator delete[]} \ + {void (void *)} \ + - \ + - \ + - +add {base::operator char*} \ + {char *(const base * const)} \ + - \ + - \ + - +add {base::operator fluff*} \ + {fluff *(const base * const)} \ + - \ + - \ + - +add {base::operator fluff**} \ + {fluff **(const base * const)} \ + - \ + - \ + - +add {base::operator int} \ + {int (const base * const)} \ + - \ + - \ + - + +# Templates +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + - \ + - +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + - \ + - +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + - \ + - +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + - \ + - +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + - \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {flubber} \ + {void (void)} \ + - \ + flubber \ + - +add {tclass::do_something} \ + {void (tclass * const)} \ + - \ + {tclass::do_something} \ + - +add {policy1::policy} \ + {void (policy > * const, int)} \ + {policy >::policy} \ + {policy::policy} \ + - +add {policy2::policy} \ + {void (policy > * const, int)} \ + {policy >::policy} \ + {policy::policy} \ + - +add {policy3::policy} \ + {void (policy > * const, int)} \ + {policy >::policy} \ + {policy::policy} \ + - +add {policy4::policy} \ + {void (policy > * const, int)} \ + {policy >::policy} \ + {policy::policy} \ + - +add {policy1::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policy2::function} \ + {void (void)} \ + {operation_2::function} \ + {operation_2::function} \ + - +add {policy3::function} \ + {void (void)} \ + {operation_3::function} \ + {operation_3::function} \ + - +add {policy4::function} \ + {void (void)} \ + {operation_4::function} \ + {operation_4::function} \ + - +add {policyd >::policyd} \ + {void (policyd > * const, int)} \ + - \ + {policyd::policyd} \ + - +add {policyd1::policyd} \ + {void (policyd > * const, int)} \ + {policyd >::policyd} \ + {policyd::policyd} \ + - +add {policyd >::~policyd} \ + {void (policyd > * const)} \ + - \ + {policyd::~policyd} \ + - +add {policyd1::~policyd} \ + {void (policyd > * const)} \ + {policyd >::~policyd} \ + {policyd::~policyd} \ + - +add {policyd >::policyd} \ + {void (policyd > * const, long)} \ + - \ + {policyd::policyd} \ + - +add {policyd2::policyd} \ + {void (policyd > * const, long)} \ + {policyd >::policyd} \ + {policyd::policyd} \ + - +add {policyd >::~policyd} \ + {void (policyd > * const)} \ + - \ + {policyd::~policyd} \ + - +add {policyd2::~policyd} \ + {void (policyd > * const)} \ + {policyd >::~policyd} \ + {policyd::~policyd} \ + - +add {policyd >::policyd} \ + {void (policyd > * const, char)} \ + - \ + {policyd::policyd} \ + - +add {policyd3::policyd} \ + {void (policyd > * const, char)} \ + {policyd >::policyd} \ + {policyd::policyd} \ + - +add {policyd >::~policyd} \ + {void (policyd > * const)} \ + - \ + {policyd::~policyd} \ + - +add {policyd3::~policyd} \ + {void (policyd > * const)} \ + {policyd >::~policyd} \ + {policyd::~policyd} \ + - +add {policyd >::policyd} \ + {void (policyd > * const, base)} \ + - \ + {policyd::policyd} \ + - +add {policyd4::policyd} \ + {void (policyd > * const, base)} \ + {policyd >::policyd} \ + {policyd::policyd} \ + - +add {policyd >::~policyd} \ + {void (policyd > * const)} \ + - \ + {policyd::~policyd} \ + - +add {policyd4::~policyd} \ + {void (policyd > * const)} \ + {policyd >::~policyd} \ + {policyd::~policyd} \ + - +add {policyd, operation_1 > >::policyd} \ + {void (policyd, operation_1 > > * const, tclass)} \ + - \ + {policyd::policyd} \ + - +add {policyd5::policyd} \ + {void (policyd, operation_1 > > * const, tclass)} \ + {policyd, operation_1 > >::policyd} \ + {policyd::policyd} \ + - +add {policyd, operation_1 > >::~policyd} \ + {void (policyd, operation_1 > > * const)} \ + - \ + {policyd::~policyd} \ + - +add {policyd5::~policyd} \ + {void (policyd, operation_1 > > * const)} \ + {policyd, operation_1 > >::~policyd} \ + {policyd::~policyd} \ + - +add {policyd >::function} \ + {void (void)} \ + {operation_1::function}\ + {operation_1::function} \ + - +add {policyd1::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd2::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd >::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd3::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd >::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd4::function} \ + {void (void)} \ + {operation_1::function} \ + {operation_1::function} \ + - +add {policyd, operation_1 > >::function} \ + {void (void)} \ + {operation_1 >::function} \ + {operation_1::function} \ + - +add {policyd5::function} \ + {void (void)} \ + {operation_1 >::function} \ + {operation_1::function} \ + - +# The below test default template arguments +add {policyd::policyd} \ + {void (policyd > * const, int)} \ + - \ + {policyd::policyd} \ + - +add {policyd::policyd} \ + {void (policyd > * const, long)} \ + - \ + {policyd::policyd} \ + - +add {policyd::policyd} \ + {void (policyd > * const, char)} \ + - \ + {policyd::policyd} \ + - +add {policyd::policyd} \ + {void (policyd > * const, base)} \ + - \ + {policyd::policyd} \ + - +add {policyd >::policyd} \ + {void (policyd >, operation_1 > > * const, int)} \ + - \ + {policyd::policyd} \ + - + +# Start the test +if {$tracelevel} { + strace $tracelevel +} + +if {[skip_cplus_tests]} { continue } + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +set testfile "realcpp" +set srcfile "${testfile}.cc" +set binfile [file join $objdir $subdir $testfile] + +if {[gdb_compile [file join $srcdir $subdir $srcfile] $binfile \ + executable {debug c++}] != "" } { + untested "$testfile.exp" + return -1 +} + +if {[get_compiler_info $binfile "c++"]} { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir [file join $srcdir $subdir] +gdb_load $binfile + +# Set the listsize to one. This will help with testing "list". +gdb_test "set listsize 1" + +# "print METHOD" +foreach name [get_functions print] { + gdb_test "print $name" [get $name print] "print $name" +} + +# "list METHOD" +foreach name [get_functions list] { + gdb_test "list $name" [get $name list] "list $name" +} + +# Running to breakpoint -- use any function we can "list" +foreach name [get_functions list] { + # Skip "main", since test_breakpoint uses it + if {[string compare $name "main"] != 0} { + test_breakpoint $name + } +} + +# "info func METHOD" +if {false} { +foreach name [get_functions "info_func"] { + regsub -all {\*} $name {\*} n + regsub -all {\^} $n {\^} n + regsub -all {\]} $n {\]} n + regsub -all {\[} $n {\[} n + gdb_test "info func $n" [get $name info_func] "info func $name" +} +} + +# What of these is not covered by above? +# operator-specific tests ('p a + b', 'print cout << "hello"', etc) +# overloaded operators & ctors +# operator names with spaces in them (other than delete and new) +# ptype of classes/templates +# backtraces +# printing data members +# catching, throwing exceptions +# STL (esp containers and iterators) +# inheritance tests +# completion scoping + +gdb_exit +return 0 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/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-empty-namespace.S b/gdb/testsuite/gdb.dwarf2/dw2-empty-namespace.S new file mode 100644 index 0000000..7b03ff1 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-empty-namespace.S @@ -0,0 +1,108 @@ +/* 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 G++ 4.1 producing DW_TAG_namespace with DW_AT_name "::". */ + + .data +var: .4byte 1 + + .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 "file1.txt\0" /* DW_AT_name */ + .ascii "GNU C 3.3.3\0" /* DW_AT_producer */ + .byte 4 /* DW_LANG_C_plus_plus (C++) */ + +.Ltype_int: + .uleb128 2 /* Abbrev: DW_TAG_base_type */ + .ascii "int\0" /* DW_AT_name */ + .byte 4 /* DW_AT_byte_size */ + .byte 5 /* DW_AT_encoding */ + + .uleb128 3 /* Abbrev: DW_TAG_namespace */ + .ascii "::\0" /* DW_AT_name */ + + .uleb128 7 /* Abbrev: DW_TAG_variable (location) */ + .ascii "var\0" /* DW_AT_name */ + .byte 2f - 1f /* DW_AT_location */ +1: .byte 3 /* DW_OP_addr */ + .4byte var /* */ +2: .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ + + .byte 0 /* End of children of DW_TAG_namespace */ + + .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 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 */ + + .uleb128 3 /* Abbrev code */ + .uleb128 0x39 /* DW_TAG_namespace */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 7 /* Abbrev code (location) */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x2 /* DW_AT_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-empty-namespace.exp b/gdb/testsuite/gdb.dwarf2/dw2-empty-namespace.exp new file mode 100644 index 0000000..1a8da16 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-empty-namespace.exp @@ -0,0 +1,43 @@ +# 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 G++ 4.1 producing DW_TAG_namespace with DW_AT_name "::". + +# 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-empty-namespace" +set srcfile ${testfile}.S +set executable ${testfile}.x + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${executable}" object {nodebug}] != "" } { + return -1 +} + +clean_restart $executable + +# `p var' below can work without identified DWARF DIE just based on its ELF symbol. +# Catch it here as `type = '. +gdb_test "ptype var" "type = int" + +gdb_test "p var" " = 1" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.c b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c new file mode 100644 index 0000000..1f02d90 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c @@ -0,0 +1,42 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + +/* The function `func1' traced into must have debug info on offset > 0; + (DW_UNSND (attr)). This is the reason of `func0' existence. */ + +void +func0(int a, int b) +{ +} + +/* `func1' being traced into must have some arguments to dump. */ + +void +func1(int a, int b) +{ + func0 (a,b); +} + +int +main(void) +{ + func1 (1, 2); + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp new file mode 100644 index 0000000..1c6e84a --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp @@ -0,0 +1,79 @@ +# Copyright 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Minimal DWARF-2 unit test + +# This test can only be run on targets which support DWARF-2. +# For now pick a sampling of likely targets. +if {![istarget *-*-linux*] + && ![istarget *-*-gnu*] + && ![istarget *-*-elf*] + && ![istarget *-*-openbsd*] + && ![istarget arm-*-eabi*] + && ![istarget powerpc-*-eabi*]} { + return 0 +} + +set testfile "dw2-stripped" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile}.x + +remote_exec build "rm -f ${binfile}" + +# get the value of gcc_compiled +if [get_compiler_info ${binfile}] { + return -1 +} + +# This test can only be run on gcc as we use additional_flags=FIXME +if {$gcc_compiled == 0} { + return 0 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-ggdb3}] != "" } { + return -1 +} + +remote_exec build "objcopy -R .debug_loc ${binfile}" +set strip_output [remote_exec build "objdump -h ${binfile}"] + +set test "stripping test file preservation" +if [ regexp ".debug_info " $strip_output] { + pass "$test (.debug_info preserved)" +} else { + fail "$test (.debug_info got also stripped)" +} + +set test "stripping test file functionality" +if [ regexp ".debug_loc " $strip_output] { + fail "$test (.debug_loc still present)" +} else { + pass "$test (.debug_loc stripped)" +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# For C programs, "start" should stop in main(). + +gdb_test "start" \ + ".*main \\(\\) at .*" \ + "start" +gdb_test "step" \ + "func.* \\(.*\\) at .*" \ + "step" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S new file mode 100644 index 0000000..5fcdd84 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S @@ -0,0 +1,83 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Debug information */ + + .section .debug_info +.Lcu1_begin: + /* CU header */ + .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */ +.Lcu1_start: + .2byte 2 /* DWARF Version */ + .4byte .Labbrev1_begin /* Offset into abbrev section */ + .byte 4 /* Pointer size */ + + /* CU die */ + .uleb128 1 /* Abbrev: DW_TAG_compile_unit */ + .ascii "dw2-struct-member-data-location.c\0" /* DW_AT_name */ + .ascii "GNU C 4.3.2\0" /* DW_AT_producer */ + .byte 1 /* DW_AT_language (C) */ + +.Ltype_uchar: + .uleb128 2 /* Abbrev: DW_TAG_structure_type */ + .ascii "some_struct\0" /* DW_AT_name */ + + .uleb128 3 /* Abbrev: DW_TAG_member */ + .ascii "field\0" /* DW_AT_name */ + .byte 0 /* DW_AT_data_member_location */ + + .byte 0 /* End of children of some_struct */ + + .byte 0 /* End of children of CU */ + +.Lcu1_end: + +/* Abbrev table */ + .section .debug_abbrev +.Labbrev1_begin: + .uleb128 1 /* Abbrev code */ + .uleb128 0x11 /* DW_TAG_compile_unit */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x25 /* DW_AT_producer */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x13 /* DW_AT_language */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 2 /* Abbrev code */ + .uleb128 0x13 /* DW_TAG_structure_type */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 3 /* Abbrev code */ + .uleb128 0x0d /* DW_TAG_member */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x38 /* DW_AT_data_member_location */ + .uleb128 0x0b /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp new file mode 100644 index 0000000..c41151c --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp @@ -0,0 +1,37 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This test can only be run on targets which support DWARF-2 and use gas. +# For now pick a sampling of likely targets. +if {![istarget *-*-linux*] + && ![istarget *-*-gnu*] + && ![istarget *-*-elf*] + && ![istarget *-*-openbsd*] + && ![istarget arm-*-eabi*] + && ![istarget powerpc-*-eabi*]} { + return 0 +} + +set testfile "dw2-struct-member-data-location" +set srcfile ${testfile}.S +set binfile ${testfile}.x + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${binfile}" object {nodebug}] != "" } { + return -1 +} + +clean_restart $binfile + +gdb_test "ptype struct some_struct" "type = struct some_struct {\[\r\n \t\]*void field;\[\r\n \t\]*}" diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.exp b/gdb/testsuite/gdb.fortran/dwarf-stride.exp new file mode 100644 index 0000000..cd3486b --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dwarf-stride.exp @@ -0,0 +1,42 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# This file is part of the gdb testsuite. Array element stride must not be +# specified in the number of elements but in a number of bytes instead. +# Original problem: +# (gdb) p c40pt(1) +# $1 = '0-hello', ' ' +# (gdb) p c40pt(2) +# warning: Fortran array stride not divisible by the element size + +set testfile dwarf-stride +set srcfile ${testfile}.f90 + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f77}] } { + return -1 +} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "break-here"] +gdb_continue_to_breakpoint "break-here" ".*break-here.*" +gdb_test "p c40pt(1)" " = '0-hello.*" +gdb_test "p c40pt(2)" " = '1-hello.*" diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.f90 b/gdb/testsuite/gdb.fortran/dwarf-stride.f90 new file mode 100644 index 0000000..e492b3a --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dwarf-stride.f90 @@ -0,0 +1,40 @@ +! Copyright 2009 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! File written by Alan Matsuoka. + +program repro + + type small_stride + character*40 long_string + integer small_pad + end type small_stride + + type(small_stride), dimension (20), target :: unpleasant + character*40, pointer, dimension(:):: c40pt + + integer i + + do i = 0,19 + unpleasant(i+1)%small_pad = i+1 + unpleasant(i+1)%long_string = char (ichar('0') + i) // '-hello' + end do + + c40pt => unpleasant%long_string + + print *, c40pt ! break-here + +end program repro diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp new file mode 100644 index 0000000..0ccebe0 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.exp @@ -0,0 +1,145 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# This file is part of the gdb testsuite. It contains tests for dynamically +# allocated Fortran arrays. +# It depends on the GCC dynamic Fortran arrays DWARF support: +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244 + +set testfile "dynamic" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "varx-init"] +gdb_continue_to_breakpoint "varx-init" +gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx unallocated" +gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx unallocated" +gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) unallocated" +gdb_test "p varx(1,5,17)=1" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17)=1 unallocated" +gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) unallocated" + +gdb_breakpoint [gdb_get_line_number "varx-allocated"] +gdb_continue_to_breakpoint "varx-allocated" +# $1 = (( ( 0, 0, 0, 0, 0, 0) ( 0, 0, 0, 0, 0, 0) --- , 0) ) ( ( 0, 0, ...) ...) ...) +gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx allocated" +# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. +gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varx allocated" + +gdb_breakpoint [gdb_get_line_number "varx-filled"] +gdb_continue_to_breakpoint "varx-filled" +gdb_test "p varx(2, 5, 17)" "\\$\[0-9\]* = 6" +gdb_test "p varx(1, 5, 17)" "\\$\[0-9\]* = 7" +gdb_test "p varx(2, 6, 18)" "\\$\[0-9\]* = 8" +gdb_test "p varx(6, 15, 28)" "\\$\[0-9\]* = 9" +# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. +gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv unassociated" +gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv unassociated" + +gdb_breakpoint [gdb_get_line_number "varv-associated"] +gdb_continue_to_breakpoint "varv-associated" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated" +# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. +gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated" +gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated" +# Intel Fortran Compiler 10.1.008 uses the pointer type. +gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated" + +gdb_breakpoint [gdb_get_line_number "varv-filled"] +gdb_continue_to_breakpoint "varv-filled" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled" + +gdb_breakpoint [gdb_get_line_number "varv-deassociated"] +gdb_continue_to_breakpoint "varv-deassociated" +# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. +gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated" +gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated" +gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." +gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." + +gdb_breakpoint [gdb_get_line_number "varx-deallocated"] +gdb_continue_to_breakpoint "varx-deallocated" +gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated" +gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated" +gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated" +gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated" + +gdb_breakpoint [gdb_get_line_number "vary-passed"] +gdb_continue_to_breakpoint "vary-passed" +# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...) +gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "vary-filled"] +gdb_continue_to_breakpoint "vary-filled" +gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)" +gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8" +gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9" +gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10" +# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "varw-almostfilled"] +gdb_continue_to_breakpoint "varw-almostfilled" +gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)" +gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1" +# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled" +# "up" works with GCC but other Fortran compilers may copy the values into the +# outer function only on the exit of the inner function. +# We need both variants as depending on the arch we optionally may still be +# executing the caller line or not after `finish'. +gdb_test "finish" ".*(call bar \\(y, x\\)|call foo \\(x, z\\(2:6, 4:7, 6:8\\)\\))" +gdb_test "p z(2,4,5)" "\\$\[0-9\]* = 3" +gdb_test "p z(2,4,6)" "\\$\[0-9\]* = 6" +gdb_test "p z(2,4,7)" "\\$\[0-9\]* = 5" +gdb_test "p z(4,4,6)" "\\$\[0-9\]* = 1" + +gdb_breakpoint [gdb_get_line_number "varz-almostfilled"] +gdb_continue_to_breakpoint "varz-almostfilled" +# GCC uses the pointer type here, Intel Fortran Compiler 10.1.008 does not. +gdb_test "ptype varz" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(\\*\\)\\)?" +# Intel Fortran Compiler 10.1.008 has a bug here - (2:11,7:7) +# as it produces DW_AT_lower_bound == DW_AT_upper_bound == 7. +gdb_test "ptype vart" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(2:11,7:\\*\\)\\)?" +gdb_test "p varz" "\\$\[0-9\]* = \\(\\)" +gdb_test "p vart" "\\$\[0-9\]* = \\(\\)" +gdb_test "p varz(3)" "\\$\[0-9\]* = 4" +# maps to foo::vary(1,1) +gdb_test "p vart(2,7)" "\\$\[0-9\]* = 8" +# maps to foo::vary(2,2) +gdb_test "p vart(3,8)" "\\$\[0-9\]* = 9" +# maps to foo::vary(1,3) +gdb_test "p vart(2,9)" "\\$\[0-9\]* = 10" diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90 new file mode 100644 index 0000000..0f43564 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.f90 @@ -0,0 +1,98 @@ +! Copyright 2007 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +subroutine baz + real, target, allocatable :: varx (:, :, :) + real, pointer :: varv (:, :, :) + real, target :: varu (1, 2, 3) + logical :: l + allocate (varx (1:6, 5:15, 17:28)) ! varx-init + l = allocated (varx) + varx(:, :, :) = 6 ! varx-allocated + varx(1, 5, 17) = 7 + varx(2, 6, 18) = 8 + varx(6, 15, 28) = 9 + varv => varx ! varx-filled + l = associated (varv) + varv(3, 7, 19) = 10 ! varv-associated + varv => null () ! varv-filled + l = associated (varv) + deallocate (varx) ! varv-deassociated + l = allocated (varx) + varu(:, :, :) = 10 ! varx-deallocated + allocate (varv (1:6, 5:15, 17:28)) + l = associated (varv) + varv(:, :, :) = 6 + varv(1, 5, 17) = 7 + varv(2, 6, 18) = 8 + varv(6, 15, 28) = 9 + deallocate (varv) + l = associated (varv) + varv => varu + varv(1, 1, 1) = 6 + varv(1, 2, 3) = 7 + l = associated (varv) +end subroutine baz +subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + vary(:, :) = 4 ! vary-passed + vary(1, 1) = 8 + vary(2, 2) = 9 + vary(1, 3) = 10 + varw(:, :, :) = 5 ! vary-filled + varw(1, 1, 1) = 6 + varw(2, 2, 2) = 7 ! varw-almostfilled +end subroutine foo +subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + varz(1:3) = 4 + varz(2) = 5 ! varz-almostfilled + vart(2,7) = vart(2,7) +end subroutine bar +program test + interface + subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + end subroutine + end interface + interface + subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + end subroutine + end interface + real :: x (10, 10), y (5), z(8, 8, 8) + x(:,:) = 1 + y(:) = 2 + z(:,:,:) = 3 + call baz + call foo (x, z(2:6, 4:7, 6:8)) + call bar (y, x) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (1, 3) .ne. 10) call abort + if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort + if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort + call foo (transpose (x), z) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (3, 1) .ne. 10) call abort +end diff --git a/gdb/testsuite/gdb.fortran/library-module-lib.f90 b/gdb/testsuite/gdb.fortran/library-module-lib.f90 new file mode 100644 index 0000000..6369d34 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/library-module-lib.f90 @@ -0,0 +1,28 @@ +! Copyright 2009 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program. If not, see . + +module lib + integer :: var_i = 1 +contains + subroutine lib_func + if (var_i .ne. 1) call abort + var_i = 2 + end subroutine lib_func +end module lib + +module libmany + integer :: var_j = 3 + integer :: var_k = 4 +end module libmany diff --git a/gdb/testsuite/gdb.fortran/library-module-main.f90 b/gdb/testsuite/gdb.fortran/library-module-main.f90 new file mode 100644 index 0000000..de63a65 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/library-module-main.f90 @@ -0,0 +1,23 @@ +! Copyright 2009 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program. If not, see . + + use lib + use libmany, only: var_j + if (var_i .ne. 1) call abort + call lib_func + if (var_i .ne. 2) call abort + if (var_j .ne. 3) call abort + var_i = var_i ! i-is-2 +end diff --git a/gdb/testsuite/gdb.fortran/library-module.exp b/gdb/testsuite/gdb.fortran/library-module.exp new file mode 100644 index 0000000..4b4ea4c --- /dev/null +++ b/gdb/testsuite/gdb.fortran/library-module.exp @@ -0,0 +1,53 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testfile "library-module" +set srcfile ${testfile}-main.f90 +set srclibfile ${testfile}-lib.f90 +set libfile ${testfile}-lib.so +set binfile ${testfile} + +# Required for -fPIC by gdb_compile_shlib. +if [get_compiler_info not-used] { + warning "Could not get compiler info" + return -1 +} + +if { [gdb_compile_shlib "${srcdir}/${subdir}/${srclibfile}" $objdir/$subdir/$libfile {debug f77}] != "" } { + untested "Couldn't compile ${srclibfile}" + return -1 +} + +# prepare_for_testing cannot be used as linking with $libfile cannot be passed +# just for the linking phase (and not the source compilation phase). And any +# warnings on ignored $libfile abort the process. + +if { [gdb_compile [list $srcdir/$subdir/$srcfile $objdir/$subdir/$libfile] $objdir/$subdir/$binfile executable {debug f77}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +clean_restart $binfile + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "i-is-2"] +gdb_continue_to_breakpoint "i-is-2" ".*i-is-2.*" +gdb_test "print var_i" " = 2" +gdb_test "print var_j" " = 3" +gdb_test "print var_k" "No symbol \"var_k\" in current context\\." diff --git a/gdb/testsuite/gdb.fortran/module.exp b/gdb/testsuite/gdb.fortran/module.exp index 0acce4f..b952162 100644 --- a/gdb/testsuite/gdb.fortran/module.exp +++ b/gdb/testsuite/gdb.fortran/module.exp @@ -15,21 +15,31 @@ set testfile "module" set srcfile ${testfile}.f90 -set binfile ${objdir}/${subdir}/${testfile} -if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { - untested "Couldn't compile ${srcfile}" +if { [prepare_for_testing $testfile.exp $testfile $srcfile {debug f77}] } { return -1 } -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} - if ![runto MAIN__] then { perror "couldn't run to breakpoint MAIN__" continue } -gdb_test "print i" " = 42" +# Do not use simple single-letter names as GDB would pick up for expectedly +# nonexisting symbols some static variables from system libraries debuginfos. + +gdb_breakpoint [gdb_get_line_number "i-is-1"] +gdb_continue_to_breakpoint "i-is-1" ".*i-is-1.*" +gdb_test "print var_i" " = 1" "print var_i value 1" + +gdb_breakpoint [gdb_get_line_number "i-is-2"] +gdb_continue_to_breakpoint "i-is-2" ".*i-is-2.*" +gdb_test "print var_i" " = 2" "print var_i value 2" + +gdb_breakpoint [gdb_get_line_number "a-b-c-d"] +gdb_continue_to_breakpoint "a-b-c-d" ".*a-b-c-d.*" +gdb_test "print var_a" "No symbol \"var_a\" in current context\\." +gdb_test "print var_b" " = 11" +gdb_test "print var_c" "No symbol \"var_c\" in current context\\." +gdb_test "print var_d" " = 12" +gdb_test "print var_i" " = 14" "print var_i value 14" diff --git a/gdb/testsuite/gdb.fortran/module.f90 b/gdb/testsuite/gdb.fortran/module.f90 index 81ef376..fb6eccd 100644 --- a/gdb/testsuite/gdb.fortran/module.f90 +++ b/gdb/testsuite/gdb.fortran/module.f90 @@ -13,10 +13,37 @@ ! You should have received a copy of the GNU General Public License ! along with this program. If not, see . -module mod - integer :: i = 42 -end module mod +module mod1 + integer :: var_i = 1 +end module mod1 - use mod - print *, i +module mod2 + integer :: var_i = 2 +end module mod2 + +module modmany + integer :: var_a = 10, var_b = 11, var_c = 12, var_i = 14 +end module modmany + + subroutine sub1 + use mod1 + if (var_i .ne. 1) call abort + var_i = var_i ! i-is-1 + end + + subroutine sub2 + use mod2 + if (var_i .ne. 2) call abort + var_i = var_i ! i-is-2 + end + + use modmany, only: var_b, var_d => var_c, var_i + + call sub1 + call sub2 + + if (var_b .ne. 11) call abort + if (var_d .ne. 12) call abort + if (var_i .ne. 14) call abort + var_b = var_b ! a-b-c-d end diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp new file mode 100644 index 0000000..b1120c3 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.exp @@ -0,0 +1,59 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# This file is part of the gdb testsuite. It contains tests for Fortran +# strings with dynamic length. + +set testfile "string" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "var-init"] +gdb_continue_to_breakpoint "var-init" +gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)" +gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)" +gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)" +gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)" +gdb_test "ptype *e" "Attempt to take contents of a non-pointer value." +gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)" +gdb_test "p c" "\\$\[0-9\]* = 'c'" +gdb_test "p d" "\\$\[0-9\]* = 'd '" +gdb_test "p e" "\\$\[0-9\]* = 'g '" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)" +gdb_test "p *e" "Attempt to take contents of a non-pointer value." +gdb_test "p *f" "Attempt to take contents of a non-pointer value." + +gdb_breakpoint [gdb_get_line_number "var-finish"] +gdb_continue_to_breakpoint "var-finish" +gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set" diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90 new file mode 100644 index 0000000..226dc5d --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.f90 @@ -0,0 +1,37 @@ +! Copyright 2008 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + +subroutine foo (e, f) + character (len=1) :: c + character (len=8) :: d + character (len=*) :: e + character (len=*) :: f (1:7, 8:10) + c = 'c' + d = 'd' + e = 'e' ! var-init + f = 'f' + f(1,9) = 'f2' + c = 'c' ! var-finish +end subroutine foo + character (len=4) :: g, h (1:7, 8:10) + g = 'g' + h = 'h' + call foo (g, h) +end diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp index 9e787f0..5ca15d5 100644 --- a/gdb/testsuite/gdb.gdb/selftest.exp +++ b/gdb/testsuite/gdb.gdb/selftest.exp @@ -95,6 +95,10 @@ proc do_steps_and_nexts {} { set description "step over ttyarg initialization" set command "step" } + -re ".*python_script = 0.*$gdb_prompt $" { + set description "step over python_script initialization" + set command "step" + } -re ".*time_at_startup = get_run_time.*$gdb_prompt $" { set description "next over get_run_time and everything it calls" set command "next" diff --git a/gdb/testsuite/gdb.java/jnpe.exp b/gdb/testsuite/gdb.java/jnpe.exp new file mode 100644 index 0000000..e71391e --- /dev/null +++ b/gdb/testsuite/gdb.java/jnpe.exp @@ -0,0 +1,77 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if $tracelevel then { + strace $tracelevel +} + +load_lib "java.exp" + +set testfile "jnpe" +set srcfile ${testfile}.java +set binfile ${objdir}/${subdir}/${testfile} +if { [compile_java_from_source ${srcdir}/$subdir/${srcfile} ${binfile} "-g"] != "" } { + untested "Couldn't compile ${srcdir}/$subdir/${srcfile}" + return -1 +} + +set prms_id 0 +set bug_id 0 + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set line [gdb_get_line_number "break here" $testfile.java] +gdb_test "break $testfile.java:$line" "" + +gdb_test "run" \ + "// break here.*" \ + "run java next-over-throw" + +# See whether we have the needed unwinder hooks. +set ok 1 +gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook in java" { + -re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" { + pass "check for unwinder hook in java" + } + -re "No symbol .* in current context.?\r\n$gdb_prompt $" { + # Pass the test so we don't get bogus fails in the results. + setup_xfail *-*-* + fail "check for unwinder hook in java" + set ok 0 + } +} +if {!$ok} { + untested jnpe.exp + return -1 +} + +gdb_test "handle SIGSEGV nostop noprint" \ + "SIGSEGV.*fault" \ + "disable SIGSEGV for next-over-NPE" + +# The line where we stop differ according to gcj; check just we did not already +# execute the catch point. + +gdb_test "next" \ + "" \ + "next over NPE" + +gdb_breakpoint [gdb_get_line_number "catch point"] +gdb_continue_to_breakpoint "catch point" ".*// catch point.*" diff --git a/gdb/testsuite/gdb.java/jnpe.java b/gdb/testsuite/gdb.java/jnpe.java new file mode 100644 index 0000000..3524830 --- /dev/null +++ b/gdb/testsuite/gdb.java/jnpe.java @@ -0,0 +1,38 @@ +// Test next-over-NPE. +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +public class jnpe +{ + public static String npe () + { + return ((Object) null).toString(); + } + + public static void main (String[] args) + { + try + { + System.out.println (npe ()); // break here + } + catch (NullPointerException n) + { + System.out.println ("success"); // catch point + } + } +} diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c new file mode 100644 index 0000000..729f457 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register-func.c @@ -0,0 +1,22 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +int +func (int *arr) +{ + return arr[0]; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c new file mode 100644 index 0000000..3090e7e --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.c @@ -0,0 +1,28 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +extern int func (int *arr); + +int +main (void) +{ + int arr[] = { 42 }; + + func (arr); + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp new file mode 100644 index 0000000..f2de718 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.exp @@ -0,0 +1,33 @@ +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# This file is part of the gdb testsuite. + +if { [prepare_for_testing array-from-register.exp "array-from-register" \ + {array-from-register.c array-from-register-func.c} \ + {debug optimize=-O2}] } { + return -1 +} + +if ![runto func] then { + return -1 +} + +gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+" + +# Seen regression: +# Address requested for identifier "arr" which is in register $rdi +gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42" diff --git a/gdb/testsuite/gdb.opt/fortran-string.exp b/gdb/testsuite/gdb.opt/fortran-string.exp new file mode 100644 index 0000000..f997eec --- /dev/null +++ b/gdb/testsuite/gdb.opt/fortran-string.exp @@ -0,0 +1,41 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil . + +# Test GDB can cope with Fortran strings having their length present in a CPU +# register. With -O0 the string length is passed on the stack. To make this +# test meaningful the follow assertion should pass. It is not being checked +# here as the "_s" symbol is compiler dependent: +# (gdb) info address _s +# Symbol "_s" is a variable in register XX. + +set test fortran-string +set srcfile ${test}.f90 +if { [prepare_for_testing ${test}.exp ${test} ${srcfile} {debug f77 additional_flags=-O2}] } { + return -1 +} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "s = s"] +gdb_continue_to_breakpoint "s = s" +gdb_test "frame" ".*s='foo'.*" +gdb_test "ptype s" "type = character\\*3" +gdb_test "p s" "\\$\[0-9\]* = 'foo'" diff --git a/gdb/testsuite/gdb.opt/fortran-string.f90 b/gdb/testsuite/gdb.opt/fortran-string.f90 new file mode 100644 index 0000000..e48d520 --- /dev/null +++ b/gdb/testsuite/gdb.opt/fortran-string.f90 @@ -0,0 +1,28 @@ +! Copyright 2009 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek . +! Modified for the GDB testcase by Jan Kratochvil . + + subroutine f(s) + character*(*) s + s = s + end + + program main + call f ('foo') + end diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp index 2a3ed0d..ff5de33 100644 --- a/gdb/testsuite/gdb.python/py-cmd.exp +++ b/gdb/testsuite/gdb.python/py-cmd.exp @@ -20,36 +20,15 @@ if $tracelevel then { strace $tracelevel } -# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... -# Run a test named NAME, consisting of multiple lines of input. -# After each input line INPUT, search for result line RESULT. -# Succeed if all results are seen; fail otherwise. -proc gdb_py_test_multiple {name args} { - global gdb_prompt - foreach {input result} $args { - if {[gdb_test_multiple $input "$name - $input" { - -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { - pass "$name - $input" - } - }]} { - return 1 - } - } - return 0 -} - # Start with a fresh gdb. gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} +if ![python_supported] then { + unsupported "python support is disabled" + return -1 } # Test a simple command. diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp index 86fe660..4c7295f 100644 --- a/gdb/testsuite/gdb.python/py-frame.exp +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -20,40 +20,28 @@ if $tracelevel then { strace $tracelevel } +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +if ![python_supported] then { + unsupported "python support is disabled" + return -1 +} + set testfile "py-frame" set srcfile ${testfile}.c set binfile ${objdir}/${subdir}/${testfile} + if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { untested "Couldn't compile ${srcfile}" return -1 } -# Run a command in GDB, and report a failure if a Python exception is thrown. -# If report_pass is true, report a pass if no exception is thrown. -proc gdb_py_test_silent_cmd {cmd name report_pass} { - global gdb_prompt - - gdb_test_multiple $cmd $name { - -re "Traceback.*$gdb_prompt $" { fail $name } - -re "$gdb_prompt $" { if $report_pass { pass $name } } - } -} - -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - # The following tests require execution. if ![runto_main] then { @@ -65,19 +53,20 @@ gdb_breakpoint "f2" gdb_continue_to_breakpoint "breakpoint at f2" gdb_test "up" "" "" -gdb_py_test_silent_cmd "python f1 = gdb.selected_frame ()" "get second frame" 0 -gdb_py_test_silent_cmd "python f0 = f1.newer ()" "get first frame" 0 +gdb_py_test_silent_cmd "python frames = gdb.selected_thread ().frames ()" "get frames list" 1 +gdb_test "python print frames" "\\(, , \\)" "verify frames list" +gdb_py_test_silent_cmd "python f0 = frames\[0\]" "get first frame" 0 +gdb_py_test_silent_cmd "python f1 = frames\[1\]" "get second frame" 0 gdb_test "python print 'result =', f0 == f1" " = False" "test equality comparison (false)" gdb_test "python print 'result =', f0 == f0" " = True" "test equality comparison (true)" -gdb_test "python print 'result =', f0 != f1" " = True" "test inequality comparison (true)" -gdb_test "python print 'result =', f0 != f0" " = False" "test inequality comparison (false)" gdb_test "python print 'result =', f0.is_valid ()" " = True" "test Frame.is_valid" gdb_test "python print 'result =', f0.name ()" " = f2" "test Frame.name" gdb_test "python print 'result =', f0.type () == gdb.NORMAL_FRAME" " = True" "test Frame.type" gdb_test "python print 'result =', f0.unwind_stop_reason () == gdb.FRAME_UNWIND_NO_REASON" " = True" "test Frame.type" gdb_test "python print 'result =', gdb.frame_stop_reason_string (gdb.FRAME_UNWIND_INNER_ID)" " = previous frame inner to this frame \\(corrupt stack\\?\\)" "test gdb.frame_stop_reason_string" gdb_test "python print 'result =', f0.pc ()" " = \[0-9\]+" "test Frame.pc" +gdb_test "python print 'result =', f0.function ()" " = symbol for f2" "test Frame.function" gdb_test "python print 'result =', f0.older () == f1" " = True" "test Frame.older" gdb_test "python print 'result =', f1.newer () == f0" " = True" "test Frame.newer" gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_exist')" \ @@ -85,4 +74,7 @@ gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_ex "test Frame.read_var - error" gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" +gdb_test "python print 'result =', gdb.selected_thread ().newest_frame () == f0" " = True" "test gdb.newest_frame" gdb_test "python print 'result =', gdb.selected_frame () == f1" " = True" "test gdb.selected_frame" + +gdb_test "python print 'result =', f0.block ()" "" "test Frame.block" diff --git a/gdb/testsuite/gdb.python/py-function.exp b/gdb/testsuite/gdb.python/py-function.exp index 461295d..ea33596 100644 --- a/gdb/testsuite/gdb.python/py-function.exp +++ b/gdb/testsuite/gdb.python/py-function.exp @@ -20,36 +20,15 @@ if $tracelevel then { strace $tracelevel } -# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... -# Run a test named NAME, consisting of multiple lines of input. -# After each input line INPUT, search for result line RESULT. -# Succeed if all results are seen; fail otherwise. -proc gdb_py_test_multiple {name args} { - global gdb_prompt - foreach {input result} $args { - if {[gdb_test_multiple $input "$name - $input" { - -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { - pass "$name - $input" - } - }]} { - return 1 - } - } - return 0 -} - # Start with a fresh gdb. gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} +if ![python_supported] then { + unsupported "python support is disabled" + return -1 } gdb_py_test_multiple "input convenience function" \ diff --git a/gdb/testsuite/gdb.python/py-inferior.c b/gdb/testsuite/gdb.python/py-inferior.c new file mode 100644 index 0000000..0b48299 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-inferior.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#define CHUNK_SIZE 16000 /* same as findcmd.c's */ +#define BUF_SIZE (2 * CHUNK_SIZE) /* at least two chunks */ + +static int8_t int8_search_buf[100]; +static int16_t int16_search_buf[100]; +static int32_t int32_search_buf[100]; +static int64_t int64_search_buf[100]; + +static char *search_buf; +static int search_buf_size; + +static int x; + + +int f2 (int a) +{ + char *str = "hello, testsuite"; + + puts (str); /* Break here. */ + + return ++a; +} + +int f1 (int a, int b) +{ + return f2(a) + b; +} + +static void +init_bufs () +{ + search_buf_size = BUF_SIZE; + search_buf = malloc (search_buf_size); + if (search_buf == NULL) + exit (1); + memset (search_buf, 'x', search_buf_size); +} + +int main (int argc, char *argv[]) +{ + init_bufs (); + + return f1 (1, 2); +} diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp new file mode 100644 index 0000000..719b178 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-inferior.exp @@ -0,0 +1,201 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing inferiors to Python. + +if $tracelevel then { + strace $tracelevel +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +if ![python_supported] then { + unsupported "python support is disabled" + return -1 +} + +set testfile "py-inferior" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_load ${binfile} + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +runto [gdb_get_line_number "Break here."] + +# Test basic gdb.Inferior attributes and methods. + +gdb_py_test_silent_cmd "python inferiors = gdb.inferiors ()" "get inferiors list" 1 +gdb_test "python print inferiors" "\\(,\\)" "verify inferiors list" +gdb_py_test_silent_cmd "python i0 = inferiors\[0\]" "get first inferior" 0 + +gdb_test "python print 'result =', i0 == inferiors\[0\]" " = True" "test equality comparison (true)" +gdb_test "python print 'result =', i0.num" " = \[0-9\]+" "test Inferior.num" +gdb_test "python print 'result =', i0.pid" " = \[0-9\]+" "test Inferior.pid" +gdb_test "python print 'result =', i0.was_attached" " = False" "test Inferior.was_attached" +gdb_test "python print i0.threads ()" "\\(,\\)" "test Inferior.threads" + +# Test memory read and write operations. + +gdb_py_test_silent_cmd "python addr = gdb.selected_frame ().read_var ('str')" \ + "read str address" 0 +gdb_py_test_silent_cmd "python str = gdb.inferiors()\[0\].read_memory (addr, 5)" \ + "read str contents" 1 +gdb_py_test_silent_cmd "python str\[1\] = 'a'" "change str" 0 +gdb_py_test_silent_cmd "python gdb.inferiors()\[0\].write_memory (addr, str)" \ + "write str" 1 +gdb_test "print str" " = 0x\[\[:xdigit:\]\]+ \"hallo, testsuite\"" \ + "ensure str was changed in the inferior" + +# Test memory search. + +set hex_number {0x[0-9a-fA-F][0-9a-fA-F]*} +set dec_number {[0-9]+} +set history_prefix {[$][0-9]* = } +set newline {[\r\n]+} +set pattern_not_found "${newline}.]" +set one_pattern_found "${newline}.${dec_number}L]" +set two_patterns_found "${newline}.${dec_number}L, ${dec_number}L]" + +# Test string pattern. + +gdb_test "set *(int32_t*) &int8_search_buf\[10\] = 0x61616161" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int8_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address" "" "" +gdb_test "py length = search_buf.type.sizeof" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 'aaa')" \ + "${two_patterns_found}" "find string pattern" + +# Test not finding pattern because search range too small, with +# potential find at the edge of the range. + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3, 'aaaa')" \ + "${pattern_not_found}" "pattern not found at end of range" + +# Increase the search range by 1 and we should find the pattern. + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 10+3+1, \['a', 'a', 'a', 'a'\])" \ + "${one_pattern_found}" "pattern found at end of range" + +# Test max-count with size, with different parameter position + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], 1, 1)" \ + "${one_pattern_found}" "size = 1, max_count = 1" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], 1, 2)" \ + "${two_patterns_found}" "size = 1, max_count = 2, normal ordering" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], size = 1, max_count = 2)" \ + "${two_patterns_found}" "size = 1, max_count = 2, normal ordering, with keywords" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \[0x61, 0x61\], max_count = 2, size = 1)" \ + "${two_patterns_found}" "size = 1, max_count = 2, inverted ordering" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, \['a', 'a'\], max_count = 2)" \ + "${two_patterns_found}" "max_count = 2, with keyword" + +# Test 16-bit pattern. + +gdb_test "set int16_search_buf\[10\] = 0x1234" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int16_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address" "" "" +gdb_test "py length = search_buf.type.sizeof" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int16_t) 0x1234')" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x1234, 2)" \ + "${one_pattern_found}" "find 16-bit pattern, with python pattern" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 16-bit pattern, with value pattern" + +# Test 32-bit pattern. + +gdb_test "set int32_search_buf\[10\] = 0x12345678" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int32_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address" "" "" +gdb_test "py length = search_buf.type.sizeof" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int32_t) 0x12345678')" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x12345678, 4)" \ + "${one_pattern_found}" "find 32-bit pattern, with python pattern" +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 32-bit pattern, with value pattern" + +# Test 64-bit pattern. + +gdb_test "set int64_search_buf\[10\] = 0xfedcba9876543210LL" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('int64_search_buf')" "" "" +gdb_test "py start_addr = search_buf.address" "" "" +gdb_test "py length = search_buf.type.sizeof" "" "" +gdb_test "py pattern = gdb.parse_and_eval ('(int64_t) 0xfedcba9876543210LL')" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0xfedcba9876543210, 8)" \ + "${one_pattern_found}" "find 64-bit pattern, with python pattern" +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, pattern)" \ + "${one_pattern_found}" "find 64-bit pattern, with value pattern" + +# Test mixed-sized patterns. + +gdb_test "set *(int8_t*) &search_buf\[10\] = 0x62" "" "" +gdb_test "set *(int16_t*) &search_buf\[11\] = 0x6363" "" "" +gdb_test "set *(int32_t*) &search_buf\[13\] = 0x64646464" "" "" +gdb_test "py search_buf = gdb.selected_frame ().read_var ('search_buf')" "" "" +gdb_test "py start_addr = search_buf\[0\].address" "" "" +gdb_test "py pattern1 = gdb.parse_and_eval ('(int8_t) 0x62')" "" "" +gdb_test "py pattern2 = gdb.parse_and_eval ('(int16_t) 0x6363')" "" "" +gdb_test "py pattern3 = gdb.parse_and_eval ('(int32_t) 0x64646464')" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, 100, \[pattern1, pattern2, pattern3\])" \ + "${one_pattern_found}" "find mixed-sized pattern" + +# Test search spanning a large range, in the particular case of native +# targets, test the search spanning multiple chunks. +# Remote targets may implement the search differently. + +set CHUNK_SIZE 16000 ; + +gdb_test "set *(int32_t*) &search_buf\[0*${CHUNK_SIZE}+100\] = 0x12345678" "" "" +gdb_test "set *(int32_t*) &search_buf\[1*${CHUNK_SIZE}+100\] = 0x12345678" "" "" +gdb_test "py start_addr = gdb.selected_frame ().read_var ('search_buf')" "" "" +gdb_test "py length = gdb.selected_frame ().read_var ('search_buf_size')" "" "" + +gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0x12345678, 4)" \ + "${two_patterns_found}" "search spanning large range" + +# For native targets, test a pattern straddling a chunk boundary. + +if [isnative] { + gdb_test "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" "" "" + + gdb_test "py print gdb.inferiors()\[0\].search_memory (start_addr, length, 0xfdb97531, 4)" \ + "${one_pattern_found}" "find pattern straddling chunk boundary" +} diff --git a/gdb/testsuite/gdb.python/py-infthread.c b/gdb/testsuite/gdb.python/py-infthread.c new file mode 100644 index 0000000..22eb9f2 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-infthread.c @@ -0,0 +1,14 @@ +int f2 (int a) +{ + return ++a; +} + +int f1 (int a, int b) +{ + return f2(a) + b; +} + +int main (int argc, char *argv[]) +{ + return f1 (1, 2); +} diff --git a/gdb/testsuite/gdb.python/py-infthread.exp b/gdb/testsuite/gdb.python/py-infthread.exp new file mode 100644 index 0000000..e9d18b7 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-infthread.exp @@ -0,0 +1,58 @@ +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests the mechanism +# exposing inferior threads to Python. + +if $tracelevel then { + strace $tracelevel +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +if ![python_supported] then { + unsupported "python support is disabled" + return -1 +} + +set testfile "py-infthread" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_load ${binfile} + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +runto [gdb_get_line_number "Break here."] + +# Test basic gdb.Inferior attributes and methods. + +gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1 +gdb_test "python print t0" "\\" "verify InferiorThread object" +gdb_test "python print 'result =', t0.num" " = \[0-9\]+" "test Inferior.num" diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp index 2626895..cd0d7e7 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.exp +++ b/gdb/testsuite/gdb.python/py-prettyprint.exp @@ -27,12 +27,20 @@ set binfile ${objdir}/${subdir}/${testfile} # Start with a fresh gdb. gdb_exit gdb_start -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} +if ![python_supported] then { + unsupported "python support is disabled" + return -1 +} + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } } # Run a command in GDB, and report a failure if a Python exception is thrown. @@ -105,6 +113,8 @@ proc run_lang_tests {lang} { gdb_test "print estring" "\"embedded x\\\\201\\\\202\\\\203\\\\204\"" gdb_test "print c" " = container \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}" + gdb_test "print nullstr" "RuntimeError: Error reading string from inferior.*" + gdb_test "continue" "Program exited normally\." remote_file host delete ${remote_python_file} diff --git a/gdb/testsuite/gdb.python/py-template.exp b/gdb/testsuite/gdb.python/py-template.exp index 713ad5f..5d17b26 100644 --- a/gdb/testsuite/gdb.python/py-template.exp +++ b/gdb/testsuite/gdb.python/py-template.exp @@ -20,6 +20,17 @@ if $tracelevel then { strace $tracelevel } +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +if ![python_supported] then { + unsupported "python support is disabled" + return -1 +} + set testfile "py-template" set srcfile ${testfile}.cc set binfile ${objdir}/${subdir}/${testfile} @@ -29,20 +40,6 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \ return -1 } -# Start with a fresh gdb. - -gdb_exit -gdb_start -gdb_reinitialize_dir $srcdir/$subdir - -gdb_test_multiple "python print 23" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} -} - proc test_template_arg {type} { global testfile srcdir subdir srcfile binfile if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index aa4e519..f87277d 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -305,6 +305,15 @@ proc test_value_after_death {} { "print value's type" } +# Regression test for a cast failure. The bug was that if we cast a +# value to its own type, gdb could crash. This happened because we +# could end up double-freeing a struct value. +proc test_cast_regression {} { + gdb_test "python v = gdb.Value(5)" "" "create value for cast test" + gdb_test "python v = v.cast(v.type)" "" "cast value for cast test" + gdb_test "python print v" "5" "print value for cast test" +} + # Regression test for invalid subscript operations. The bug was that # the type of the value was not being checked before allowing a # subscript operation to proceed. @@ -390,16 +399,23 @@ proc test_parse_and_eval {} { gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir -gdb_load ${binfile} -gdb_test_multiple "python print 'hello, world!'" "verify python support" { - -re "not supported.*$gdb_prompt $" { - unsupported "python support is disabled" - return -1 - } - -re "$gdb_prompt $" {} +if ![python_supported] then { + unsupported "python support is disabled" + return -1 } +set testfile "py-value" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_load ${binfile} + test_value_creation test_value_numeric_ops test_value_boolean @@ -417,6 +433,7 @@ if ![runto_main] then { test_value_in_inferior test_lazy_strings test_value_after_death +test_cast_regression # The following test recompiles the binary to test either C or C++ # values. diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c b/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c new file mode 100644 index 0000000..4dc308b --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c @@ -0,0 +1,175 @@ +/* Test case for forgotten hw-watchpoints after fork()-off of a process. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + +static void +delay (void) +{ + int i = usleep (1000000 / 100); + assert (i == 0 || errno == EINTR); +} + +#if defined FOLLOW_PARENT + +static void +forkoff (int nr) +{ + pid_t child, pid_got; + int exit_code = 42 + nr; + int status, i; + + child = fork (); + switch (child) + { + case -1: + assert (0); + case 0: + printf ("child%d: %d\n", nr, (int) getpid ()); + /* Delay to get both the "child%d" and "parent%d" message printed without + a race breaking expect by its endless wait on `$gdb_prompt$': + Breakpoint 3, breakpoint () at ../../../gdb/testsuite/gdb.threads/watchpoint-fork.c:33 + 33 } + (gdb) parent2: 14223 */ + i = sleep (1); + assert (i == 0); + + /* We must not get caught here (against a forgotten breakpoint). */ + var++; + breakpoint (); + + _exit (exit_code); + default: + printf ("parent%d: %d\n", nr, (int) child); + /* Delay to get both the "child%d" and "parent%d" message printed, see + above. */ + i = sleep (1); + assert (i == 0); + + pid_got = wait (&status); + assert (pid_got == child); + assert (WIFEXITED (status)); + assert (WEXITSTATUS (status) == exit_code); + + /* We must get caught here (against a false watchpoint removal). */ + breakpoint (); + } +} + +#elif defined FOLLOW_CHILD + +static volatile int usr1_got; + +static void +handler_usr1 (int signo) +{ + usr1_got++; +} + +static void +forkoff (int nr) +{ + pid_t child; + int i, loop; + struct sigaction act, oldact; +#ifdef THREAD + void *thread_result; +#endif + + memset (&act, 0, sizeof act); + act.sa_flags = SA_RESTART; + act.sa_handler = handler_usr1; + sigemptyset (&act.sa_mask); + i = sigaction (SIGUSR1, &act, &oldact); + assert (i == 0); + + child = fork (); + switch (child) + { + case -1: + assert (0); + default: + printf ("parent%d: %d\n", nr, (int) child); + + /* Sleep for a while to possibly get incorrectly ATTACH_THREADed by GDB + tracing the child fork with no longer valid thread/lwp entries of the + parent. */ + + i = sleep (2); + assert (i == 0); + + /* We must not get caught here (against a forgotten breakpoint). */ + + var++; + breakpoint (); + +#ifdef THREAD + /* And neither got caught our thread. */ + + step = 99; + i = pthread_join (thread, &thread_result); + assert (i == 0); + assert (thread_result == (void *) 99UL); +#endif + + /* Be sure our child knows we did not get caught above. */ + + i = kill (child, SIGUSR1); + assert (i == 0); + + /* Sleep for a while to check GDB's `info threads' no longer tracks us in + the child fork. */ + + i = sleep (2); + assert (i == 0); + + _exit (0); + case 0: + printf ("child%d: %d\n", nr, (int) getpid ()); + + /* Let the parent signal us about its success. Be careful of races. */ + + for (loop = 0; loop < 1000; loop++) + { + /* Parent either died (and USR1_GOT is zero) or it succeeded. */ + if (kill (getppid (), 0) != 0) + break; + /* Parent succeeded? */ + if (usr1_got) + break; + + delay (); + } + assert (usr1_got); + + /* We must get caught here (against a false watchpoint removal). */ + + breakpoint (); + } + + i = sigaction (SIGUSR1, &oldact, NULL); + assert (i == 0); +} + +#else +# error "!FOLLOW_PARENT && !FOLLOW_CHILD" +#endif diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c new file mode 100644 index 0000000..edacfc0 --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c @@ -0,0 +1,157 @@ +/* Test case for forgotten hw-watchpoints after fork()-off of a process. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#define gettid() syscall (__NR_gettid) + +/* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP + variable. Hit-comments need to be duplicite there to catch both at-stops + and behind-stops, depending on the target. */ + +static volatile int var; + +static void +dummy (void) +{ +} + +static void +breakpoint (void) +{ +} + +/* Include here the functions: + static void forkoff (int nr); + static void delay (void); */ + +static pthread_t thread; +static volatile int step; +#define THREAD + +#include "watchpoint-fork-forkoff.c" + +static void * +start (void *arg) +{ + if (step >= 3) + goto step_3; + + while (step != 1) + delay (); + + var++; /* validity-thread-B */ + dummy (); /* validity-thread-B */ + step = 2; + while (step != 3) + { + if (step == 99) + goto step_99; + delay (); + } + +step_3: + if (step >= 5) + goto step_5; + + var++; /* after-fork1-B */ + dummy (); /* after-fork1-B */ + step = 4; + while (step != 5) + { + if (step == 99) + goto step_99; + delay (); + } + +step_5: + var++; /* after-fork2-B */ + dummy (); /* after-fork2-B */ + return (void *) 5UL; + +step_99: + /* We must not get caught here (against a forgotten breakpoint). */ + var++; + breakpoint (); + return (void *) 99UL; +} + +int +main (void) +{ + int i; + void *thread_result; + + setbuf (stdout, NULL); + printf ("main: %d\n", (int) gettid ()); + + /* General watchpoints validity. */ + var++; /* validity-first */ + dummy (); /* validity-first */ + + i = pthread_create (&thread, NULL, start, NULL); + assert (i == 0); + + var++; /* validity-thread-A */ + dummy (); /* validity-thread-A */ + step = 1; + while (step != 2) + delay (); + + /* Hardware watchpoints got disarmed here. */ + forkoff (1); + + var++; /* after-fork1-A */ + dummy (); /* after-fork1-A */ + step = 3; +#ifdef FOLLOW_CHILD + /* Spawn new thread as it was deleted in the child of FORK. */ + i = pthread_create (&thread, NULL, start, NULL); + assert (i == 0); +#endif + while (step != 4) + delay (); + + /* A sanity check for double hardware watchpoints removal. */ + forkoff (2); + + var++; /* after-fork2-A */ + dummy (); /* after-fork2-A */ + step = 5; +#ifdef FOLLOW_CHILD + /* Spawn new thread as it was deleted in the child of FORK. */ + i = pthread_create (&thread, NULL, start, NULL); + assert (i == 0); +#endif + + i = pthread_join (thread, &thread_result); + assert (i == 0); + assert (thread_result == (void *) 5UL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.c b/gdb/testsuite/gdb.threads/watchpoint-fork.c new file mode 100644 index 0000000..5f62e7f --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchpoint-fork.c @@ -0,0 +1,57 @@ +/* Test case for forgotten hw-watchpoints after fork()-off of a process. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +static volatile int var; + +static void +breakpoint (void) +{ +} + +/* Include here the function: + static void forkoff (int nr); */ + +#include "watchpoint-fork-forkoff.c" + +int +main (void) +{ + setbuf (stdout, NULL); + printf ("main: %d\n", (int) getpid ()); + + /* General watchpoints validity. */ + var++; + /* Hardware watchpoints got disarmed here. */ + forkoff (1); + /* This watchpoint got lost before. */ + var++; + /* A sanity check for double hardware watchpoints removal. */ + forkoff (2); + var++; + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.exp b/gdb/testsuite/gdb.threads/watchpoint-fork.exp new file mode 100644 index 0000000..1dc93ab --- /dev/null +++ b/gdb/testsuite/gdb.threads/watchpoint-fork.exp @@ -0,0 +1,130 @@ +# Copyright 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test case for forgotten hw-watchpoints after fork()-off of a process. + +proc test {type symbol} { + global objdir subdir srcdir + + set test watchpoint-fork + + global pf_prefix + set prefix_test $pf_prefix + lappend pf_prefix "$type:" + set prefix_mt $pf_prefix + + # no threads + + set pf_prefix $prefix_mt + lappend pf_prefix "singlethreaded:" + + set executable ${test}-${type} + if { [gdb_compile ${srcdir}/${subdir}/${test}.c ${objdir}/${subdir}/${executable} executable [list debug additional_flags=-D$symbol]] != "" } { + untested ${test}.exp + return -1 + } + clean_restart $executable + + gdb_test "show detach-on-fork" "Whether gdb will detach the child of a fork is on." + gdb_test "set follow-fork-mode $type" + gdb_test "show follow-fork-mode" "Debugger response to a program call of fork or vfork is \"$type\"." + # Testcase uses it for the `follow-fork-mode child' type. + gdb_test "handle SIGUSR1 nostop noprint pass" + + if { ![runto_main] } then { + gdb_suppress_tests + return + } + + # Install the watchpoint only after getting into MAIN - workaround some PPC + # problem. + gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint" + + # It is never hit but it should not be left over in the fork()ed-off child. + gdb_breakpoint "breakpoint" + + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work" + gdb_test "continue" \ + "reakpoint 3, breakpoint.*" "breakpoint after the first fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork" + gdb_test "continue" \ + "reakpoint 3, breakpoint.*" "breakpoint after the second fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 2.*New value = 3.*return *0;" "watchpoint after the second fork" + gdb_test "continue" "Continuing..*Program exited normally." "finish" + + + # threads + + set pf_prefix $prefix_mt + lappend pf_prefix "multithreaded:" + + set executable ${test}-mt-${type} + if { [gdb_compile_pthreads ${srcdir}/${subdir}/${test}-mt.c ${objdir}/${subdir}/${executable} executable [list debug additional_flags=-D$symbol]] != "" } { + untested ${test}.exp + return -1 + } + clean_restart $executable + + gdb_test "set follow-fork-mode $type" + # Testcase uses it for the `follow-fork-mode child' type. + gdb_test "handle SIGUSR1 nostop noprint pass" + + if { ![runto_main] } then { + gdb_suppress_tests + return + } + + # Install the watchpoint only after getting into MAIN - workaround some PPC + # problem. + gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint" + + # It is never hit but it should not be left over in the fork()ed-off child. + gdb_breakpoint "breakpoint" + + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B" + gdb_test "continue" \ + "reakpoint 3, breakpoint.*" "breakpoint (A) after the first fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork" + gdb_test "continue" \ + "reakpoint 3, breakpoint.*" "breakpoint (A) after the second fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork" + gdb_test "continue" \ + "atchpoint 2: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork" + gdb_test "continue" "Continuing..*Program exited normally." "finish" + + + # cleanup + + set pf_prefix $prefix_test +} + +test parent FOLLOW_PARENT + +# Only GNU/Linux is known to support `set follow-fork-mode child'. +if {[istarget "*-*-linux*"]} { + test child FOLLOW_CHILD +} diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp index 6fbee84..1189cfd 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 9b06a2f..419d5a9 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -27,6 +27,7 @@ if {$tool == ""} { } load_lib libgloss.exp +load_lib python-support.exp global GDB diff --git a/gdb/testsuite/lib/python-support.exp b/gdb/testsuite/lib/python-support.exp new file mode 100644 index 0000000..b8e9836 --- /dev/null +++ b/gdb/testsuite/lib/python-support.exp @@ -0,0 +1,53 @@ +global python_supported_saved + +# Return 1 if Python scripting is supported in GDB, 0 if not. +proc python_supported { } { + global gdb_prompt + global python_supported_saved + + if [info exists python_supported_saved] { + verbose "python_supported: returning saved $python_supported_saved" 2 + return $python_supported_saved + } + + gdb_test_multiple "python print 'hello, world!'" "verify python support" { + -re "not supported.*$gdb_prompt $" { + return [set python_supported_saved 0] + } + -re "$gdb_prompt $" { + return [set python_supported_saved 1] + } + } + + return [set python_supported_saved 0] +} + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } +} + +# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}... +# Run a test named NAME, consisting of multiple lines of input. +# After each input line INPUT, search for result line RESULT. +# Succeed if all results are seen; fail otherwise. +proc gdb_py_test_multiple {name args} { + global gdb_prompt + + foreach {input result} $args { + if {[gdb_test_multiple $input "$name - $input" { + -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" { + pass "$name - $input" + } + }]} { + return 1 + } + } + return 0 +} diff --git a/gdb/thread.c b/gdb/thread.c index 16a207c..c3cff06 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -61,7 +61,6 @@ static int thread_alive (struct thread_info *); static void info_threads_command (char *, int); static void thread_apply_command (char *, int); static void restore_current_thread (ptid_t); -static void prune_threads (void); /* Frontend view of the thread state. Possible extensions: stepping, finishing, until(ling),... */ @@ -517,7 +516,7 @@ thread_alive (struct thread_info *tp) return 1; } -static void +void prune_threads (void) { struct thread_info *tp, *next; diff --git a/gdb/top.c b/gdb/top.c index 90e8f1e..489e24a 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -337,6 +337,7 @@ void prepare_execute_command (void) { free_all_values (); + free_all_types (); /* With multiple threads running while the one we're examining is stopped, the dcache can get stale without us being able to detect it. diff --git a/gdb/typeprint.c b/gdb/typeprint.c index ce9f551..5f9d739 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -36,6 +36,7 @@ #include "gdb_string.h" #include "exceptions.h" #include "valprint.h" +#include "dwarf2loc.h" #include extern void _initialize_typeprint (void); @@ -77,6 +78,9 @@ void type_print (struct type *type, char *varstring, struct ui_file *stream, int show) { + if (show >= 0) + type = check_typedef (type); + LA_PRINT_TYPE (type, varstring, stream, show, 0); } @@ -115,7 +119,8 @@ whatis_exp (char *exp, int show) { struct expression *expr; struct value *val; - struct cleanup *old_chain = NULL; + /* Required at least for the object_address_set call. */ + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); struct type *real_type = NULL; struct type *type; int full = 0; @@ -126,12 +131,13 @@ whatis_exp (char *exp, int show) if (exp) { expr = parse_expression (exp); - old_chain = make_cleanup (free_current_contents, &expr); + make_cleanup (free_current_contents, &expr); val = evaluate_type (expr); } else val = access_value_history (0); + object_address_set (value_raw_address (val)); type = value_type (val); get_user_print_options (&opts); @@ -168,8 +174,7 @@ whatis_exp (char *exp, int show) type_print (type, "", gdb_stdout, show); printf_filtered ("\n"); - if (exp) - do_cleanups (old_chain); + do_cleanups (old_chain); } static void diff --git a/gdb/typeprint.h b/gdb/typeprint.h index 7d7e6bc..6ee65cf 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 e6aaf93..1760b4c 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 "gdb_select.h" @@ -264,7 +265,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 { @@ -298,6 +299,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 6155699..bb94f4b 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -20,6 +20,7 @@ #ifndef UI_FILE_H #define UI_FILE_H +struct obstack; struct ui_file; /* Create a generic ui_file object with null methods. */ @@ -78,7 +79,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 82a66a1..c305506 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -2656,7 +2656,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) @@ -2681,7 +2684,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 ed76b09..8bf3634 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 ca34083..c23fd68 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -38,6 +38,7 @@ #include "cp-support.h" #include "dfp.h" #include "user-regs.h" +#include "dwarf2loc.h" #include #include "gdb_string.h" @@ -374,8 +375,6 @@ value_cast (struct type *type, struct value *arg2) new_length = val_length / element_length; if (val_length % element_length != 0) warning (_("array element type size does not divide object size in cast")); - /* FIXME-type-allocation: need a way to free this type when - we are done with it. */ range_type = create_range_type ((struct type *) NULL, TYPE_TARGET_TYPE (range_type), low_bound, @@ -822,6 +821,64 @@ value_one (struct type *type, enum lval_type lv) return val; } +/* object_address_set must be already called before this function. */ + +const char * +object_address_data_not_valid (struct type *type) +{ + /* Attributes are present only at the target type of a typedef. Make the + call conditional as it would otherwise loop through type_length_get. */ + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + CHECK_TYPEDEF (type); + + /* DW_AT_associated has a preference over DW_AT_allocated. */ + if (TYPE_NOT_ASSOCIATED (type) + || (TYPE_ASSOCIATED (type) != NULL + && 0 == dwarf_locexpr_baton_eval (TYPE_ASSOCIATED (type)))) + return N_("object is not associated"); + + if (TYPE_NOT_ALLOCATED (type) + || (TYPE_ALLOCATED (type) != NULL + && 0 == dwarf_locexpr_baton_eval (TYPE_ALLOCATED (type)))) + return N_("object is not allocated"); + + return NULL; +} + +/* Return non-zero if the variable is valid. If it is valid the function + may store the data address (DW_AT_DATA_LOCATION) of TYPE at *ADDRESS_RETURN. + You must set *ADDRESS_RETURN from value_raw_address (VAL) before calling this + function. If no DW_AT_DATA_LOCATION is present for TYPE the address at + *ADDRESS_RETURN is left unchanged. ADDRESS_RETURN must not be NULL, use + object_address_data_not_valid () for just the data validity check. */ + +int +object_address_get_data (struct type *type, CORE_ADDR *address_return) +{ + gdb_assert (address_return != NULL); + + object_address_set (*address_return); + + /* TYPE_DATA_LOCATION_DWARF_BLOCK / TYPE_DATA_LOCATION_ADDR are present only + at the target type of a typedef. */ + CHECK_TYPEDEF (type); + + if (object_address_data_not_valid (type) != NULL) + { + /* Do not try to evaluate DW_AT_data_location as it may even crash + (it would just return the value zero in the gfortran case). */ + return 0; + } + + if (TYPE_DATA_LOCATION_IS_ADDR (type)) + *address_return = TYPE_DATA_LOCATION_ADDR (type); + else if (TYPE_DATA_LOCATION_DWARF_BLOCK (type) != NULL) + *address_return + = dwarf_locexpr_baton_eval (TYPE_DATA_LOCATION_DWARF_BLOCK (type)); + + return 1; +} + /* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */ static struct value * @@ -913,15 +970,21 @@ value_fetch_lazy (struct value *val) } else if (VALUE_LVAL (val) == lval_memory) { - CORE_ADDR addr = value_address (val); - int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val))); + CORE_ADDR addr = value_raw_address (val); - if (length) + if (object_address_get_data (value_type (val), &addr)) { - if (value_stack (val)) - read_stack (addr, value_contents_all_raw (val), length); - else - read_memory (addr, value_contents_all_raw (val), length); + struct type *type = value_enclosing_type (val); + int length = TYPE_LENGTH (check_typedef (type)); + + if (length) + { + addr += value_offset (val); + if (value_stack (val)) + read_stack (addr, value_contents_all_raw (val), length); + else + read_memory (addr, value_contents_all_raw (val), length); + } } } else if (VALUE_LVAL (val) == lval_register) @@ -1329,7 +1392,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); } @@ -1435,6 +1509,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 @@ -1444,8 +1519,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 @@ -2328,12 +2407,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, @@ -2353,16 +2445,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 C++ name, try to extract just the function - part. */ - if (qualified_name) - func_name = cp_func_name (qualified_name); + /* 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 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; @@ -3096,7 +3201,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); @@ -3240,7 +3345,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) @@ -3294,8 +3399,6 @@ value_slice (struct value *array, int lowbound, int length) || lowbound + length - 1 > upperbound) error (_("slice out of range")); - /* FIXME-type-allocation: need a way to free this type when we are - done with it. */ slice_range_type = create_range_type ((struct type *) NULL, TYPE_TARGET_TYPE (range_type), lowbound, diff --git a/gdb/valprint.c b/gdb/valprint.c index 3f21ae4..9b15b1a 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -236,7 +236,6 @@ scalar_type_p (struct type *type) case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: case TYPE_CODE_SET: - case TYPE_CODE_STRING: case TYPE_CODE_BITSTRING: return 0; default: @@ -1154,6 +1153,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, for (; i < len && things_printed < options->print_max; i++) { + size_t elt_offset = i * eltlen; if (i != 0) { if (options->prettyprint_arrays) @@ -1173,7 +1173,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, rep1 = i + 1; reps = 1; while ((rep1 < len) && - !memcmp (valaddr + i * eltlen, valaddr + rep1 * eltlen, eltlen)) + !memcmp (valaddr + elt_offset, valaddr + rep1 * eltlen, eltlen)) { ++reps; ++rep1; diff --git a/gdb/value.c b/gdb/value.c index a462ee4..968cdf4 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -37,8 +37,10 @@ #include "block.h" #include "dfp.h" #include "objfiles.h" +#include "cli/cli-decode.h" #include "valprint.h" #include "cli/cli-decode.h" +#include "observer.h" #include "python/python.h" @@ -170,6 +172,14 @@ struct value taken off this list. */ struct value *next; + /* The reference count. A value that is still on the `all_values' + list will have a reference count of 0. A call to `release_value' + will increment the reference count (and remove the value from the + list, the first time). A call to `value_free' will decrement the + reference count, and will free the value when there are no more + references. */ + int refcount; + /* Register number if the value is from a register. */ short regnum; @@ -631,6 +641,13 @@ value_free (struct value *val) if (val->parent != NULL) value_free (val->parent); +#if 0 + /* We need type GC instead. This can fail when an objfile is + reclaimed and then a value is later freed. */ + type_decref (val->type); + type_decref (val->enclosing_type); +#endif + if (VALUE_LVAL (val) == lval_computed) { struct lval_funcs *funcs = val->location.computed.funcs; @@ -735,6 +752,7 @@ value_copy (struct value *arg) val = allocate_value_lazy (encl_type); else val = allocate_value (encl_type); + val->type = arg->type; VALUE_LVAL (val) = VALUE_LVAL (arg); val->location = arg->location; @@ -770,12 +788,15 @@ value_copy (struct value *arg) void set_value_component_location (struct value *component, struct value *whole) { + CORE_ADDR addr; + if (VALUE_LVAL (whole) == lval_internalvar) VALUE_LVAL (component) = lval_internalvar_component; else VALUE_LVAL (component) = VALUE_LVAL (whole); component->location = whole->location; + if (VALUE_LVAL (whole) == lval_computed) { struct lval_funcs *funcs = whole->location.computed.funcs; @@ -783,6 +804,12 @@ set_value_component_location (struct value *component, struct value *whole) if (funcs->copy_closure) component->location.computed.closure = funcs->copy_closure (whole); } + + addr = value_raw_address (component); + object_address_get_data (value_type (whole), &addr); + if (component->lval != lval_internalvar + && component->lval != lval_internalvar_component) + set_value_address (component, addr); } @@ -913,6 +940,29 @@ show_values (char *num_exp, int from_tty) num_exp[1] = '\0'; } } + +/* Sanity check for memory leaks and proper types reference counting. */ + +static void +value_history_cleanup (void *unused) +{ + while (value_history_chain) + { + struct value_history_chunk *chunk = value_history_chain; + int i; + + for (i = 0; i < ARRAY_SIZE (chunk->values); i++) + value_free (chunk->values[i]); + + value_history_chain = chunk->next; + xfree (chunk); + } + value_history_count = 0; + + /* Free the unreferenced types above. */ + free_all_values (); + free_all_types (); +} /* Internal variables. These are variables within the debugger that hold values assigned by debugger commands. @@ -1388,6 +1438,40 @@ call_internal_function (struct gdbarch *gdbarch, return (*ifn->handler) (gdbarch, language, ifn->cookie, argc, argv); } +/* Call type_mark_used for any TYPEs referenced from this GDB source file. */ + +static void +value_types_mark_used (void) +{ + struct internalvar *var; + struct value_history_chunk *chunk; + + for (var = internalvars; var != NULL; var = var->next) + switch (var->kind) + { + case INTERNALVAR_VALUE: + type_mark_used (value_type (var->u.value)); + break; + + case INTERNALVAR_INTEGER: + type_mark_used (var->u.integer.type); + break; + + case INTERNALVAR_POINTER: + type_mark_used (var->u.pointer.type); + break; + } + + for (chunk = value_history_chain; chunk != NULL; chunk = chunk->next) + { + int i; + + for (i = 0; i < ARRAY_SIZE (chunk->values); i++) + if (chunk->values[i]) + type_mark_used (value_type (chunk->values[i])); + } +} + /* The 'function' command. This does nothing -- it is just a placeholder to let "help function NAME" work. This is also used as the implementation of the sub-command that is created when @@ -1435,11 +1519,10 @@ preserve_one_value (struct value *value, struct objfile *objfile, htab_t copied_types) { if (TYPE_OBJFILE (value->type) == objfile) - value->type = copy_type_recursive (objfile, value->type, copied_types); + value->type = copy_type_recursive (value->type, copied_types); if (TYPE_OBJFILE (value->enclosing_type) == objfile) - value->enclosing_type = copy_type_recursive (objfile, - value->enclosing_type, + value->enclosing_type = copy_type_recursive (value->enclosing_type, copied_types); } @@ -1454,13 +1537,13 @@ preserve_one_internalvar (struct internalvar *var, struct objfile *objfile, case INTERNALVAR_INTEGER: if (var->u.integer.type && TYPE_OBJFILE (var->u.integer.type) == objfile) var->u.integer.type - = copy_type_recursive (objfile, var->u.integer.type, copied_types); + = copy_type_recursive (var->u.integer.type, copied_types); break; case INTERNALVAR_POINTER: if (TYPE_OBJFILE (var->u.pointer.type) == objfile) var->u.pointer.type - = copy_type_recursive (objfile, var->u.pointer.type, copied_types); + = copy_type_recursive (var->u.pointer.type, copied_types); break; case INTERNALVAR_VALUE: @@ -2192,6 +2275,42 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num) } +/* Pack NUM into BUF using a target format of TYPE. */ + +void +pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num) +{ + enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); + int len; + + type = check_typedef (type); + len = TYPE_LENGTH (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + case TYPE_CODE_ENUM: + case TYPE_CODE_FLAGS: + case TYPE_CODE_BOOL: + case TYPE_CODE_RANGE: + case TYPE_CODE_MEMBERPTR: + store_unsigned_integer (buf, len, byte_order, num); + break; + + case TYPE_CODE_REF: + case TYPE_CODE_PTR: + store_typed_address (buf, type, (CORE_ADDR) num); + break; + + default: + error (_("\ +Unexpected type (%d) encountered for unsigned integer constant."), + TYPE_CODE (type)); + } +} + + /* Convert C numbers into newly allocated values. */ struct value * @@ -2205,6 +2324,19 @@ value_from_longest (struct type *type, LONGEST num) } +/* Convert C unsigned numbers into newly allocated values. */ + +struct value * +value_from_ulongest (struct type *type, ULONGEST num) +{ + struct value *val = allocate_value (type); + + pack_unsigned_long (value_contents_raw (val), type, num); + + return val; +} + + /* Create a value representing a pointer of type TYPE to the address ADDR. */ struct value * @@ -2363,4 +2495,8 @@ VARIABLE is already initialized.")); add_prefix_cmd ("function", no_class, function_command, _("\ Placeholder command for showing help on convenience functions."), &functionlist, "function ", 0, &cmdlist); + + make_final_cleanup (value_history_cleanup, NULL); + + observer_attach_mark_used (value_types_mark_used); } diff --git a/gdb/value.h b/gdb/value.h index 42b4497..6f9923c 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -342,11 +342,16 @@ extern LONGEST unpack_field_as_long (struct type *type, extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num); extern struct value *value_from_longest (struct type *type, LONGEST num); +extern struct value *value_from_ulongest (struct type *type, ULONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); extern struct value *value_from_decfloat (struct type *type, const gdb_byte *decbytes); +extern const char *object_address_data_not_valid (struct type *type); +extern int object_address_get_data (struct type *type, + CORE_ADDR *address_return); + extern struct value *value_at (struct type *type, CORE_ADDR addr); extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr); @@ -689,7 +694,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 6ec87b3..b274ade 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -26,6 +26,8 @@ #include "gdbcmd.h" #include "block.h" #include "valprint.h" +#include "objfiles.h" +#include "parser-defs.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -3495,7 +3497,7 @@ all_root_varobjs (void (*func) (struct varobj *var, void *data), void *data) (*func) (var_root->rootvar, data); } } - + extern void _initialize_varobj (void); void _initialize_varobj (void) diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c index 25cc2d9..6784654 100644 --- a/gdb/xcoffread.c +++ b/gdb/xcoffread.c @@ -3030,6 +3030,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