http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: commit 30a7ce8ffc2b54bc4453a127be8dd28a3ea6d299 branch `archer' - the merge of branches: archer-jankratochvil-vla archer-jankratochvil-watchpoint3 archer-jankratochvil-ifunc archer-pmuldoon-next-over-throw2 archer-tromey-python (not a merge) archer-tromey-optional-psymtab (cherry-picked from post-7.2 master) #TODO:archer-tromey-threaded-dwarf diff --git a/gdb/Makefile.in b/gdb/Makefile.in index f07bc8b..3703dca 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -169,6 +169,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. @@ -295,13 +301,13 @@ SUBDIR_PYTHON_SRCS = \ 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-progspace.c \ python/py-symbol.c \ python/py-symtab.c \ python/py-type.c \ @@ -780,8 +786,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 \ -psymtab.h psympriv.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. @@ -1301,6 +1307,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 @@ -2024,6 +2036,10 @@ 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) @@ -2072,6 +2088,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 1d4c38b..cafb88e 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -11114,6 +11114,7 @@ ada_operator_length (const struct expression *exp, int pc, int *oplenp, 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) { @@ -11128,12 +11129,15 @@ ada_operator_check (struct expression *exp, int pos, break; default: - return operator_check_standard (exp, pos, objfile_func, data); + 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_OBJFILE (type) + 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; diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index c0edc10..17d36b5 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -375,6 +375,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) @@ -796,6 +810,7 @@ _initialize_amd64_linux_nat (void) i386_dr_low.reset_addr = amd64_linux_dr_reset_addr; i386_dr_low.get_status = amd64_linux_dr_get_status; i386_dr_low.unset_status = amd64_linux_dr_unset_status; + i386_dr_low.detach = amd64_linux_dr_detach; i386_set_debug_register_length (8); /* Override the GNU/Linux inferior startup hook. */ diff --git a/gdb/block.c b/gdb/block.c index 48ac21b..ffcc97f 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -321,3 +321,21 @@ allocate_block (struct obstack *obstack) 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..a517e80 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -166,4 +166,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/blockframe.c b/gdb/blockframe.c index 0348bf4..f01d0ee 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -38,6 +38,7 @@ #include "block.h" #include "inline-frame.h" #include "psymtab.h" +#include "elf-bfd.h" /* Return the innermost lexical block in execution in a specified stack frame. The frame address is assumed valid. @@ -159,6 +160,7 @@ static CORE_ADDR cache_pc_function_low = 0; static CORE_ADDR cache_pc_function_high = 0; static char *cache_pc_function_name = 0; static struct obj_section *cache_pc_function_section = NULL; +static int cache_pc_function_is_gnu_ifunc = 0; /* Clear cache, e.g. when symbol table is discarded. */ @@ -169,6 +171,7 @@ clear_pc_function_cache (void) cache_pc_function_high = 0; cache_pc_function_name = (char *) 0; cache_pc_function_section = NULL; + cache_pc_function_is_gnu_ifunc = 0; } /* Finds the "function" (text symbol) that is smaller than PC but @@ -184,7 +187,7 @@ clear_pc_function_cache (void) /* Backward compatibility, no section argument. */ -int +enum find_pc_partial_function_type find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, CORE_ADDR *endaddr) { @@ -236,6 +239,7 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); cache_pc_function_name = SYMBOL_LINKAGE_NAME (f); cache_pc_function_section = section; + cache_pc_function_is_gnu_ifunc = TYPE_GNU_IFUNC (SYMBOL_TYPE (f)); goto return_cached_value; } } @@ -258,12 +262,13 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, *address = 0; if (endaddr != NULL) *endaddr = 0; - return 0; + return FIND_PC_PARTIAL_FUNCTION_NOT_FOUND; } cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol); cache_pc_function_name = SYMBOL_LINKAGE_NAME (msymbol); cache_pc_function_section = section; + cache_pc_function_is_gnu_ifunc = MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc; /* If the minimal symbol has a size, use it for the cache. Otherwise use the lesser of the next minimal symbol in the same @@ -323,7 +328,8 @@ find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address, *endaddr = cache_pc_function_high; } - return 1; + return cache_pc_function_is_gnu_ifunc ? FIND_PC_PARTIAL_FUNCTION_GNU_IFUNC + : FIND_PC_PARTIAL_FUNCTION_NORMAL; } /* Return the innermost stack frame executing inside of BLOCK, diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 6a6864c..5df336d 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -62,6 +62,7 @@ #include "jit.h" #include "xml-syscall.h" #include "parser-defs.h" +#include "regcache.h" /* readline include files */ #include "readline/readline.h" @@ -92,6 +93,9 @@ static void map_breakpoint_numbers (char *, void (*) (struct breakpoint *, static void ignore_command (char *, int); +static void update_breakpoint_locations (struct breakpoint *b, + struct symtabs_and_lines sals); + static int breakpoint_re_set_one (void *); static void clear_command (char *, int); @@ -106,6 +110,9 @@ static void break_command_1 (char *, int, int); static void mention (struct breakpoint *); +static struct bp_location *add_location_to_breakpoint (struct breakpoint *b, + const struct symtab_and_line *sal); + /* This function is used in gdbtk sources and thus can not be made static. */ struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line, @@ -230,6 +237,10 @@ static void disable_trace_command (char *, int); static void trace_pass_command (char *, int); +static void gnu_ifunc_resolver_stop (struct breakpoint *b); + +static void gnu_ifunc_resolver_return_stop (struct breakpoint *b); + /* Assuming we're creating a static tracepoint, does S look like a static tracepoint marker spec ("-m MARKER_ID")? */ #define is_marker_spec(s) \ @@ -430,7 +441,7 @@ static int tracepoint_count; static struct cmd_list_element *breakpoint_set_cmdlist; static struct cmd_list_element *breakpoint_show_cmdlist; -static struct cmd_list_element *save_cmdlist; +struct cmd_list_element *save_cmdlist; /* Return whether a breakpoint is an active enabled breakpoint. */ static int @@ -1252,6 +1263,22 @@ watchpoint_in_thread_scope (struct breakpoint *b) && !is_executing (inferior_ptid))); } +static void +watchpoint_del_at_next_stop (struct breakpoint *b) +{ + gdb_assert (is_watchpoint (b)); + + if (b->related_breakpoint != b) + { + gdb_assert (b->related_breakpoint->type == bp_watchpoint_scope); + gdb_assert (b->related_breakpoint->related_breakpoint == b); + b->related_breakpoint->disposition = disp_del_at_next_stop; + b->related_breakpoint->related_breakpoint = b->related_breakpoint; + b->related_breakpoint = b; + } + b->disposition = disp_del_at_next_stop; +} + /* Assuming that B is a watchpoint: - Reparse watchpoint expression, if REPARSE is non-zero - Evaluate expression and store the result in B->val @@ -1307,6 +1334,8 @@ update_watchpoint (struct breakpoint *b, int reparse) struct frame_id saved_frame_id; int frame_saved; + gdb_assert (is_watchpoint (b)); + /* If this is a local watchpoint, we only want to check if the watchpoint frame is in scope if the current thread is the thread that was used to create the watchpoint. */ @@ -1510,13 +1539,7 @@ update_watchpoint (struct breakpoint *b, int reparse) Watchpoint %d deleted because the program has left the block\n\ in which its expression is valid.\n"), b->number); - if (b->related_breakpoint) - { - b->related_breakpoint->disposition = disp_del_at_next_stop; - b->related_breakpoint->related_breakpoint = NULL; - b->related_breakpoint= NULL; - } - b->disposition = disp_del_at_next_stop; + watchpoint_del_at_next_stop (b); } /* Restore the selected frame. */ @@ -2201,6 +2224,33 @@ create_std_terminate_master_breakpoint (const 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) + { + struct breakpoint *b; + + b = create_internal_breakpoint (get_objfile_arch (objfile), + SYMBOL_VALUE_ADDRESS (debug_hook), + 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) { @@ -2242,7 +2292,8 @@ 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_std_terminate_master) + || b->type == bp_longjmp_master || b->type == bp_std_terminate_master + || b->type == bp_exception_master) { delete_breakpoint (b); continue; @@ -2257,7 +2308,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; @@ -2319,6 +2371,7 @@ update_breakpoints_after_exec (void) create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); create_std_terminate_master_breakpoint ("std::terminate()"); + create_exception_master_breakpoint (); } int @@ -2346,6 +2399,8 @@ detach_breakpoints (int pid) /* Detach single-step breakpoints as well. */ detach_single_step_breakpoints (); + val |= target_detach_watchpoints (); + do_cleanups (old_chain); return val; } @@ -2447,9 +2502,11 @@ 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) { - b->inserted = (is == mark_inserted); + b->inserted = 0; val = target_remove_watchpoint (b->address, b->length, b->watchpoint_type, b->owner->cond_exp); @@ -3237,6 +3294,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); @@ -3324,6 +3387,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: @@ -3331,6 +3396,8 @@ print_it_typical (bpstat bs) case bp_tracepoint: case bp_fast_tracepoint: case bp_jit_event: + case bp_gnu_ifunc_resolver: + case bp_gnu_ifunc_resolver_return: default: result = PRINT_UNKNOWN; break; @@ -3549,6 +3616,8 @@ watchpoint_check (void *p) gdb_assert (bs->breakpoint_at->owner != NULL); b = bs->breakpoint_at->owner; + gdb_assert (is_watchpoint (b)); + /* If this is a local watchpoint, we only want to check if the watchpoint frame is in scope if the current thread is the thread that was used to create the watchpoint. */ @@ -3655,13 +3724,7 @@ watchpoint_check (void *p) ui_out_text (uiout, " deleted because the program has left the block in\n\ which its expression is valid.\n"); - if (b->related_breakpoint) - { - b->related_breakpoint->disposition = disp_del_at_next_stop; - b->related_breakpoint->related_breakpoint = NULL; - b->related_breakpoint = NULL; - } - b->disposition = disp_del_at_next_stop; + watchpoint_del_at_next_stop (b); return WP_DELETED; } @@ -3730,8 +3793,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; @@ -3865,9 +3932,7 @@ bpstat_check_watchpoint (bpstat bs) case 0: /* Error from catch_errors. */ printf_filtered (_("Watchpoint %d deleted.\n"), b->number); - if (b->related_breakpoint) - b->related_breakpoint->disposition = disp_del_at_next_stop; - b->disposition = disp_del_at_next_stop; + watchpoint_del_at_next_stop (b); /* We've already printed what needs to be printed. */ bs->print_it = print_it_done; break; @@ -3881,8 +3946,10 @@ bpstat_check_watchpoint (bpstat bs) anything for this watchpoint. */ bs->print_it = print_it_noop; bs->stop = 0; + return 0; } } + return 1; } @@ -3914,7 +3981,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) watchpoint as triggered so that we will handle the out-of-scope event. We'll get to the watchpoint next iteration. */ - if (b->type == bp_watchpoint_scope) + if (b->type == bp_watchpoint_scope && b->related_breakpoint != b) b->related_breakpoint->watchpoint_triggered = watch_triggered_yes; if (is_watchpoint (b)) @@ -4045,6 +4112,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 the entire expression, not the individual locations. For read watchpoints, the @@ -4062,6 +4131,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 @@ -4069,13 +4139,23 @@ 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_std_terminate_master) + || b->type == bp_std_terminate_master + || b->type == bp_exception_master) /* We do not stop for these. */ bs->stop = 0; else @@ -4176,7 +4256,7 @@ handle_jit_event (void) /* Decide what infrun needs to do with this bpstat. */ struct bpstat_what -bpstat_what (bpstat bs) +bpstat_what (bpstat bs_head) { struct bpstat_what retval; /* We need to defer calling `solib_add', as adding new symbols @@ -4184,11 +4264,13 @@ bpstat_what (bpstat bs) and hence may clear unprocessed entries in the BS chain. */ int shlib_event = 0; int jit_event = 0; + bpstat bs; retval.main_action = BPSTAT_WHAT_KEEP_CHECKING; retval.call_dummy = STOP_NONE; + retval.is_longjmp = 0; - for (; bs != NULL; bs = bs->next) + for (bs = bs_head; bs != NULL; bs = bs->next) { /* Extract this BS's action. After processing each BS, we check if its action overrides all we've seem so far. */ @@ -4242,10 +4324,15 @@ bpstat_what (bpstat bs) } break; case bp_longjmp: + case bp_exception: this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME; + retval.is_longjmp = bs->breakpoint_at->owner->type == bp_longjmp; break; case bp_longjmp_resume: + case bp_exception_resume: this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME; + retval.is_longjmp + = bs->breakpoint_at->owner->type == bp_longjmp_resume; break; case bp_step_resume: if (bs->stop) @@ -4261,6 +4348,7 @@ bpstat_what (bpstat bs) case bp_overlay_event: case bp_longjmp_master: case bp_std_terminate_master: + case bp_exception_master: this_action = BPSTAT_WHAT_SINGLE; break; case bp_catchpoint: @@ -4313,6 +4401,20 @@ bpstat_what (bpstat bs) out already. */ internal_error (__FILE__, __LINE__, _("bpstat_what: tracepoint encountered")); + break; + case bp_gnu_ifunc_resolver: + /* Skip the current breakpoint but otherwise nothing happens. GDB is + inserting new bp_gnu_ifunc_resolver_return at this point but + bp_gnu_ifunc_resolver is being kept there as another + bp_gnu_ifunc_resolver_return may be inserted in the meantime. */ + this_action = BPSTAT_WHAT_SINGLE; + break; + case bp_gnu_ifunc_resolver_return: + /* The whole bp_gnu_ifunc_resolver with its associated + bp_gnu_ifunc_resolver_return related_breakpoint's has been + resolved now, all these helper breakpoints are being removed and + new final bp_breakpoint is being put at the target location. */ + break; default: internal_error (__FILE__, __LINE__, _("bpstat_what: unhandled bptype %d"), (int) bptype); @@ -4350,6 +4452,23 @@ bpstat_what (bpstat bs) handle_jit_event (); } + for (bs = bs_head; bs != NULL; bs = bs->next) + { + if (bs->breakpoint_at == NULL) + continue; + if (bs->breakpoint_at->owner == NULL) + continue; + switch (bs->breakpoint_at->owner->type) + { + case bp_gnu_ifunc_resolver: + gnu_ifunc_resolver_stop (bs->breakpoint_at->owner); + break; + case bp_gnu_ifunc_resolver_return: + gnu_ifunc_resolver_return_stop (bs->breakpoint_at->owner); + break; + } + } + return retval; } @@ -4461,6 +4580,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"}, @@ -4470,11 +4591,14 @@ print_one_breakpoint_location (struct breakpoint *b, {bp_overlay_event, "overlay events"}, {bp_longjmp_master, "longjmp master"}, {bp_std_terminate_master, "std::terminate master"}, + {bp_exception_master, "exception master"}, {bp_catchpoint, "catchpoint"}, {bp_tracepoint, "tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"}, {bp_static_tracepoint, "static tracepoint"}, {bp_jit_event, "jit events"}, + {bp_gnu_ifunc_resolver, "gnu-ifunc resolver"}, + {bp_gnu_ifunc_resolver_return, "gnu-func resolver return"}, }; static char bpenables[] = "nynny"; @@ -4595,6 +4719,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: @@ -4604,10 +4730,13 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_overlay_event: case bp_longjmp_master: case bp_std_terminate_master: + case bp_exception_master: case bp_tracepoint: case bp_fast_tracepoint: case bp_static_tracepoint: case bp_jit_event: + case bp_gnu_ifunc_resolver: + case bp_gnu_ifunc_resolver_return: if (opts.addressprint) { annotate_field (4); @@ -4888,7 +5017,8 @@ user_settable_breakpoint (const struct breakpoint *b) || b->type == bp_catchpoint || b->type == bp_hardware_breakpoint || is_tracepoint (b) - || is_watchpoint (b)); + || is_watchpoint (b) + || b->type == bp_gnu_ifunc_resolver); } /* Print information on user settable breakpoint (watchpoint, etc) @@ -5334,6 +5464,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: @@ -5344,6 +5476,9 @@ allocate_bp_location (struct breakpoint *bpt) case bp_jit_event: case bp_longjmp_master: case bp_std_terminate_master: + case bp_gnu_ifunc_resolver: + case bp_gnu_ifunc_resolver_return: + case bp_exception_master: loc->loc_type = bp_loc_software_breakpoint; break; case bp_hardware_breakpoint: @@ -5420,6 +5555,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch, b->syscalls_to_be_caught = NULL; b->ops = NULL; b->condition_not_parsed = 0; + b->related_breakpoint = b; /* Add this breakpoint to the end of the chain so that a list of breakpoints will come out in order @@ -5439,7 +5575,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch, /* Initialize loc->function_name. */ static void -set_breakpoint_location_function (struct bp_location *loc) +set_breakpoint_location_function (struct bp_location *loc, int explicit_loc) { gdb_assert (loc->owner != NULL); @@ -5447,8 +5583,29 @@ set_breakpoint_location_function (struct bp_location *loc) || loc->owner->type == bp_hardware_breakpoint || is_tracepoint (loc->owner)) { - find_pc_partial_function (loc->address, &(loc->function_name), - NULL, NULL); + if (find_pc_partial_function (loc->address, &(loc->function_name), NULL, + NULL) == FIND_PC_PARTIAL_FUNCTION_GNU_IFUNC + && !explicit_loc) + { + struct breakpoint *b = loc->owner; + + gdb_assert (loc->pspace == current_program_space); + if (resolve_gnu_ifunc (loc->function_name, &loc->requested_address)) + { + /* Recalculate ADDRESS based on new REQUESTED_ADDRESS. */ + loc->address = adjust_breakpoint_address (loc->gdbarch, + loc->requested_address, + b->type); + } + else if (b->type == bp_breakpoint && b->loc == loc + && loc->next == NULL && b->related_breakpoint == b) + { + /* Create only the whole new breakpoint of this type but do not + mess more complicated breakpoints with multiple locations. */ + b->type = bp_gnu_ifunc_resolver; + } + } + if (loc->function_name) loc->function_name = xstrdup (loc->function_name); } @@ -5521,7 +5678,8 @@ set_raw_breakpoint (struct gdbarch *gdbarch, b->loc->section = sal.section; b->line_number = sal.line; - set_breakpoint_location_function (b->loc); + set_breakpoint_location_function (b->loc, + sal.explicit_pc || sal.explicit_line); breakpoints_changed (); @@ -5548,8 +5706,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) @@ -5562,11 +5719,12 @@ 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; } } @@ -5578,7 +5736,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); @@ -6595,7 +6753,7 @@ clone_momentary_breakpoint (struct breakpoint *orig) copy = set_raw_breakpoint_without_location (orig->gdbarch, orig->type); copy->loc = allocate_bp_location (copy); - set_breakpoint_location_function (copy->loc); + set_breakpoint_location_function (copy->loc, 1); copy->loc->gdbarch = orig->loc->gdbarch; copy->loc->requested_address = orig->loc->requested_address; @@ -6694,6 +6852,7 @@ mention (struct breakpoint *b) do_cleanups (ui_out_chain); break; case bp_breakpoint: + case bp_gnu_ifunc_resolver: if (ui_out_is_mi_like_p (uiout)) { say_where = 0; @@ -6704,6 +6863,8 @@ mention (struct breakpoint *b) else printf_filtered (_("Breakpoint")); printf_filtered (_(" %d"), b->number); + if (b->type == bp_gnu_ifunc_resolver) + printf_filtered (_(" at gnu-indirect-function resolver")); say_where = 1; break; case bp_hardware_breakpoint: @@ -6750,6 +6911,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_std_terminate: @@ -6760,6 +6923,8 @@ mention (struct breakpoint *b) case bp_jit_event: case bp_longjmp_master: case bp_std_terminate_master: + case bp_gnu_ifunc_resolver_return: + case bp_exception_master: break; } @@ -6820,7 +6985,8 @@ add_location_to_breakpoint (struct breakpoint *b, gdb_assert (loc->pspace != NULL); loc->section = sal->section; - set_breakpoint_location_function (loc); + set_breakpoint_location_function (loc, + sal->explicit_pc || sal->explicit_line); return loc; } @@ -8346,6 +8512,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 @@ -8360,6 +8527,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 @@ -8371,6 +8539,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 (); @@ -8409,6 +8579,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. */ @@ -8421,6 +8594,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); @@ -8437,6 +8614,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 (), @@ -9564,12 +9742,22 @@ delete_breakpoint (struct breakpoint *bpt) /* At least avoid this stale reference until the reference counting of breakpoints gets resolved. */ - if (bpt->related_breakpoint != NULL) + if (bpt->related_breakpoint != bpt) { - gdb_assert (bpt->related_breakpoint->related_breakpoint == bpt); - bpt->related_breakpoint->disposition = disp_del_at_next_stop; - bpt->related_breakpoint->related_breakpoint = NULL; - bpt->related_breakpoint = NULL; + if (bpt->type == bp_watchpoint_scope) + watchpoint_del_at_next_stop (bpt->related_breakpoint); + else if (bpt->related_breakpoint->type == bp_watchpoint_scope) + watchpoint_del_at_next_stop (bpt); + else + { + struct breakpoint *related; + + /* Unlink bpt from the bpt->related_breakpoint ring. */ + for (related = bpt; related->related_breakpoint != bpt; + related = related->related_breakpoint); + related->related_breakpoint = bpt->related_breakpoint; + bpt->related_breakpoint = bpt; + } } observer_notify_breakpoint_deleted (bpt->number); @@ -9658,6 +9846,7 @@ delete_command (char *arg, int from_tty) && b->type != bp_overlay_event && b->type != bp_longjmp_master && b->type != bp_std_terminate_master + && b->type != bp_exception_master && b->number >= 0) { breaks_to_delete = 1; @@ -9679,6 +9868,7 @@ delete_command (char *arg, int from_tty) && b->type != bp_overlay_event && b->type != bp_longjmp_master && b->type != bp_std_terminate_master + && b->type != bp_exception_master && b->number >= 0) delete_breakpoint (b); } @@ -9887,6 +10077,9 @@ update_breakpoint_locations (struct breakpoint *b, return; b->loc = NULL; + xfree (b->source_file); + b->source_file = NULL; + b->line_number = 0; for (i = 0; i < sals.nelts; ++i) { @@ -9913,11 +10106,7 @@ update_breakpoint_locations (struct breakpoint *b, } } - if (b->source_file != NULL) - xfree (b->source_file); - if (sals.sals[i].symtab == NULL) - b->source_file = NULL; - else + if (sals.sals[i].symtab != NULL && b->source_file == NULL) b->source_file = xstrdup (sals.sals[i].symtab->filename); if (b->line_number == 0) @@ -9999,6 +10188,7 @@ breakpoint_re_set_one (void *bint) case bp_tracepoint: case bp_fast_tracepoint: case bp_static_tracepoint: + case bp_gnu_ifunc_resolver: /* Do not attempt to re-set breakpoints disabled during startup. */ if (b->enable_state == bp_startup_disabled) return 0; @@ -10139,6 +10329,7 @@ breakpoint_re_set_one (void *bint) case bp_overlay_event: case bp_longjmp_master: case bp_std_terminate_master: + case bp_exception_master: delete_breakpoint (b); break; @@ -10162,7 +10353,10 @@ 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: + case bp_gnu_ifunc_resolver_return: break; } @@ -10205,6 +10399,7 @@ breakpoint_re_set (void) create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); create_std_terminate_master_breakpoint ("std::terminate()"); + create_exception_master_breakpoint (); } /* Reset the thread number of this breakpoint: @@ -10334,11 +10529,20 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *, ALL_BREAKPOINTS_SAFE (b, tmp) if (b->number == num) { - struct breakpoint *related_breakpoint = b->related_breakpoint; + struct breakpoint *related_breakpoint; + match = 1; - function (b, data); - if (related_breakpoint) - function (related_breakpoint, data); + related_breakpoint = b; + do + { + struct breakpoint *next_related_b; + + /* FUNCTION can be also delete_breakpoint. */ + next_related_b = related_breakpoint->related_breakpoint; + function (related_breakpoint, data); + related_breakpoint = next_related_b; + } + while (related_breakpoint != b); break; } if (match == 0) @@ -11428,6 +11632,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. @@ -11497,6 +11717,107 @@ save_command (char *arg, int from_tty) help_list (save_cmdlist, "save ", -1, gdb_stdout); } +static void +gnu_ifunc_resolver_stop (struct breakpoint *b) +{ + struct breakpoint *b_return; + struct frame_info *prev_frame = get_prev_frame (get_current_frame ()); + struct frame_id prev_frame_id = get_stack_frame_id (prev_frame); + CORE_ADDR prev_pc = get_frame_pc (prev_frame); + int thread_id = pid_to_thread_id (inferior_ptid); + + gdb_assert (b->type == bp_gnu_ifunc_resolver); + + for (b_return = b->related_breakpoint; b_return != b; + b_return = b_return->related_breakpoint) + { + gdb_assert (b_return->type == bp_gnu_ifunc_resolver_return); + gdb_assert (b_return->loc != NULL && b_return->loc->next == NULL); + gdb_assert (frame_id_p (b_return->frame_id)); + + if (b_return->thread == thread_id + && b_return->loc->requested_address == prev_pc + && frame_id_eq (b_return->frame_id, prev_frame_id)) + break; + } + + if (b_return == b) + { + struct symtab_and_line sal; + + /* No need to call find_pc_line for symbols resolving as this is only + a helper breakpointer never shown to the user. */ + + init_sal (&sal); + sal.pspace = current_inferior ()->pspace; + sal.pc = prev_pc; + sal.section = find_pc_overlay (sal.pc); + sal.explicit_pc = 1; + b_return = set_momentary_breakpoint (get_frame_arch (prev_frame), sal, + prev_frame_id, + bp_gnu_ifunc_resolver_return); + + /* Add new b_return to the ring list b->related_breakpoint. */ + gdb_assert (b_return->related_breakpoint == b_return); + b_return->related_breakpoint = b->related_breakpoint; + b->related_breakpoint = b_return; + } +} + +static void +gnu_ifunc_resolver_return_stop (struct breakpoint *b) +{ + struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); + struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func; + struct type *value_type = TYPE_TARGET_TYPE (func_func_type); + struct regcache *regcache = get_thread_regcache (inferior_ptid); + struct value *value; + CORE_ADDR resolved_address, resolved_pc; + struct symtab_and_line sal; + struct symtabs_and_lines sals; + + gdb_assert (b->type == bp_gnu_ifunc_resolver_return); + + value = allocate_value (value_type); + gdbarch_return_value (gdbarch, func_func_type, value_type, regcache, + value_contents_raw (value), NULL); + resolved_address = value_as_address (value); + resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch, + resolved_address, + ¤t_target); + + while (b->related_breakpoint != b) + { + struct breakpoint *b_next = b->related_breakpoint; + + switch (b->type) + { + case bp_gnu_ifunc_resolver: + break; + case bp_gnu_ifunc_resolver_return: + delete_breakpoint (b); + break; + default: + internal_error (__FILE__, __LINE__, + _("handle_inferior_event: Invalid " + "gnu-indirect-function breakpoint type %d"), + (int) b->type); + } + b = b_next; + } + gdb_assert (b->type == bp_gnu_ifunc_resolver); + + gdb_assert (current_program_space == b->pspace); + gnu_ifunc_record_cache (gdbarch, b->addr_string, resolved_pc); + + sal = find_pc_line (resolved_pc, 0); + sals.nelts = 1; + sals.sals = &sal; + + b->type = bp_breakpoint; + update_breakpoint_locations (b, sals); +} + void _initialize_breakpoint (void) { @@ -12022,4 +12343,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 6f5d050..d0c3cc1 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, @@ -125,6 +132,9 @@ enum bptype /* Master copies of std::terminate breakpoints. */ bp_std_terminate_master, + /* Like bp_longjmp_master, but for exceptions. */ + bp_exception_master, + bp_catchpoint, bp_tracepoint, @@ -133,6 +143,9 @@ enum bptype /* Event for JIT compiled code generation or deletion. */ bp_jit_event, + + bp_gnu_ifunc_resolver, + bp_gnu_ifunc_resolver_return, }; /* States of enablement of breakpoint. */ @@ -653,6 +666,10 @@ struct bpstat_what continuing from a call dummy without popping the frame is not a useful one). */ enum stop_stack_kind 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, diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 926ae2f..a59b965 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -585,7 +585,13 @@ 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_RANGE_DATA (TYPE_INDEX_TYPE (type))->high.kind + != RANGE_BOUND_KIND_CONSTANT) + { + /* No _() - printed sources should not be locale dependent. */ + fprintf_filtered (stream, "variable"); + } + else if (TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0 && !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) fprintf_filtered (stream, "%d", (TYPE_LENGTH (type) diff --git a/gdb/config.in b/gdb/config.in index 1fc457d..f4c846a 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -50,11 +50,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. */ @@ -769,6 +768,9 @@ 'ptrdiff_t'. */ #undef PTRDIFF_T_SUFFIX +/* Define to install path for Python sources */ +#undef PYTHONDIR + /* Define if the python directory should be relocated when GDB is moved. */ #undef PYTHON_PATH_RELOCATABLE diff --git a/gdb/configure b/gdb/configure index 041ffc1..8243abb 100755 --- a/gdb/configure +++ b/gdb/configure @@ -679,6 +679,8 @@ REPORT_BUGS_TO PKGVERSION TARGET_OBS subdirs +pythondir +GDB_DATADIR_PATH GDB_DATADIR DEBUGDIR am__fastdepCC_FALSE @@ -945,6 +947,7 @@ enable_dependency_tracking with_separate_debug_dir with_gdb_datadir with_relocated_sources +with_pythondir enable_targets enable_64_bit_bfd enable_gdbcli @@ -1646,6 +1649,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 @@ -7878,6 +7885,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" @@ -10919,6 +10993,7 @@ $as_echo "#define HAVE_PYTHON 1" >>confdefs.h 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 b69c3b6..4e89558 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 @@ -833,6 +878,7 @@ if test "${have_libpython}" != no; then 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/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 65d4899..96767b0 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1162,6 +1162,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} @@ -14308,6 +14318,7 @@ program. To debug a core dump of a previous run, you must also tell @menu * Files:: Commands to specify files * Separate Debug Files:: Debugging information in separate files +* Index Files:: Index files speed up GDB * Symbol Errors:: Errors reading symbol files * Data Files:: GDB data files @end menu @@ -15197,6 +15208,46 @@ gnu_debuglink_crc32 (unsigned long crc, This computation does not apply to the ``build ID'' method. +@node Index Files +@section Index Files Speed Up @value{GDBN} +@cindex index files +@cindex @samp{.gdb_index} section + +When @value{GDBN} finds a symbol file, it scans the symbols in the +file in order to construct an internal symbol table. This lets most +@value{GDBN} operations work quickly---at the cost of a delay early +on. For large programs, this delay can be quite lengthy, so +@value{GDBN} provides a way to build an index, which speeds up +startup. + +The index is stored as a section in the symbol file. @value{GDBN} can +write the index to a file, then you can put it into the symbol file +using @command{objcopy}. + +To create an index file, use the @code{save gdb-index} command: + +@table @code +@item save gdb-index @var{directory} +@kindex save gdb-index +Create an index file for each symbol file currently known by +@value{GDBN}. Each file is named after its corresponding symbol file, +with @samp{.gdb-index} appended, and is written into the given +@var{directory}. +@end table + +Once you have created an index file you can merge it into your symbol +file, here named @file{symfile}, using @command{objcopy}: + +@smallexample +$ objcopy --add-section .gdb_index=symfile.gdb-index \ + --set-section-flags .gdb_index=readonly symfile symfile +@end smallexample + +There are currently some limitation on indices. They only work when +for DWARF debugging information, not stabs. And, they do not +currently work for programs using Ada. + + @node Symbol Errors @section Errors Reading Symbol Files @@ -20349,8 +20400,6 @@ containing @code{end}. For example: @smallexample (@value{GDBP}) python -Type python script -End with a line saying just "end". >print 23 >end 23 @@ -20363,6 +20412,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 It is also possible to execute a Python script from the @value{GDBN} @@ -20384,6 +20441,14 @@ and thus is always available. @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 @@ -20395,7 +20460,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown. @menu * Basic Python:: Basic Python Functions. * Exception Handling:: -* Values From Inferior:: +* Values From Inferior:: Python representation of values. * Types In Python:: Python representation of types. * Pretty Printing API:: Pretty-printing values. * Selecting Pretty-Printers:: How GDB chooses a pretty-printer. @@ -20456,6 +20521,12 @@ Return a sequence holding all of @value{GDBN}'s breakpoints. @xref{Breakpoints In Python}, for more information. @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 @@ -20472,6 +20543,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 @@ -20496,6 +20568,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. diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 54187dd..320b501 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -2102,6 +2102,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 @@ -2194,6 +2206,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: @@ -2295,6 +2308,7 @@ and partial symbol tables behind a set of function pointers known as the @dfn{quick symbol functions}. These are documented in @file{symfile.h}. +@node Types @section Types @unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}). @@ -2317,6 +2331,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 @@ -2331,6 +2346,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 @@ -2416,6 +2432,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 @@ -2487,6 +2504,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 @@ -2509,6 +2527,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 @@ -2520,10 +2539,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 e19b8ed..343e160 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -223,6 +223,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/dwarf2expr.c b/gdb/dwarf2expr.c index b9ae108..2555908 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -875,6 +875,13 @@ execute_stack_op (struct dwarf_expr_context *ctx, ctx->dwarf_call (ctx, result); 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 61b8f00..d94c03c 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -108,9 +108,15 @@ struct dwarf_expr_context #if 0 /* Not yet implemented. */ + /* Return the location expression for the dwarf expression + subroutine in the die at OFFSET in the current compilation unit. + 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 f59bc40..7ff0ef9 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -48,6 +48,12 @@ static void dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, const gdb_byte **start, size_t *length); +static struct value *dwarf2_evaluate_loc_desc (struct type *type, + struct frame_info *frame, + const gdb_byte *data, + unsigned short size, + struct dwarf2_per_cu_data *per_cu); + /* A helper function for dealing with location lists. Given a symbol baton (BATON) and a pc value (PC), find the appropriate location expression, set *LOCEXPR_LENGTH, and return a pointer @@ -127,6 +133,9 @@ struct dwarf_expr_baton { struct frame_info *frame; struct dwarf2_per_cu_data *per_cu; + /* 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. */ @@ -195,23 +204,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 @@ -263,6 +282,158 @@ dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, size_t die_offset) return per_cu_dwarf_call (ctx, die_offset, debaton->per_cu); } +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, const gdb_byte *data, + size_t size, struct dwarf2_per_cu_data *per_cu) +{ + struct dwarf_expr_context *ctx; + struct dwarf_expr_baton baton; + struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); + + baton.frame = frame; + baton.per_cu = per_cu; + baton.object_address = object_address; + + ctx = new_dwarf_expr_context (); + make_cleanup_free_dwarf_expr_context (ctx); + + ctx->gdbarch = get_objfile_arch (objfile); + ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->offset = dwarf2_per_cu_text_offset (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_call = dwarf_expr_dwarf_call; + 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 (get_selected_frame (NULL), dlbaton->data, + dlbaton->size, dlbaton->per_cu); + if (ctx->num_pieces > 0) + error (_("DW_OP_*piece is unsupported for DW_FORM_block")); + + retval = dwarf_expr_fetch (ctx, 0); + + if (ctx->location == DWARF_VALUE_REGISTER) + { + /* Inlined dwarf_expr_read_reg as we no longer have the baton. */ + + int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (ctx->gdbarch, retval); + struct type *type = builtin_type (ctx->gdbarch)->builtin_data_ptr; + struct frame_info *frame = get_selected_frame (NULL); + + retval = address_from_register (type, gdb_regnum, frame); + } + + do_cleanups (back_to); + + return retval; +} + +/* Evaluate DWARF location list at DLLBATON expecting it produces exactly one + CORE_ADDR result stored to *ADDRP on the DWARF stack stack. If the result + could not be found return zero and keep *ADDRP unchanged. */ + +int +dwarf_loclist_baton_eval (struct dwarf2_loclist_baton *dllbaton, + struct type *type, CORE_ADDR *addrp) +{ + struct frame_info *frame = get_selected_frame (NULL); + const gdb_byte *data; + size_t size; + struct value *val; + + if (!dllbaton) + return 0; + + data = find_location_expression (dllbaton, &size, + get_frame_address_in_block (frame)); + if (data == NULL) + return 0; + + val = dwarf2_evaluate_loc_desc (type, frame, data, size, dllbaton->per_cu); + if (value_optimized_out (val)) + return 0; + + *addrp = value_as_address (val); + return 1; +} + struct piece_closure { /* Reference count. */ @@ -887,10 +1058,8 @@ dwarf2_evaluate_loc_desc (struct type *type, 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 objfile *objfile = dwarf2_per_cu_objfile (per_cu); + struct cleanup *old_chain = make_cleanup (null_cleanup, 0); if (size == 0) { @@ -900,24 +1069,8 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, return retval; } - baton.frame = frame; - baton.per_cu = per_cu; + ctx = dwarf_expr_prep_ctx (frame, data, size, per_cu); - ctx = new_dwarf_expr_context (); - old_chain = make_cleanup_free_dwarf_expr_context (ctx); - - ctx->gdbarch = get_objfile_arch (objfile); - ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); - ctx->offset = dwarf2_per_cu_text_offset (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_call = dwarf_expr_dwarf_call; - - dwarf_expr_eval (ctx, data, size); if (ctx->num_pieces > 0) { struct piece_closure *c; @@ -951,6 +1104,11 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, CORE_ADDR address = dwarf_expr_fetch_address (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 (type); VALUE_LVAL (retval) = lval_memory; set_value_lazy (retval, 1); @@ -2590,11 +2748,51 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch, dlbaton->per_cu); } -/* 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 void +missing_describe_location (struct symbol *symbol, CORE_ADDR addr, + struct ui_file *stream) +{ + fprintf_filtered (stream, _("a variable we are unable to resolve")); +} + +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 826bc45..1e7d8dc 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -86,5 +86,14 @@ 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); + +extern int dwarf_loclist_baton_eval (struct dwarf2_loclist_baton *dllbaton, + struct type *type, CORE_ADDR *addrp); #endif /* dwarf2loc.h */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 1e75235..d54e266 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -51,6 +51,9 @@ #include "typeprint.h" #include "jv-lang.h" #include "psympriv.h" +#include "exceptions.h" +#include "gdb_stat.h" +#include "completer.h" #include #include "gdb_string.h" @@ -129,6 +132,33 @@ struct dwarf2_section_info int readin; }; +/* All offsets in the index are of this type. It must be + architecture-independent. */ +typedef uint32_t offset_type; + +DEF_VEC_I (offset_type); + +/* A description of the mapped index. The file format is described in + a comment by the code that writes the index. */ +struct mapped_index +{ + /* The total length of the buffer. */ + off_t total_size; + /* A pointer to the address table data. */ + const gdb_byte *address_table; + /* Size of the address table data in bytes. */ + offset_type address_table_size; + /* The hash table. */ + const offset_type *index_table; + /* Size in slots, each slot is 2 offset_types. */ + offset_type index_table_slots; + /* A pointer to the constant pool. */ + const char *constant_pool; +}; + +typedef struct dwarf2_per_cu_data *dwarf2_per_cu_data_ptr; +DEF_VEC_P (dwarf2_per_cu_data_ptr); + struct dwarf2_per_objfile { struct dwarf2_section_info info; @@ -141,6 +171,7 @@ struct dwarf2_per_objfile struct dwarf2_section_info types; struct dwarf2_section_info frame; struct dwarf2_section_info eh_frame; + struct dwarf2_section_info gdb_index; /* Back link. */ struct objfile *objfile; @@ -163,6 +194,12 @@ struct dwarf2_per_objfile /* A flag indicating wether this objfile has a section loaded at a VMA of 0. */ int has_section_at_zero; + + /* True if we are using the mapped index. */ + unsigned char using_index; + + /* The mapped index. */ + struct mapped_index *index_table; }; static struct dwarf2_per_objfile *dwarf2_per_objfile; @@ -182,6 +219,7 @@ static struct dwarf2_per_objfile *dwarf2_per_objfile; #define TYPES_SECTION "debug_types" #define FRAME_SECTION "debug_frame" #define EH_FRAME_SECTION "eh_frame" +#define GDB_INDEX_SECTION "gdb_index" /* local data types */ @@ -307,6 +345,32 @@ struct dwarf2_cu unsigned int has_namespace_info : 1; }; +/* When using the index (and thus not using psymtabs), each CU has an + object of this type. This is used to hold information needed by + the various "quick" methods. */ +struct dwarf2_per_cu_quick_data +{ + /* The line table. This can be NULL if there was no line table. */ + struct line_header *lines; + + /* The file names from the line table. */ + const char **file_names; + /* The file names from the line table after being run through + gdb_realpath. */ + const char **full_names; + + /* The corresponding symbol table. This is NULL if symbols for this + CU have not yet been read. */ + struct symtab *symtab; + + /* A temporary mark bit used when iterating over all CUs in + expand_symtabs_matching. */ + unsigned int mark : 1; + + /* True if we've tried to read the line table. */ + unsigned int read_lines : 1; +}; + /* Persistent data held for a compilation unit, even when not processing it. We put a pointer to this structure in the read_symtab_private field of the psymtab. If we encounter @@ -347,10 +411,21 @@ struct dwarf2_per_cu_data it. */ htab_t type_hash; - /* The partial symbol table associated with this compilation unit, - or NULL for partial units (which do not have an associated - symtab). */ - struct partial_symtab *psymtab; + /* The corresponding objfile. */ + struct objfile *objfile; + + /* When using partial symbol tables, the 'psymtab' field is active. + Otherwise the 'quick' field is active. */ + union + { + /* The partial symbol table associated with this compilation unit, + or NULL for partial units (which do not have an associated + symtab). */ + struct partial_symtab *psymtab; + + /* Data needed by the "quick" functions. */ + struct dwarf2_per_cu_quick_data *quick; + } v; }; /* Entry in the signatured_types hash table. */ @@ -1083,6 +1158,9 @@ static int attr_form_is_section_offset (struct attribute *); static int attr_form_is_constant (struct attribute *); +static struct dwarf2_loclist_baton *dwarf2_attr_to_loclist_baton + (struct attribute *attr, struct dwarf2_cu *cu); + static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); @@ -1113,6 +1191,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 *); @@ -1132,6 +1213,56 @@ 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 struct dwarf2_locexpr_baton *dwarf2_attr_to_locexpr_baton + (struct attribute *attr, struct dwarf2_cu *cu); + +static void dwarf2_release_queue (void *dummy); + +static void queue_comp_unit (struct dwarf2_per_cu_data *per_cu, + struct objfile *objfile); + +static void process_queue (struct objfile *objfile); + +static void find_file_and_directory (struct die_info *die, + struct dwarf2_cu *cu, + char **name, char **comp_dir); + +static char *file_full_name (int file, struct line_header *lh, + const char *comp_dir); + +static gdb_byte *partial_read_comp_unit_head (struct comp_unit_head *header, + gdb_byte *info_ptr, + gdb_byte *buffer, + unsigned int buffer_size, + bfd *abfd); + +static void init_cu_die_reader (struct die_reader_specs *reader, + struct dwarf2_cu *cu); + +#if WORDS_BIGENDIAN + +/* Convert VALUE between big- and little-endian. */ +static offset_type +byte_swap (offset_type value) +{ + offset_type result; + + result = (value & 0xff) << 24; + result |= (value & 0xff00) << 8; + result |= (value & 0xff0000) >> 8; + result |= (value & 0xff000000) >> 24; + return result; +} + +#define MAYBE_SWAP(V) byte_swap (V) + +#else +#define MAYBE_SWAP(V) (V) +#endif /* WORDS_BIGENDIAN */ + +/* The suffix for an index file. */ +#define INDEX_SUFFIX ".gdb-index" + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ @@ -1230,6 +1361,11 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr) dwarf2_per_objfile->types.asection = sectp; dwarf2_per_objfile->types.size = bfd_get_section_size (sectp); } + else if (section_is_p (sectp->name, GDB_INDEX_SECTION)) + { + dwarf2_per_objfile->gdb_index.asection = sectp; + dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp); + } if ((bfd_get_section_flags (abfd, sectp) & SEC_LOAD) && bfd_section_vma (abfd, sectp) == 0) @@ -1353,87 +1489,940 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) if (pagesize == 0) pagesize = getpagesize (); - /* Only try to mmap sections which are large enough: we don't want to - waste space due to fragmentation. Also, only try mmap for sections - without relocations. */ + /* Only try to mmap sections which are large enough: we don't want to + waste space due to fragmentation. Also, only try mmap for sections + without relocations. */ + + if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0) + { + off_t pg_offset = sectp->filepos & ~(pagesize - 1); + size_t map_length = info->size + sectp->filepos - pg_offset; + caddr_t retbuf = bfd_mmap (abfd, 0, map_length, PROT_READ, + MAP_PRIVATE, pg_offset); + + if (retbuf != MAP_FAILED) + { + info->was_mmapped = 1; + info->buffer = retbuf + (sectp->filepos & (pagesize - 1)) ; +#if HAVE_POSIX_MADVISE + posix_madvise (retbuf, map_length, POSIX_MADV_WILLNEED); +#endif + return; + } + } +#endif + + /* If we get here, we are a normal, not-compressed section. */ + info->buffer = buf + = obstack_alloc (&objfile->objfile_obstack, info->size); + + /* When debugging .o files, we may need to apply relocations; see + http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . + We never compress sections in .o files, so we only need to + try this when the section is not compressed. */ + retbuf = symfile_relocate_debug_section (objfile, sectp, buf); + if (retbuf != NULL) + { + info->buffer = retbuf; + return; + } + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (buf, info->size, abfd) != info->size) + error (_("Dwarf Error: Can't read DWARF data from '%s'"), + bfd_get_filename (abfd)); +} + +/* Fill in SECTP, BUFP and SIZEP with section info, given OBJFILE and + SECTION_NAME. */ + +void +dwarf2_get_section_info (struct objfile *objfile, const char *section_name, + asection **sectp, gdb_byte **bufp, + bfd_size_type *sizep) +{ + struct dwarf2_per_objfile *data + = objfile_data (objfile, dwarf2_objfile_data_key); + struct dwarf2_section_info *info; + + /* We may see an objfile without any DWARF, in which case we just + return nothing. */ + if (data == NULL) + { + *sectp = NULL; + *bufp = NULL; + *sizep = 0; + return; + } + if (section_is_p (section_name, EH_FRAME_SECTION)) + info = &data->eh_frame; + else if (section_is_p (section_name, FRAME_SECTION)) + info = &data->frame; + else + gdb_assert (0); + + if (info->asection != NULL && info->size != 0 && info->buffer == NULL) + /* We haven't read this section in yet. Do it now. */ + dwarf2_read_section (objfile, info); + + *sectp = info->asection; + *bufp = info->buffer; + *sizep = info->size; +} + + + +/* Read in the symbols for PER_CU. OBJFILE is the objfile from which + this CU came. */ +static void +dw2_do_instantiate_symtab (struct objfile *objfile, + struct dwarf2_per_cu_data *per_cu) +{ + struct cleanup *back_to; + + back_to = make_cleanup (dwarf2_release_queue, NULL); + + queue_comp_unit (per_cu, objfile); + + if (per_cu->from_debug_types) + read_signatured_type_at_offset (objfile, per_cu->offset); + else + load_full_comp_unit (per_cu, objfile); + + process_queue (objfile); + + /* Age the cache, releasing compilation units that have not + been used recently. */ + age_cached_comp_units (); + + do_cleanups (back_to); +} + +/* Ensure that the symbols for PER_CU have been read in. OBJFILE is + the objfile from which this CU came. Returns the resulting symbol + table. */ +static struct symtab * +dw2_instantiate_symtab (struct objfile *objfile, + struct dwarf2_per_cu_data *per_cu) +{ + if (!per_cu->v.quick->symtab) + { + struct cleanup *back_to = make_cleanup (free_cached_comp_units, NULL); + increment_reading_symtab (); + dw2_do_instantiate_symtab (objfile, per_cu); + do_cleanups (back_to); + } + return per_cu->v.quick->symtab; +} + +/* A helper function that knows how to read a 64-bit value in a way + that doesn't make gdb die. Returns 1 if the conversion went ok, 0 + otherwise. */ +static int +extract_cu_value (const char *bytes, ULONGEST *result) +{ + if (sizeof (ULONGEST) < 8) + { + int i; + + /* Ignore the upper 4 bytes if they are all zero. */ + for (i = 0; i < 4; ++i) + if (bytes[i + 4] != 0) + return 0; + + *result = extract_unsigned_integer (bytes, 4, BFD_ENDIAN_LITTLE); + } + else + *result = extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE); + return 1; +} + +/* Read the CU list from the mapped index, and use it to create all + the CU objects for this objfile. Return 0 if something went wrong, + 1 if everything went ok. */ +static int +create_cus_from_index (struct objfile *objfile, struct mapped_index *index, + const gdb_byte *cu_list, offset_type cu_list_elements) +{ + offset_type i; + const char *entry; + + dwarf2_per_objfile->n_comp_units = cu_list_elements / 2; + dwarf2_per_objfile->all_comp_units + = obstack_alloc (&objfile->objfile_obstack, + dwarf2_per_objfile->n_comp_units + * sizeof (struct dwarf2_per_cu_data *)); + + for (i = 0; i < cu_list_elements; i += 2) + { + struct dwarf2_per_cu_data *the_cu; + ULONGEST offset, length; + + if (!extract_cu_value (cu_list, &offset) + || !extract_cu_value (cu_list + 8, &length)) + return 0; + cu_list += 2 * 8; + + the_cu = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_per_cu_data); + the_cu->offset = offset; + the_cu->length = length; + the_cu->objfile = objfile; + the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_per_cu_quick_data); + dwarf2_per_objfile->all_comp_units[i / 2] = the_cu; + } + + return 1; +} + +/* Read the address map data from the mapped index, and use it to + populate the objfile's psymtabs_addrmap. */ +static void +create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index) +{ + const gdb_byte *iter, *end; + struct obstack temp_obstack; + struct addrmap *mutable_map; + struct cleanup *cleanup; + CORE_ADDR baseaddr; + + obstack_init (&temp_obstack); + cleanup = make_cleanup_obstack_free (&temp_obstack); + mutable_map = addrmap_create_mutable (&temp_obstack); + + iter = index->address_table; + end = iter + index->address_table_size; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + while (iter < end) + { + ULONGEST hi, lo, cu_index; + lo = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE); + iter += 8; + hi = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE); + iter += 8; + cu_index = extract_unsigned_integer (iter, 4, BFD_ENDIAN_LITTLE); + iter += 4; + + addrmap_set_empty (mutable_map, lo + baseaddr, hi + baseaddr - 1, + dwarf2_per_objfile->all_comp_units[cu_index]); + } + + objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map, + &objfile->objfile_obstack); + do_cleanups (cleanup); +} + +/* The hash function for strings in the mapped index. This is the + same as the hashtab.c hash function, but we keep a separate copy to + maintain control over the implementation. This is necessary + because the hash function is tied to the format of the mapped index + file. */ +static hashval_t +mapped_index_string_hash (const void *p) +{ + const unsigned char *str = (const unsigned char *) p; + hashval_t r = 0; + unsigned char c; + + while ((c = *str++) != 0) + r = r * 67 + c - 113; + + return r; +} + +/* Find a slot in the mapped index INDEX for the object named NAME. + If NAME is found, set *VEC_OUT to point to the CU vector in the + constant pool and return 1. If NAME cannot be found, return 0. */ +static int +find_slot_in_mapped_hash (struct mapped_index *index, const char *name, + offset_type **vec_out) +{ + offset_type hash = mapped_index_string_hash (name); + offset_type slot, step; + + slot = hash & (index->index_table_slots - 1); + step = ((hash * 17) & (index->index_table_slots - 1)) | 1; + + for (;;) + { + /* Convert a slot number to an offset into the table. */ + offset_type i = 2 * slot; + const char *str; + if (index->index_table[i] == 0 && index->index_table[i + 1] == 0) + return 0; + + str = index->constant_pool + MAYBE_SWAP (index->index_table[i]); + if (!strcmp (name, str)) + { + *vec_out = (offset_type *) (index->constant_pool + + MAYBE_SWAP (index->index_table[i + 1])); + return 1; + } + + slot = (slot + step) & (index->index_table_slots - 1); + } +} + +/* Read the index file. If everything went ok, initialize the "quick" + elements of all the CUs and return 1. Otherwise, return 0. */ +static int +dwarf2_read_index (struct objfile *objfile) +{ + char *addr; + struct mapped_index *map; + offset_type *metadata; + const gdb_byte *cu_list; + offset_type cu_list_elements; + + if (dwarf2_per_objfile->gdb_index.asection == NULL + || dwarf2_per_objfile->gdb_index.size == 0) + return 0; + dwarf2_read_section (objfile, &dwarf2_per_objfile->gdb_index); + + addr = dwarf2_per_objfile->gdb_index.buffer; + /* Version check. */ + if (MAYBE_SWAP (*(offset_type *) addr) != 1) + return 0; + + map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index); + map->total_size = dwarf2_per_objfile->gdb_index.size; + + metadata = (offset_type *) (addr + sizeof (offset_type)); + cu_list = addr + MAYBE_SWAP (metadata[0]); + cu_list_elements = ((MAYBE_SWAP (metadata[1]) - MAYBE_SWAP (metadata[0])) + / 8); + map->address_table = addr + MAYBE_SWAP (metadata[1]); + map->address_table_size = (MAYBE_SWAP (metadata[2]) + - MAYBE_SWAP (metadata[1])); + map->index_table = (offset_type *) (addr + MAYBE_SWAP (metadata[2])); + map->index_table_slots = ((MAYBE_SWAP (metadata[3]) + - MAYBE_SWAP (metadata[2])) + / (2 * sizeof (offset_type))); + map->constant_pool = addr + MAYBE_SWAP (metadata[3]); + + if (!create_cus_from_index (objfile, map, cu_list, cu_list_elements)) + return 0; + + create_addrmap_from_index (objfile, map); + + dwarf2_per_objfile->index_table = map; + dwarf2_per_objfile->using_index = 1; + + return 1; +} + +/* A helper for the "quick" functions which sets the global + dwarf2_per_objfile according to OBJFILE. */ +static void +dw2_setup (struct objfile *objfile) +{ + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); + gdb_assert (dwarf2_per_objfile); +} + +/* A helper for the "quick" functions which attempts to read the line + table for THIS_CU. */ +static void +dw2_require_line_header (struct objfile *objfile, + struct dwarf2_per_cu_data *this_cu) +{ + bfd *abfd = objfile->obfd; + struct line_header *lh = NULL; + struct attribute *attr; + struct cleanup *cleanups; + struct die_info *comp_unit_die; + gdb_byte *beg_of_comp_unit, *info_ptr, *buffer; + int has_children, i; + struct dwarf2_cu cu; + unsigned int bytes_read, buffer_size; + struct die_reader_specs reader_specs; + char *name, *comp_dir; + + if (this_cu->v.quick->read_lines) + return; + this_cu->v.quick->read_lines = 1; + + memset (&cu, 0, sizeof (cu)); + cu.objfile = objfile; + obstack_init (&cu.comp_unit_obstack); + + cleanups = make_cleanup (free_stack_comp_unit, &cu); + + dwarf2_read_section (objfile, &dwarf2_per_objfile->info); + buffer_size = dwarf2_per_objfile->info.size; + buffer = dwarf2_per_objfile->info.buffer; + info_ptr = buffer + this_cu->offset; + beg_of_comp_unit = info_ptr; + + info_ptr = partial_read_comp_unit_head (&cu.header, info_ptr, + buffer, buffer_size, + abfd); + + /* Complete the cu_header. */ + cu.header.offset = beg_of_comp_unit - buffer; + cu.header.first_die_offset = info_ptr - beg_of_comp_unit; + + this_cu->cu = &cu; + cu.per_cu = this_cu; + + dwarf2_read_abbrevs (abfd, &cu); + make_cleanup (dwarf2_free_abbrev_table, &cu); + + if (this_cu->from_debug_types) + info_ptr += 8 /*signature*/ + cu.header.offset_size; + init_cu_die_reader (&reader_specs, &cu); + info_ptr = read_full_die (&reader_specs, &comp_unit_die, info_ptr, + &has_children); + + attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, &cu); + if (attr) + { + unsigned int line_offset = DW_UNSND (attr); + lh = dwarf_decode_line_header (line_offset, abfd, &cu); + } + if (lh == NULL) + { + do_cleanups (cleanups); + return; + } + + find_file_and_directory (comp_unit_die, &cu, &name, &comp_dir); + + this_cu->v.quick->lines = lh; + + this_cu->v.quick->file_names + = obstack_alloc (&objfile->objfile_obstack, + lh->num_file_names * sizeof (char *)); + for (i = 0; i < lh->num_file_names; ++i) + this_cu->v.quick->file_names[i] = file_full_name (i + 1, lh, comp_dir); + + do_cleanups (cleanups); +} + +/* A helper for the "quick" functions which computes and caches the + real path for a given file name from the line table. + dw2_require_line_header must have been called before this is + invoked. */ +static const char * +dw2_require_full_path (struct objfile *objfile, + struct dwarf2_per_cu_data *cu, + int index) +{ + if (!cu->v.quick->full_names) + cu->v.quick->full_names + = OBSTACK_CALLOC (&objfile->objfile_obstack, + cu->v.quick->lines->num_file_names, + sizeof (char *)); + + if (!cu->v.quick->full_names[index]) + cu->v.quick->full_names[index] + = gdb_realpath (cu->v.quick->file_names[index]); + + return cu->v.quick->full_names[index]; +} + +static struct symtab * +dw2_find_last_source_symtab (struct objfile *objfile) +{ + int index; + dw2_setup (objfile); + index = dwarf2_per_objfile->n_comp_units - 1; + return dw2_instantiate_symtab (objfile, + dwarf2_per_objfile->all_comp_units[index]); +} + +static void +dw2_forget_cached_source_info (struct objfile *objfile) +{ + int i; + + dw2_setup (objfile); + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (cu->v.quick->full_names) + { + int j; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + xfree ((void *) cu->v.quick->full_names[j]); + } + } +} + +static int +dw2_lookup_symtab (struct objfile *objfile, const char *name, + const char *full_path, const char *real_path, + struct symtab **result) +{ + int i; + int check_basename = lbasename (name) == name; + struct dwarf2_per_cu_data *base_cu = NULL; + + dw2_setup (objfile); + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (cu->v.quick->symtab) + continue; + + dw2_require_line_header (objfile, cu); + if (!cu->v.quick->lines) + continue; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + { + const char *this_name = cu->v.quick->file_names[j]; + + if (FILENAME_CMP (name, this_name) == 0) + { + *result = dw2_instantiate_symtab (objfile, cu); + return 1; + } + + if (check_basename && ! base_cu + && FILENAME_CMP (lbasename (this_name), name) == 0) + base_cu = cu; + + if (full_path != NULL) + { + const char *this_full_name = dw2_require_full_path (objfile, + cu, j); + + if (this_full_name + && FILENAME_CMP (full_path, this_full_name) == 0) + { + *result = dw2_instantiate_symtab (objfile, cu); + return 1; + } + } + + if (real_path != NULL) + { + const char *this_full_name = dw2_require_full_path (objfile, + cu, j); + + if (this_full_name != NULL) + { + char *rp = gdb_realpath (this_full_name); + if (rp != NULL && FILENAME_CMP (real_path, rp) == 0) + { + xfree (rp); + *result = dw2_instantiate_symtab (objfile, cu); + return 1; + } + xfree (rp); + } + } + } + } + + if (base_cu) + { + *result = dw2_instantiate_symtab (objfile, base_cu); + return 1; + } + + return 0; +} + +static struct symtab * +dw2_lookup_symbol (struct objfile *objfile, int block_index, + const char *name, domain_enum domain) +{ + /* We do all the work in the pre_expand_symtabs_matching hook + instead. */ + return NULL; +} + +/* A helper function that expands all symtabs that hold an object + named NAME. */ +static void +dw2_do_expand_symtabs_matching (struct objfile *objfile, const char *name) +{ + dw2_setup (objfile); + + if (dwarf2_per_objfile->index_table) + { + offset_type *vec; + + if (find_slot_in_mapped_hash (dwarf2_per_objfile->index_table, + name, &vec)) + { + offset_type i, len = MAYBE_SWAP (*vec); + for (i = 0; i < len; ++i) + { + offset_type cu_index = MAYBE_SWAP (vec[i + 1]); + struct dwarf2_per_cu_data *cu; + cu = dwarf2_per_objfile->all_comp_units[cu_index]; + dw2_instantiate_symtab (objfile, cu); + } + } + } +} + +static void +dw2_pre_expand_symtabs_matching (struct objfile *objfile, + int kind, const char *name, + domain_enum domain) +{ + dw2_do_expand_symtabs_matching (objfile, name); +} + +static void +dw2_print_stats (struct objfile *objfile) +{ + int i, count; + + dw2_setup (objfile); + count = 0; + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (!cu->v.quick->symtab) + ++count; + } + printf_filtered (_(" Number of unread CUs: %d\n"), count); +} + +static void +dw2_dump (struct objfile *objfile) +{ + /* Nothing worth printing. */ +} + +static void +dw2_relocate (struct objfile *objfile, struct section_offsets *new_offsets, + struct section_offsets *delta) +{ + /* There's nothing to relocate here. */ +} + +static void +dw2_expand_symtabs_for_function (struct objfile *objfile, + const char *func_name) +{ + dw2_do_expand_symtabs_matching (objfile, func_name); +} + +static void +dw2_expand_all_symtabs (struct objfile *objfile) +{ + int i; + + dw2_setup (objfile); + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + dw2_instantiate_symtab (objfile, cu); + } +} + +static void +dw2_expand_symtabs_with_filename (struct objfile *objfile, + const char *filename) +{ + int i; + + dw2_setup (objfile); + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (cu->v.quick->symtab) + continue; + + dw2_require_line_header (objfile, cu); + if (!cu->v.quick->lines) + continue; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + { + const char *this_name = cu->v.quick->file_names[j]; + if (strcmp (this_name, filename) == 0) + { + dw2_instantiate_symtab (objfile, cu); + break; + } + } + } +} + +static const char * +dw2_find_symbol_file (struct objfile *objfile, const char *name) +{ + struct dwarf2_per_cu_data *cu; + offset_type *vec; + + dw2_setup (objfile); + + if (!dwarf2_per_objfile->index_table) + return NULL; + + if (!find_slot_in_mapped_hash (dwarf2_per_objfile->index_table, + name, &vec)) + return NULL; + + /* Note that this just looks at the very first one named NAME -- but + actually we are looking for a function. find_main_filename + should be rewritten so that it doesn't require a custom hook. It + could just use the ordinary symbol tables. */ + /* vec[0] is the length, which must always be >0. */ + cu = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[1])]; + + dw2_require_line_header (objfile, cu); + if (!cu->v.quick->lines) + return NULL; + + return cu->v.quick->file_names[cu->v.quick->lines->num_file_names - 1]; +} + +static void +dw2_map_ada_symtabs (struct objfile *objfile, + int (*wild_match) (const char *, int, const char *), + int (*is_name_suffix) (const char *), + void (*callback) (struct objfile *, + struct symtab *, void *), + const char *name, int global, + domain_enum namespace, int wild, + void *data) +{ + /* For now, we don't support Ada, so this function can't be + reached. */ + internal_error (__FILE__, __LINE__, + _("map_ada_symtabs called via index method")); +} + +static void +dw2_expand_symtabs_matching (struct objfile *objfile, + int (*file_matcher) (const char *, void *), + int (*name_matcher) (const char *, void *), + domain_enum kind, + void *data) +{ + int i; + offset_type iter; + + dw2_setup (objfile); + if (!dwarf2_per_objfile->index_table) + return; + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + cu->v.quick->mark = 0; + if (cu->v.quick->symtab) + continue; + + dw2_require_line_header (objfile, cu); + if (!cu->v.quick->lines) + continue; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + { + if (file_matcher (cu->v.quick->file_names[j], data)) + { + cu->v.quick->mark = 1; + break; + } + } + } + + for (iter = 0; + iter < dwarf2_per_objfile->index_table->index_table_slots; + ++iter) + { + offset_type idx = 2 * iter; + const char *name; + offset_type *vec, vec_len, vec_idx; + + if (dwarf2_per_objfile->index_table->index_table[idx] == 0 + && dwarf2_per_objfile->index_table->index_table[idx + 1] == 0) + continue; + + name = (dwarf2_per_objfile->index_table->constant_pool + + dwarf2_per_objfile->index_table->index_table[idx]); + + if (! (*name_matcher) (name, data)) + continue; + + /* The name was matched, now expand corresponding CUs that were + marked. */ + vec = (offset_type *) (dwarf2_per_objfile->index_table->constant_pool + + dwarf2_per_objfile->index_table->index_table[idx + 1]); + vec_len = MAYBE_SWAP (vec[0]); + for (vec_idx = 0; vec_idx < vec_len; ++vec_idx) + { + struct dwarf2_per_cu_data *cu + = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[vec_idx + 1])]; + if (cu->v.quick->mark) + dw2_instantiate_symtab (objfile, cu); + } + } +} + +static struct symtab * +dw2_find_pc_sect_symtab (struct objfile *objfile, + struct minimal_symbol *msymbol, + CORE_ADDR pc, + struct obj_section *section, + int warn_if_readin) +{ + struct dwarf2_per_cu_data *data; + + dw2_setup (objfile); + + if (!objfile->psymtabs_addrmap) + return NULL; + + data = addrmap_find (objfile->psymtabs_addrmap, pc); + if (!data) + return NULL; + + if (warn_if_readin && data->v.quick->symtab) + warning (_("(Internal error: pc %s in read in CU, but not in symtab.)\n"), + paddress (get_objfile_arch (objfile), pc)); + + return dw2_instantiate_symtab (objfile, data); +} + +static void +dw2_map_symbol_names (struct objfile *objfile, + void (*fun) (const char *, void *), + void *data) +{ + offset_type iter; + dw2_setup (objfile); - if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0) + if (!dwarf2_per_objfile->index_table) + return; + + for (iter = 0; + iter < dwarf2_per_objfile->index_table->index_table_slots; + ++iter) { - off_t pg_offset = sectp->filepos & ~(pagesize - 1); - size_t map_length = info->size + sectp->filepos - pg_offset; - caddr_t retbuf = bfd_mmap (abfd, 0, map_length, PROT_READ, - MAP_PRIVATE, pg_offset); + offset_type idx = 2 * iter; + const char *name; + offset_type *vec, vec_len, vec_idx; - if (retbuf != MAP_FAILED) - { - info->was_mmapped = 1; - info->buffer = retbuf + (sectp->filepos & (pagesize - 1)) ; -#if HAVE_POSIX_MADVISE - posix_madvise (retbuf, map_length, POSIX_MADV_WILLNEED); -#endif - return; - } + if (dwarf2_per_objfile->index_table->index_table[idx] == 0 + && dwarf2_per_objfile->index_table->index_table[idx + 1] == 0) + continue; + + name = (dwarf2_per_objfile->index_table->constant_pool + + dwarf2_per_objfile->index_table->index_table[idx]); + + (*fun) (name, data); } -#endif +} - /* If we get here, we are a normal, not-compressed section. */ - info->buffer = buf - = obstack_alloc (&objfile->objfile_obstack, info->size); +static void +dw2_map_symbol_filenames (struct objfile *objfile, + void (*fun) (const char *, const char *, void *), + void *data) +{ + int i; - /* When debugging .o files, we may need to apply relocations; see - http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . - We never compress sections in .o files, so we only need to - try this when the section is not compressed. */ - retbuf = symfile_relocate_debug_section (objfile, sectp, buf); - if (retbuf != NULL) + dw2_setup (objfile); + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) { - info->buffer = retbuf; - return; + int j; + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (cu->v.quick->symtab) + continue; + + dw2_require_line_header (objfile, cu); + if (!cu->v.quick->lines) + continue; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + { + const char *this_full_name = dw2_require_full_path (objfile, cu, j); + (*fun) (cu->v.quick->file_names[j], this_full_name, data); + } } +} - if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 - || bfd_bread (buf, info->size, abfd) != info->size) - error (_("Dwarf Error: Can't read DWARF data from '%s'"), - bfd_get_filename (abfd)); +static int +dw2_has_symbols (struct objfile *objfile) +{ + return 1; } -/* Fill in SECTP, BUFP and SIZEP with section info, given OBJFILE and - SECTION_NAME. */ +const struct quick_symbol_functions dwarf2_gdb_index_functions = +{ + dw2_has_symbols, + dw2_find_last_source_symtab, + dw2_forget_cached_source_info, + dw2_lookup_symtab, + dw2_lookup_symbol, + dw2_pre_expand_symtabs_matching, + dw2_print_stats, + dw2_dump, + dw2_relocate, + dw2_expand_symtabs_for_function, + dw2_expand_all_symtabs, + dw2_expand_symtabs_with_filename, + dw2_find_symbol_file, + dw2_map_ada_symtabs, + dw2_expand_symtabs_matching, + dw2_find_pc_sect_symtab, + dw2_map_symbol_names, + dw2_map_symbol_filenames +}; -void -dwarf2_get_section_info (struct objfile *objfile, const char *section_name, - asection **sectp, gdb_byte **bufp, - bfd_size_type *sizep) -{ - struct dwarf2_per_objfile *data - = objfile_data (objfile, dwarf2_objfile_data_key); - struct dwarf2_section_info *info; +/* Initialize for reading DWARF for this objfile. Return 0 if this + file will use psymtabs, or 1 if using the GNU index. */ - /* We may see an objfile without any DWARF, in which case we just - return nothing. */ - if (data == NULL) +int +dwarf2_initialize_objfile (struct objfile *objfile) +{ + /* If we're about to read full symbols, don't bother with the + indices. In this case we also don't care if some other debug + format is making psymtabs, because they are all about to be + expanded anyway. */ + if ((objfile->flags & OBJF_READNOW)) { - *sectp = NULL; - *bufp = NULL; - *sizep = 0; - return; + int i; + + dwarf2_per_objfile->using_index = 1; + create_all_comp_units (objfile); + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_per_cu_quick_data); + } + + /* Return 1 so that gdb sees the "quick" functions. However, + these functions will be no-ops because we will have expanded + all symtabs. */ + return 1; } - if (section_is_p (section_name, EH_FRAME_SECTION)) - info = &data->eh_frame; - else if (section_is_p (section_name, FRAME_SECTION)) - info = &data->frame; - else - gdb_assert (0); - if (info->asection != NULL && info->size != 0 && info->buffer == NULL) - /* We haven't read this section in yet. Do it now. */ - dwarf2_read_section (objfile, info); + if (dwarf2_read_index (objfile)) + return 1; - *sectp = info->asection; - *bufp = info->buffer; - *sizep = info->size; + dwarf2_build_psymtabs (objfile); + return 0; } + + /* Build a partial symbol table. */ void @@ -1699,6 +2688,7 @@ create_debug_types_hash_table (struct objfile *objfile) type_sig->signature = signature; type_sig->offset = offset; type_sig->type_offset = type_offset; + type_sig->per_cu.objfile = objfile; slot = htab_find_slot (types_htab, type_sig, INSERT); gdb_assert (slot != NULL); @@ -1897,7 +2887,7 @@ process_psymtab_comp_unit (struct objfile *objfile, /* Store the function that reads in the rest of the symbol table */ pst->read_symtab = dwarf2_psymtab_to_symtab; - this_cu->psymtab = pst; + this_cu->v.psymtab = pst; dwarf2_find_base_address (comp_unit_die, &cu); @@ -2182,6 +3172,7 @@ create_all_comp_units (struct objfile *objfile) memset (this_cu, 0, sizeof (*this_cu)); this_cu->offset = offset; this_cu->length = length + initial_length_size; + this_cu->objfile = objfile; if (n_comp_units == n_allocated) { @@ -2613,7 +3604,7 @@ add_partial_subprogram (struct partial_die_info *pdi, addrmap_set_empty (objfile->psymtabs_addrmap, pdi->lowpc + baseaddr, pdi->highpc - 1 + baseaddr, - cu->per_cu->psymtab); + cu->per_cu->v.psymtab); } if (!pdi->is_declaration) /* Ignore subprogram DIEs that do not have a name, they are @@ -2885,7 +3876,6 @@ locate_pdi_sibling (struct partial_die_info *orig_pdi, static void dwarf2_psymtab_to_symtab (struct partial_symtab *pst) { - /* FIXME: This is barely more than a stub. */ if (pst != NULL) { if (pst->readin) @@ -2958,7 +3948,9 @@ process_queue (struct objfile *objfile) may load a new CU, adding it to the end of the queue. */ for (item = dwarf2_queue; item != NULL; dwarf2_queue = item = next_item) { - if (item->per_cu->psymtab && !item->per_cu->psymtab->readin) + if (dwarf2_per_objfile->using_index + ? !item->per_cu->v.quick->symtab + : (item->per_cu->v.psymtab && !item->per_cu->v.psymtab->readin)) process_full_comp_unit (item->per_cu); item->per_cu->queued = 0; @@ -3035,22 +4027,7 @@ psymtab_to_symtab_1 (struct partial_symtab *pst) return; } - back_to = make_cleanup (dwarf2_release_queue, NULL); - - queue_comp_unit (per_cu, pst->objfile); - - if (per_cu->from_debug_types) - read_signatured_type_at_offset (pst->objfile, per_cu->offset); - else - load_full_comp_unit (per_cu, pst->objfile); - - process_queue (pst->objfile); - - /* Age the cache, releasing compilation units that have not - been used recently. */ - age_cached_comp_units (); - - do_cleanups (back_to); + dw2_do_instantiate_symtab (pst->objfile, per_cu); } /* Load the DIEs associated with PER_CU into memory. */ @@ -3130,9 +4107,8 @@ load_full_comp_unit (struct dwarf2_per_cu_data *per_cu, struct objfile *objfile) static void process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) { - struct partial_symtab *pst = per_cu->psymtab; struct dwarf2_cu *cu = per_cu->cu; - struct objfile *objfile = pst->objfile; + struct objfile *objfile = per_cu->objfile; CORE_ADDR lowpc, highpc; struct symtab *symtab; struct cleanup *back_to; @@ -3165,8 +4141,15 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) { symtab->language = cu->language; } - pst->symtab = symtab; - pst->readin = 1; + + if (dwarf2_per_objfile->using_index) + per_cu->v.quick->symtab = symtab; + else + { + struct partial_symtab *pst = per_cu->v.psymtab; + pst->symtab = symtab; + pst->readin = 1; + } do_cleanups (back_to); } @@ -3557,6 +4540,46 @@ free_cu_line_header (void *arg) } static void +find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu, + char **name, char **comp_dir) +{ + struct attribute *attr; + + *name = NULL; + *comp_dir = NULL; + + /* Find the filename. Do not use dwarf2_name here, since the filename + is not a source language identifier. */ + attr = dwarf2_attr (die, DW_AT_name, cu); + if (attr) + { + *name = DW_STRING (attr); + } + + attr = dwarf2_attr (die, DW_AT_comp_dir, cu); + if (attr) + *comp_dir = DW_STRING (attr); + else if (*name != NULL && IS_ABSOLUTE_PATH (*name)) + { + *comp_dir = ldirname (*name); + if (*comp_dir != NULL) + make_cleanup (xfree, *comp_dir); + } + if (*comp_dir != NULL) + { + /* Irix 6.2 native cc prepends .: to the compilation + directory, get rid of it. */ + char *cp = strchr (*comp_dir, ':'); + + if (cp && cp != *comp_dir && cp[-1] == '.' && cp[1] == '/') + *comp_dir = cp + 1; + } + + if (*name == NULL) + *name = ""; +} + +static void read_file_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; @@ -3582,35 +4605,7 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) lowpc += baseaddr; highpc += baseaddr; - /* Find the filename. Do not use dwarf2_name here, since the filename - is not a source language identifier. */ - attr = dwarf2_attr (die, DW_AT_name, cu); - if (attr) - { - name = DW_STRING (attr); - } - - attr = dwarf2_attr (die, DW_AT_comp_dir, cu); - if (attr) - comp_dir = DW_STRING (attr); - else if (name != NULL && IS_ABSOLUTE_PATH (name)) - { - comp_dir = ldirname (name); - if (comp_dir != NULL) - make_cleanup (xfree, comp_dir); - } - if (comp_dir != NULL) - { - /* Irix 6.2 native cc prepends .: to the compilation - directory, get rid of it. */ - char *cp = strchr (comp_dir, ':'); - - if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') - comp_dir = cp + 1; - } - - if (name == NULL) - name = ""; + find_file_and_directory (die, cu, &name, &comp_dir); attr = dwarf2_attr (die, DW_AT_language, cu); if (attr) @@ -5529,6 +6524,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. */ @@ -5542,7 +6560,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; @@ -5595,17 +6613,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 @@ -6059,29 +7071,114 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) struct gdbarch *gdbarch = get_objfile_arch (objfile); struct type *type, *range_type, *index_type, *char_type; struct attribute *attr; - unsigned int length; + int length; + + index_type = objfile_type (objfile)->builtin_int; + /* RANGE_TYPE is allocated from OBJFILE, not as a permanent type. */ + range_type = alloc_type (objfile); + /* 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; + const 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; + gdb_byte *data; + + 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; + data = obstack_alloc (&cu->comp_unit_obstack, + length_baton->size); + length_baton->data = data; + memcpy (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) + { + data[DW_BLOCK (attr)->size] = DW_OP_deref_size; + data[DW_BLOCK (attr)->size + 1] = DW_UNSND (size_attr); + if (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 + { + data[DW_BLOCK (attr)->size] = DW_OP_deref; + data[DW_BLOCK (attr)->size + 1] = DW_OP_nop; + } + } + + TYPE_RANGE_DATA (range_type)->high.kind + = RANGE_BOUND_KIND_DWARF_BLOCK; + 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_RANGE_DATA (range_type)->high.kind + = RANGE_BOUND_KIND_DWARF_BLOCK; + 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); @@ -6324,60 +7421,136 @@ 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; base_type = die_type (die, cu); + /* Preserve BASE_TYPE's original type, just set its LENGTH. */ + check_typedef (base_type); /* The die_type call above may have already set the type for this DIE. */ range_type = get_die_type (die, cu); if (range_type) return range_type; - 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); + + /* Exclude language_ada from any TYPE_DYNAMIC constructs below. GDB Ada + supports implements the dynamic bounds in a non-DWARF way and the + existing DWARF dynamic bounds are invalid, leading to memory access + errors. */ - /* 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) && cu->language != language_ada) + { + TYPE_RANGE_DATA (range_type)->low.kind = RANGE_BOUND_KIND_DWARF_BLOCK; + 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 && is_ref_attr (attr) && cu->language != language_ada) + { + struct die_info *target_die; + struct dwarf2_cu *target_cu = cu; + struct attribute *target_loc_attr; + + target_die = follow_die_ref_or_sig (die, attr, &target_cu); + gdb_assert (target_cu->objfile == cu->objfile); + target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu); + + TYPE_RANGE_DATA (range_type)->low.kind = RANGE_BOUND_KIND_DWARF_LOCLIST; + TYPE_RANGE_DATA (range_type)->low.u.dwarf_loclist.loclist + = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu); + TYPE_RANGE_DATA (range_type)->low.u.dwarf_loclist.type + = die_type (target_die, target_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 || (!attr_form_is_block (attr) && !attr_form_is_constant (attr) + && !is_ref_attr (attr))) { - if (attr->form == DW_FORM_block1 || is_ref_attr (attr)) - { - /* GCC encodes arrays with unspecified or dynamic length - with a DW_FORM_block1 attribute or a reference 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); + attr = dwarf2_attr (die, DW_AT_count, cu); + /* It does not hurt but it is needlessly ineffective in check_typedef. */ + if (attr && (attr_form_is_block (attr) || attr_form_is_constant (attr))) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1; + TYPE_DYNAMIC (range_type) = 1; + } + /* Pass it now as the regular DW_AT_upper_bound. */ + } + + if (attr && attr_form_is_block (attr) && cu->language != language_ada) + { + TYPE_RANGE_DATA (range_type)->high.kind = RANGE_BOUND_KIND_DWARF_BLOCK; + TYPE_RANGE_DATA (range_type)->high.u.dwarf_block = + dwarf2_attr_to_locexpr_baton (attr, cu); + TYPE_DYNAMIC (range_type) = 1; + } + else if (attr && is_ref_attr (attr) && cu->language != language_ada) + { + struct die_info *target_die; + struct dwarf2_cu *target_cu = cu; + struct attribute *target_loc_attr; + + target_die = follow_die_ref_or_sig (die, attr, &target_cu); + gdb_assert (target_cu->objfile == cu->objfile); + target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu); + + TYPE_RANGE_DATA (range_type)->high.kind = RANGE_BOUND_KIND_DWARF_LOCLIST; + TYPE_RANGE_DATA (range_type)->high.u.dwarf_loclist.loclist + = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu); + TYPE_RANGE_DATA (range_type)->high.u.dwarf_loclist.type + = die_type (target_die, target_cu); + TYPE_DYNAMIC (range_type) = 1; } else { - attr = dwarf2_attr (die, DW_AT_count, cu); - if (attr) + LONGEST high; + + if (attr && attr_form_is_constant (attr)) + high = dwarf2_get_attr_constant_value (attr, 0); + else { - int count = dwarf2_get_attr_constant_value (attr, 1); - high = low + count - 1; + TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; + high = low - 1; } + if (!TYPE_UNSIGNED (base_type) && (high & negative_mask)) + high |= negative_mask; + TYPE_HIGH_BOUND (range_type) = high; } /* Dwarf-2 specifications explicitly allows to create subrange types @@ -6419,20 +7592,41 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) } } - 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; + /* 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) && cu->language != language_ada) + { + TYPE_RANGE_DATA (range_type)->byte_stride.kind + = RANGE_BOUND_KIND_DWARF_BLOCK; + 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 && is_ref_attr (attr) && cu->language != language_ada) + { + struct die_info *target_die; + struct dwarf2_cu *target_cu = cu; + struct attribute *target_loc_attr; - range_type = create_range_type (NULL, base_type, low, high); + target_die = follow_die_ref_or_sig (die, attr, &target_cu); + gdb_assert (target_cu->objfile == cu->objfile); + target_loc_attr = dwarf2_attr (target_die, DW_AT_location, target_cu); - /* Mark arrays with dynamic length at least as an array of unspecified - length. GDB could check the boundary but before it gets implemented at - least allow accessing the array elements. */ - if (attr && attr->form == DW_FORM_block1) - TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; + TYPE_RANGE_DATA (range_type)->byte_stride.kind + = RANGE_BOUND_KIND_DWARF_LOCLIST; + TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_loclist.loclist + = dwarf2_attr_to_loclist_baton (target_loc_attr, target_cu); + TYPE_RANGE_DATA (range_type)->byte_stride.u.dwarf_loclist.type + = die_type (target_die, target_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) @@ -8712,10 +9906,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 @@ -8746,6 +9942,8 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) sizeof (struct symbol)); OBJSTAT (objfile, n_syms++); memset (sym, 0, sizeof (struct symbol)); + /* Some methods are called w/o checking SYMBOL_COMPUTED_OPS validity. */ + SYMBOL_COMPUTED_OPS (sym) = &dwarf2_missing_funcs; /* Cache this symbol's name and the name's demangled form (if any). */ SYMBOL_LANGUAGE (sym) = cu->language; @@ -9375,6 +10573,9 @@ read_type_die (struct die_info *die, struct dwarf2_cu *cu) break; } + if (this_type) + finalize_type (this_type); + return this_type; } @@ -11979,67 +13180,102 @@ attr_form_is_constant (struct attribute *attr) } } -static void -dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, - struct dwarf2_cu *cu) +/* 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) { - if (attr_form_is_section_offset (attr) - /* ".debug_loc" may not exist at all, or the offset may be outside - the section. If so, fall through to the complaint in the - other branch. */ - && DW_UNSND (attr) < dwarf2_per_objfile->loc.size) - { - struct dwarf2_loclist_baton *baton; + struct dwarf2_locexpr_baton *baton; - baton = obstack_alloc (&cu->objfile->objfile_obstack, - sizeof (struct dwarf2_loclist_baton)); - baton->per_cu = cu->per_cu; - gdb_assert (baton->per_cu); + gdb_assert (attr_form_is_block (attr)); - dwarf2_read_section (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->loc); + baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (*baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); - /* We don't know how long the location list is, but make sure we - don't run off the edge of the section. */ - baton->size = dwarf2_per_objfile->loc.size - DW_UNSND (attr); - baton->data = dwarf2_per_objfile->loc.buffer + DW_UNSND (attr); - baton->base_address = cu->base_address; - if (cu->base_known == 0) - complaint (&symfile_complaints, - _("Location list used without specifying the CU base address.")); + /* 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; +} + +static struct dwarf2_loclist_baton * +dwarf2_attr_to_loclist_baton (struct attribute *attr, struct dwarf2_cu *cu) +{ + struct dwarf2_loclist_baton *baton; + + /* DW_AT_location of the referenced DIE may be missing if the referenced + variable has been optimized out. */ + if (!attr) + return NULL; + + dwarf2_read_section (dwarf2_per_objfile->objfile, + &dwarf2_per_objfile->loc); + + if (!(attr_form_is_section_offset (attr) + /* ".debug_loc" may not exist at all, or the offset may be outside + the section. If so, fall through to the complaint in the + other branch. */ + && DW_UNSND (attr) < dwarf2_per_objfile->loc.size)) + return NULL; + + baton = obstack_alloc (&cu->objfile->objfile_obstack, + sizeof (struct dwarf2_loclist_baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); + + /* We don't know how long the location list is, but make sure we + don't run off the edge of the section. */ + baton->size = dwarf2_per_objfile->loc.size - DW_UNSND (attr); + baton->data = dwarf2_per_objfile->loc.buffer + DW_UNSND (attr); + baton->base_address = cu->base_address; + if (cu->base_known == 0) + complaint (&symfile_complaints, + _("Location list used without specifying the CU base address.")); + + 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) +{ + struct dwarf2_loclist_baton *loclist_baton; + loclist_baton = dwarf2_attr_to_loclist_baton (attr, cu); + if (loclist_baton) + { SYMBOL_COMPUTED_OPS (sym) = &dwarf2_loclist_funcs; - SYMBOL_LOCATION_BATON (sym) = baton; + SYMBOL_LOCATION_BATON (sym) = loclist_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_missing_funcs; + SYMBOL_LOCATION_BATON (sym) = NULL; - SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs; - SYMBOL_LOCATION_BATON (sym) = baton; + /* 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; } } @@ -12050,7 +13286,7 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct objfile * dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *per_cu) { - struct objfile *objfile = per_cu->psymtab->objfile; + struct objfile *objfile = per_cu->objfile; /* Return the master objfile, so that we can report and look up the correct file containing this variable. */ @@ -12070,7 +13306,7 @@ dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *per_cu) else { /* If the CU is not currently read in, we re-read its header. */ - struct objfile *objfile = per_cu->psymtab->objfile; + struct objfile *objfile = per_cu->objfile; struct dwarf2_per_objfile *per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset; @@ -12092,7 +13328,7 @@ dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu) else { /* If the CU is not currently read in, we re-read its header. */ - struct objfile *objfile = per_cu->psymtab->objfile; + struct objfile *objfile = per_cu->objfile; struct dwarf2_per_objfile *per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset; @@ -12112,7 +13348,7 @@ dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu) CORE_ADDR dwarf2_per_cu_text_offset (struct dwarf2_per_cu_data *per_cu) { - struct objfile *objfile = per_cu->psymtab->objfile; + struct objfile *objfile = per_cu->objfile; return ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); } @@ -12334,6 +13570,30 @@ dwarf2_free_objfile (struct objfile *objfile) /* Cached DIE trees use xmalloc and the comp_unit_obstack. */ free_cached_comp_units (NULL); + if (dwarf2_per_objfile->using_index) + { + int i; + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + int j; + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + + if (!cu->v.quick->lines) + continue; + + for (j = 0; j < cu->v.quick->lines->num_file_names; ++j) + { + if (cu->v.quick->file_names) + xfree ((void *) cu->v.quick->file_names[j]); + if (cu->v.quick->full_names) + xfree ((void *) cu->v.quick->full_names[j]); + } + + free_line_header (cu->v.quick->lines); + } + } + /* Everything else should be on the objfile obstack. */ } @@ -12368,6 +13628,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. @@ -12391,6 +13676,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 @@ -12591,8 +13878,567 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d) munmap_section_buffer (&data->types); munmap_section_buffer (&data->frame); munmap_section_buffer (&data->eh_frame); + munmap_section_buffer (&data->gdb_index); +} + + + +/* The contents of the hash table we create when building the string + table. */ +struct strtab_entry +{ + offset_type offset; + const char *str; +}; + +/* Hash function for a strtab_entry. */ +static hashval_t +hash_strtab_entry (const void *e) +{ + const struct strtab_entry *entry = e; + return mapped_index_string_hash (entry->str); +} + +/* Equality function for a strtab_entry. */ +static int +eq_strtab_entry (const void *a, const void *b) +{ + const struct strtab_entry *ea = a; + const struct strtab_entry *eb = b; + return !strcmp (ea->str, eb->str); +} + +/* Create a strtab_entry hash table. */ +static htab_t +create_strtab (void) +{ + return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry, + xfree, xcalloc, xfree); +} + +/* Add a string to the constant pool. Return the string's offset in + host order. */ +static offset_type +add_string (htab_t table, struct obstack *cpool, const char *str) +{ + void **slot; + struct strtab_entry entry; + struct strtab_entry *result; + + entry.str = str; + slot = htab_find_slot (table, &entry, INSERT); + if (*slot) + result = *slot; + else + { + result = XNEW (struct strtab_entry); + result->offset = obstack_object_size (cpool); + result->str = str; + obstack_grow_str0 (cpool, str); + *slot = result; + } + return result->offset; +} + +/* An entry in the symbol table. */ +struct symtab_index_entry +{ + /* The name of the symbol. */ + const char *name; + /* The offset of the name in the constant pool. */ + offset_type index_offset; + /* A sorted vector of the indices of all the CUs that hold an object + of this name. */ + VEC (offset_type) *cu_indices; +}; + +/* The symbol table. This is a power-of-2-sized hash table. */ +struct mapped_symtab +{ + offset_type n_elements; + offset_type size; + struct symtab_index_entry **data; +}; + +/* Hash function for a symtab_index_entry. */ +static hashval_t +hash_symtab_entry (const void *e) +{ + const struct symtab_index_entry *entry = e; + return iterative_hash (VEC_address (offset_type, entry->cu_indices), + sizeof (offset_type) * VEC_length (offset_type, + entry->cu_indices), + 0); +} + +/* Equality function for a symtab_index_entry. */ +static int +eq_symtab_entry (const void *a, const void *b) +{ + const struct symtab_index_entry *ea = a; + const struct symtab_index_entry *eb = b; + int len = VEC_length (offset_type, ea->cu_indices); + if (len != VEC_length (offset_type, eb->cu_indices)) + return 0; + return !memcmp (VEC_address (offset_type, ea->cu_indices), + VEC_address (offset_type, eb->cu_indices), + sizeof (offset_type) * len); +} + +/* Destroy a symtab_index_entry. */ +static void +delete_symtab_entry (void *p) +{ + struct symtab_index_entry *entry = p; + VEC_free (offset_type, entry->cu_indices); + xfree (entry); +} + +/* Create a hash table holding symtab_index_entry objects. */ +static htab_t +create_index_table (void) +{ + return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry, + delete_symtab_entry, xcalloc, xfree); +} + +/* Create a new mapped symtab object. */ +static struct mapped_symtab * +create_mapped_symtab (void) +{ + struct mapped_symtab *symtab = XNEW (struct mapped_symtab); + symtab->n_elements = 0; + symtab->size = 1024; + symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size); + return symtab; +} + +/* Destroy a mapped_symtab. */ +static void +cleanup_mapped_symtab (void *p) +{ + struct mapped_symtab *symtab = p; + /* The contents of the array are freed when the other hash table is + destroyed. */ + xfree (symtab->data); + xfree (symtab); +} + +/* Find a slot in SYMTAB for the symbol NAME. Returns a pointer to + the slot. */ +static struct symtab_index_entry ** +find_slot (struct mapped_symtab *symtab, const char *name) +{ + offset_type index, step, hash = mapped_index_string_hash (name); + + index = hash & (symtab->size - 1); + step = ((hash * 17) & (symtab->size - 1)) | 1; + + for (;;) + { + if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name)) + return &symtab->data[index]; + index = (index + step) & (symtab->size - 1); + } } +/* Expand SYMTAB's hash table. */ +static void +hash_expand (struct mapped_symtab *symtab) +{ + offset_type old_size = symtab->size; + offset_type i; + struct symtab_index_entry **old_entries = symtab->data; + + symtab->size *= 2; + symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size); + + for (i = 0; i < old_size; ++i) + { + if (old_entries[i]) + { + struct symtab_index_entry **slot = find_slot (symtab, + old_entries[i]->name); + *slot = old_entries[i]; + } + } + + xfree (old_entries); +} + +/* Add an entry to SYMTAB. NAME is the name of the symbol. CU_INDEX + is the index of the CU in which the symbol appears. */ +static void +add_index_entry (struct mapped_symtab *symtab, const char *name, + offset_type cu_index) +{ + struct symtab_index_entry **slot; + + ++symtab->n_elements; + if (4 * symtab->n_elements / 3 >= symtab->size) + hash_expand (symtab); + + slot = find_slot (symtab, name); + if (!*slot) + { + *slot = XNEW (struct symtab_index_entry); + (*slot)->name = name; + (*slot)->cu_indices = NULL; + } + /* Don't push an index twice. Due to how we add entries we only + have to check the last one. */ + if (VEC_empty (offset_type, (*slot)->cu_indices) + || VEC_length (offset_type, (*slot)->cu_indices) != cu_index) + VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index); +} + +/* Add a vector of indices to the constant pool. */ +static offset_type +add_indices_to_cpool (htab_t index_table, struct obstack *cpool, + struct symtab_index_entry *entry) +{ + void **slot; + + slot = htab_find_slot (index_table, entry, INSERT); + if (!*slot) + { + offset_type len = VEC_length (offset_type, entry->cu_indices); + offset_type val = MAYBE_SWAP (len); + offset_type iter; + int i; + + *slot = entry; + entry->index_offset = obstack_object_size (cpool); + + obstack_grow (cpool, &val, sizeof (val)); + for (i = 0; + VEC_iterate (offset_type, entry->cu_indices, i, iter); + ++i) + { + val = MAYBE_SWAP (iter); + obstack_grow (cpool, &val, sizeof (val)); + } + } + else + { + struct symtab_index_entry *old_entry = *slot; + entry->index_offset = old_entry->index_offset; + entry = old_entry; + } + return entry->index_offset; +} + +/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with + constant pool entries going into the obstack CPOOL. */ +static void +write_hash_table (struct mapped_symtab *symtab, + struct obstack *output, struct obstack *cpool) +{ + offset_type i; + htab_t index_table; + htab_t str_table; + + index_table = create_index_table (); + str_table = create_strtab (); + /* We add all the index vectors to the constant pool first, to + ensure alignment is ok. */ + for (i = 0; i < symtab->size; ++i) + { + if (symtab->data[i]) + add_indices_to_cpool (index_table, cpool, symtab->data[i]); + } + + /* Now write out the hash table. */ + for (i = 0; i < symtab->size; ++i) + { + offset_type str_off, vec_off; + + if (symtab->data[i]) + { + str_off = add_string (str_table, cpool, symtab->data[i]->name); + vec_off = symtab->data[i]->index_offset; + } + else + { + /* While 0 is a valid constant pool index, it is not valid + to have 0 for both offsets. */ + str_off = 0; + vec_off = 0; + } + + str_off = MAYBE_SWAP (str_off); + vec_off = MAYBE_SWAP (vec_off); + + obstack_grow (output, &str_off, sizeof (str_off)); + obstack_grow (output, &vec_off, sizeof (vec_off)); + } + + htab_delete (str_table); + htab_delete (index_table); +} + +/* Write an address entry to ADDR_OBSTACK. The addresses are taken + from PST; CU_INDEX is the index of the CU in the vector of all + CUs. */ +static void +add_address_entry (struct objfile *objfile, + struct obstack *addr_obstack, struct partial_symtab *pst, + unsigned int cu_index) +{ + offset_type offset; + char addr[8]; + CORE_ADDR baseaddr; + + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + + store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, pst->textlow - baseaddr); + obstack_grow (addr_obstack, addr, 8); + store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, pst->texthigh - baseaddr); + obstack_grow (addr_obstack, addr, 8); + offset = MAYBE_SWAP (cu_index); + obstack_grow (addr_obstack, &offset, sizeof (offset_type)); +} + +/* Add a list of partial symbols to SYMTAB. */ +static void +write_psymbols (struct mapped_symtab *symtab, + struct partial_symbol **psymp, + int count, + offset_type cu_index) +{ + for (; count-- > 0; ++psymp) + { + if (SYMBOL_LANGUAGE (*psymp) == language_ada) + error (_("Ada is not currently supported by the index")); + add_index_entry (symtab, SYMBOL_NATURAL_NAME (*psymp), cu_index); + } +} + +/* Write the contents of an ("unfinished") obstack to FILE. Throw an + exception if there is an error. */ +static void +write_obstack (FILE *file, struct obstack *obstack) +{ + if (fwrite (obstack_base (obstack), 1, obstack_object_size (obstack), + file) + != obstack_object_size (obstack)) + error (_("couldn't data write to file")); +} + +/* Unlink a file if the argument is not NULL. */ +static void +unlink_if_set (void *p) +{ + char **filename = p; + if (*filename) + unlink (*filename); +} + +/* Create an index file for OBJFILE in the directory DIR. */ +static void +write_psymtabs_to_index (struct objfile *objfile, const char *dir) +{ + struct cleanup *cleanup; + char *filename, *cleanup_filename; + struct obstack contents, addr_obstack, constant_pool, symtab_obstack, cu_list; + int i; + FILE *out_file; + struct mapped_symtab *symtab; + offset_type val, size_of_contents, total_len; + struct stat st; + char buf[8]; + + if (!objfile->psymtabs) + return; + if (dwarf2_per_objfile->using_index) + error (_("Cannot use an index to create the index")); + + if (stat (objfile->name, &st) < 0) + perror_with_name (_("Could not stat")); + + filename = concat (dir, SLASH_STRING, lbasename (objfile->name), + INDEX_SUFFIX, (char *) NULL); + cleanup = make_cleanup (xfree, filename); + + out_file = fopen (filename, "wb"); + if (!out_file) + error (_("Can't open `%s' for writing"), filename); + + cleanup_filename = filename; + make_cleanup (unlink_if_set, &cleanup_filename); + + symtab = create_mapped_symtab (); + make_cleanup (cleanup_mapped_symtab, symtab); + + obstack_init (&addr_obstack); + make_cleanup_obstack_free (&addr_obstack); + + obstack_init (&cu_list); + make_cleanup_obstack_free (&cu_list); + + for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i) + { + struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i]; + struct partial_symtab *psymtab = cu->v.psymtab; + gdb_byte val[8]; + + write_psymbols (symtab, + objfile->global_psymbols.list + psymtab->globals_offset, + psymtab->n_global_syms, i); + write_psymbols (symtab, + objfile->static_psymbols.list + psymtab->statics_offset, + psymtab->n_static_syms, i); + + add_address_entry (objfile, &addr_obstack, psymtab, i); + + store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, cu->offset); + obstack_grow (&cu_list, val, 8); + store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, cu->length); + obstack_grow (&cu_list, val, 8); + } + + obstack_init (&constant_pool); + make_cleanup_obstack_free (&constant_pool); + obstack_init (&symtab_obstack); + make_cleanup_obstack_free (&symtab_obstack); + write_hash_table (symtab, &symtab_obstack, &constant_pool); + + obstack_init (&contents); + make_cleanup_obstack_free (&contents); + size_of_contents = 5 * sizeof (offset_type); + total_len = size_of_contents; + + /* The version number. */ + val = MAYBE_SWAP (1); + obstack_grow (&contents, &val, sizeof (val)); + + /* The offset of the CU list from the start of the file. */ + val = MAYBE_SWAP (total_len); + obstack_grow (&contents, &val, sizeof (val)); + total_len += obstack_object_size (&cu_list); + + /* The offset of the address table from the start of the file. */ + val = MAYBE_SWAP (total_len); + obstack_grow (&contents, &val, sizeof (val)); + total_len += obstack_object_size (&addr_obstack); + + /* The offset of the symbol table from the start of the file. */ + val = MAYBE_SWAP (total_len); + obstack_grow (&contents, &val, sizeof (val)); + total_len += obstack_object_size (&symtab_obstack); + + /* The offset of the constant pool from the start of the file. */ + val = MAYBE_SWAP (total_len); + obstack_grow (&contents, &val, sizeof (val)); + total_len += obstack_object_size (&constant_pool); + + gdb_assert (obstack_object_size (&contents) == size_of_contents); + + write_obstack (out_file, &contents); + write_obstack (out_file, &cu_list); + write_obstack (out_file, &addr_obstack); + write_obstack (out_file, &symtab_obstack); + write_obstack (out_file, &constant_pool); + + fclose (out_file); + + /* We want to keep the file, so we set cleanup_filename to NULL + here. See unlink_if_set. */ + cleanup_filename = NULL; + + do_cleanups (cleanup); +} + +/* The mapped index file format is designed to be directly mmap()able + on any architecture. In most cases, a datum is represented using a + little-endian 32-bit integer value, called an offset_type. Big + endian machines must byte-swap the values before using them. + Exceptions to this rule are noted. The data is laid out such that + alignment is always respected. + + A mapped index consists of several sections. + + 1. The file header. This is a sequence of values, of offset_type + unless otherwise noted: + [0] The version number. Currently 1. + [1] The offset, from the start of the file, of the CU list. + [2] The offset, from the start of the file, of the address section. + [3] The offset, from the start of the file, of the symbol table. + [4] The offset, from the start of the file, of the constant pool. + + 2. The CU list. This is a sequence of pairs of 64-bit + little-endian values. The first element in each pair is the offset + of a CU in the .debug_info section. The second element in each + pair is the length of that CU. References to a CU elsewhere in the + map are done using a CU index, which is just the 0-based index into + this table. + + 3. The address section. The address section consists of a sequence + of address entries. Each address entry has three elements. + [0] The low address. This is a 64-bit little-endian value. + [1] The high address. This is a 64-bit little-endian value. + [2] The CU index. This is an offset_type value. + + 4. The symbol table. This is a hash table. The size of the hash + table is always a power of 2. The initial hash and the step are + currently defined by the `find_slot' function. + + Each slot in the hash table consists of a pair of offset_type + values. The first value is the offset of the symbol's name in the + constant pool. The second value is the offset of the CU vector in + the constant pool. + + If both values are 0, then this slot in the hash table is empty. + This is ok because while 0 is a valid constant pool index, it + cannot be a valid index for both a string and a CU vector. + + A string in the constant pool is stored as a \0-terminated string, + as you'd expect. + + A CU vector in the constant pool is a sequence of offset_type + values. The first value is the number of CU indices in the vector. + Each subsequent value is the index of a CU in the CU list. This + element in the hash table is used to indicate which CUs define the + symbol. + + 5. The constant pool. This is simply a bunch of bytes. It is + organized so that alignment is correct: CU vectors are stored + first, followed by strings. */ +static void +save_gdb_index_command (char *arg, int from_tty) +{ + struct objfile *objfile; + + if (!arg || !*arg) + error (_("usage: save gdb-index DIRECTORY")); + + ALL_OBJFILES (objfile) + { + struct stat st; + + /* If the objfile does not correspond to an actual file, skip it. */ + if (stat (objfile->name, &st) < 0) + continue; + + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); + if (dwarf2_per_objfile) + { + volatile struct gdb_exception except; + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + write_psymtabs_to_index (objfile, arg); + } + if (except.reason < 0) + exception_fprintf (gdb_stderr, except, + _("Error while writing index for `%s': "), + objfile->name); + } + } +} + + + int dwarf2_always_disassemble; static void @@ -12609,6 +14455,8 @@ void _initialize_dwarf2_read (void); void _initialize_dwarf2_read (void) { + struct cmd_list_element *c; + dwarf2_objfile_data_key = register_objfile_data_with_cleanup (NULL, dwarf2_per_objfile_free); @@ -12656,4 +14504,9 @@ The value is the maximum depth to print."), NULL, NULL, &setdebuglist, &showdebuglist); + + c = add_cmd ("gdb-index", class_files, save_gdb_index_command, + _("Save a .gdb-index file"), + &save_cmdlist); + set_cmd_completer (c, filename_completer); } diff --git a/gdb/elfread.c b/gdb/elfread.c index 8c00938..a250c58 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -37,9 +37,13 @@ #include "complaints.h" #include "demangle.h" #include "psympriv.h" +#include "gdbtypes.h" extern void _initialize_elfread (void); +/* Forward declaration. */ +static struct sym_fns elf_sym_fns_gdb_index; + /* The struct elfinfo is available only during ELF symbol table and psymtab reading. It is destroyed at the completion of psymtab-reading. It's local to elf_symfile_read. */ @@ -180,7 +184,8 @@ record_minimal_symbol (const char *name, int name_len, int copy_name, { struct gdbarch *gdbarch = get_objfile_arch (objfile); - if (ms_type == mst_text || ms_type == mst_file_text) + if (ms_type == mst_text || ms_type == mst_file_text + || ms_type == mst_text_gnu_ifunc) address = gdbarch_smash_text_address (gdbarch, address); return prim_record_minimal_symbol_full (name, name_len, copy_name, address, @@ -388,7 +393,10 @@ elf_symtab_read (struct objfile *objfile, int type, { if (sym->flags & (BSF_GLOBAL | BSF_WEAK)) { - ms_type = mst_text; + if (sym->flags & BSF_GNU_INDIRECT_FUNCTION) + ms_type = mst_text_gnu_ifunc; + else + ms_type = mst_text; } else if ((sym->name[0] == '.' && sym->name[1] == 'L') || ((sym->flags & BSF_LOCAL) @@ -569,6 +577,250 @@ elf_symtab_read (struct objfile *objfile, int type, } } +/* FIXME: Delay it through elf_sym_fns. */ + +static void +elf_rel_plt_read (struct objfile *objfile, asymbol **dyn_symbol_table) +{ + bfd *obfd = objfile->obfd; + const struct elf_backend_data *bed = get_elf_backend_data (obfd); + asection *plt, *relplt, *got_plt; + unsigned u; + int plt_elf_idx; + bfd_size_type reloc_count, reloc; + char *string_buffer = NULL; + size_t string_buffer_size = 0; + struct cleanup *back_to; + struct gdbarch *gdbarch = objfile->gdbarch; + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; + size_t ptr_size = TYPE_LENGTH (ptr_type); + + if (objfile->separate_debug_objfile_backlink) + return; + + plt = bfd_get_section_by_name (obfd, ".plt"); + if (plt == NULL) + return; + plt_elf_idx = elf_section_data (plt)->this_idx; + + got_plt = bfd_get_section_by_name (obfd, ".got.plt"); + if (got_plt == NULL) + return; + + /* This search algorithm is from _bfd_elf_canonicalize_dynamic_reloc. */ + for (relplt = obfd->sections; relplt != NULL; relplt = relplt->next) + if (elf_section_data (relplt)->this_hdr.sh_info == plt_elf_idx + && (elf_section_data (relplt)->this_hdr.sh_type == SHT_REL + || elf_section_data (relplt)->this_hdr.sh_type == SHT_RELA)) + break; + if (relplt == NULL) + return; + + if (! bed->s->slurp_reloc_table (obfd, relplt, dyn_symbol_table, TRUE)) + return; + + back_to = make_cleanup (free_current_contents, &string_buffer); + + reloc_count = relplt->size / elf_section_data (relplt)->this_hdr.sh_entsize; + for (reloc = 0; reloc < reloc_count; reloc++) + { + const char *name, *name_got_plt; + struct minimal_symbol *msym; + CORE_ADDR address; + const char *suffix = "@got.plt"; + size_t suffix_len = strlen (suffix); + size_t name_len; + + name = bfd_asymbol_name (*relplt->relocation[reloc].sym_ptr_ptr); + name_len = strlen (name); + address = relplt->relocation[reloc].address; + + /* Does the pointer reside in the .got.plt section? */ + if (!(bfd_get_section_vma (obfd, got_plt) <= address + && address < bfd_get_section_vma (obfd, got_plt) + + bfd_get_section_size (got_plt))) + continue; + + /* We cannot check if NAME is a reference to mst_text_gnu_ifunc as in + OBJFILE the symbol is undefined and the objfile having NAME defined + may not yet have been loaded. */ + + if (string_buffer_size < name_len + suffix_len) + { + string_buffer_size = 2 * (name_len + suffix_len); + string_buffer = xrealloc (string_buffer, string_buffer_size); + } + memcpy (string_buffer, name, name_len); + memcpy (&string_buffer[name_len], suffix, suffix_len); + + msym = record_minimal_symbol (string_buffer, name_len + suffix_len, 1, + address, mst_slot_got_plt, got_plt, + objfile); + if (msym) + MSYMBOL_SIZE (msym) = ptr_size; + } + + do_cleanups (back_to); +} + +/* Function does not check for possibly created duplicities in the cache. + Check it by resolve_gnu_ifunc_by_cache first. */ + +static struct minimal_symbol * +gnu_ifunc_record_cache_unchecked (const char *function_name, + CORE_ADDR function_address) +{ + struct minimal_symbol *msym, *msym_new; + asection *sect; + struct objfile *objfile; + char *function_name_gnu_ifunc_tgt; + + msym = lookup_minimal_symbol_by_pc (function_address); + if (msym == NULL) + return NULL; + if (SYMBOL_VALUE_ADDRESS (msym) != function_address) + return NULL; + /* minimal symbols have always SYMBOL_OBJ_SECTION non-NULL. */ + sect = SYMBOL_OBJ_SECTION (msym)->the_bfd_section; + objfile = SYMBOL_OBJ_SECTION (msym)->objfile; + + /* If .plt jumps back to .plt the symbol is still deferred for later + resolution and it has no use for GDB. Besides ".text" this symbol can + reside also in ".opd" for ppc64 function descriptor. */ + if (strcmp (bfd_get_section_name (objfile->obfd, sect), ".plt") == 0) + return NULL; + + function_name_gnu_ifunc_tgt = alloca (strlen (function_name) + + strlen ("@gnu-ifunc-tgt") + 1); + sprintf (function_name_gnu_ifunc_tgt, "%s@gnu-ifunc-tgt", function_name); + + /* Create new alias "@gnu-ifunc-tgt" for MSYM. */ + msym_new = record_minimal_symbol (function_name_gnu_ifunc_tgt, + strlen (function_name_gnu_ifunc_tgt), 1, + SYMBOL_VALUE_ADDRESS (msym), + MSYMBOL_TYPE (msym), sect, objfile); + /* Should not happen. */ + if (msym_new == NULL) + return 0; + + /* objfile->msymbols array is already allocated on obstack and it cannot be + easily extended. Therefore -completion on symbol names will never + show the @gnu-ifunc-tgt symbol. Link it at least to the hash table so + that resolve_gnu_ifunc_by_cache can find it. */ + add_minsym_to_hash_table (msym_new, objfile->msymbol_hash); + + MSYMBOL_SIZE (msym_new) = MSYMBOL_SIZE (msym); + return msym_new; +} + +/* Check first the cache if it - unlikely - has not been populated since + bp_gnu_ifunc_resolver has been created. gnu_ifunc_record_cache_unchecked + could create a duplicate symbol otherwise. */ + +void +gnu_ifunc_record_cache (struct gdbarch *gdbarch, const char *function_name, + CORE_ADDR function_address) +{ + struct minimal_symbol *msym; + + msym = resolve_gnu_ifunc_by_cache (function_name); + if (msym == NULL) + gnu_ifunc_record_cache_unchecked (function_name, function_address); + else if (SYMBOL_VALUE_ADDRESS (msym) != function_address) + { + /* This case indicates buggy inferior program. GDB would need to update + its MSYM cache symbol for function_address. Anyway FUNCTION_NAME is + never normally found in the case as in such case no + bp_gnu_ifunc_resolver would be created in the first place. */ + + warning (_("gnu-indirect-function \"%s\" has changed its resolved " + "function_address from %s to %s; GDB is using the former one"), + function_name, paddress (gdbarch, SYMBOL_VALUE_ADDRESS (msym)), + paddress (gdbarch, function_address)); + } +} + +static struct minimal_symbol * +resolve_gnu_ifunc_by_got (const char *function_name) +{ + char *function_name_got_plt; + struct objfile *objfile; + + function_name_got_plt = alloca (strlen (function_name) + strlen ("@got.plt") + + 1); + sprintf (function_name_got_plt, "%s@got.plt", function_name); + + ALL_PSPACE_OBJFILES (current_program_space, objfile) + { + bfd *obfd = objfile->obfd; + struct gdbarch *gdbarch = objfile->gdbarch; + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; + size_t ptr_size = TYPE_LENGTH (ptr_type); + CORE_ADDR pointer_address, function_address; + asection *plt; + gdb_byte *buf = alloca (ptr_size); + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol (function_name_got_plt, NULL, objfile); + if (msym == NULL) + continue; + if (MSYMBOL_TYPE (msym) != mst_slot_got_plt) + continue; + pointer_address = SYMBOL_VALUE_ADDRESS (msym); + + plt = bfd_get_section_by_name (obfd, ".plt"); + if (plt == NULL) + continue; + + if (MSYMBOL_SIZE (msym) != ptr_size) + continue; + if (target_read_memory (pointer_address, buf, ptr_size) != 0) + continue; + function_address = extract_typed_address (buf, ptr_type); + + msym = gnu_ifunc_record_cache_unchecked (function_name, function_address); + if (msym == NULL) + continue; + return msym; + } + + return NULL; +} + +struct minimal_symbol * +resolve_gnu_ifunc_by_cache (const char *function_name) +{ + char *function_name_gnu_ifunc_tgt; + + function_name_gnu_ifunc_tgt = alloca (strlen (function_name) + + strlen ("@gnu-ifunc-tgt") + 1); + sprintf (function_name_gnu_ifunc_tgt, "%s@gnu-ifunc-tgt", function_name); + + return lookup_minimal_symbol (function_name_gnu_ifunc_tgt, NULL, NULL); +} + +int +resolve_gnu_ifunc (const char *function_name, CORE_ADDR *function_addressp) +{ + struct minimal_symbol *msym; + + msym = resolve_gnu_ifunc_by_cache (function_name); + if (msym != NULL) + { + *function_addressp = SYMBOL_VALUE_ADDRESS (msym); + return 1; + } + + msym = resolve_gnu_ifunc_by_got (function_name); + if (msym != NULL) + { + *function_addressp = SYMBOL_VALUE_ADDRESS (msym); + return 1; + } + + return 0; +} + struct build_id { size_t size; @@ -797,6 +1049,8 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) bfd_errmsg (bfd_get_error ())); elf_symtab_read (objfile, ST_DYNAMIC, dynsymcount, dyn_symbol_table, 0); + + elf_rel_plt_read (objfile, dyn_symbol_table); } /* Add synthetic symbols - for instance, names for any PLT entries. */ @@ -869,11 +1123,9 @@ 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); - } + + if (dwarf2_has_info (objfile) && dwarf2_initialize_objfile (objfile)) + objfile->sf = &elf_sym_fns_gdb_index; /* 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. @@ -1049,6 +1301,24 @@ static struct sym_fns elf_sym_fns = NULL /* next: pointer to next struct sym_fns */ }; +/* The same as elf_sym_fns, but not registered and uses the + DWARF-specific GNU index rather than psymtab. */ +static struct sym_fns elf_sym_fns_gdb_index = +{ + bfd_target_elf_flavour, + elf_new_init, /* sym_new_init: init anything gbl to entire symab */ + elf_symfile_init, /* sym_init: read initial info, setup for sym_red() */ + elf_symfile_read, /* sym_read: read a symbol file into symtab */ + elf_symfile_finish, /* sym_finish: finished with file, cleanup */ + default_symfile_offsets, /* sym_offsets: Translate ext. to int. relocatin */ + elf_symfile_segments, /* sym_segments: Get segment information from + a file. */ + NULL, /* sym_read_linetable */ + default_symfile_relocate, /* sym_relocate: Relocate a debug section. */ + &dwarf2_gdb_index_functions, + NULL /* next: pointer to next struct sym_fns */ +}; + void _initialize_elfread (void) { diff --git a/gdb/eval.c b/gdb/eval.c index ff17c34..7b9e871 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -44,6 +44,7 @@ #include "objfiles.h" #include "python/python.h" #include "wrapper.h" +#include "dwarf2loc.h" #include "gdb_assert.h" @@ -788,6 +789,7 @@ evaluate_subexp_standard (struct type *expect_type, int save_pos1; struct symbol *function = NULL; char *function_name = NULL; + struct cleanup *old_chain; pc = (*pos)++; op = exp->elts[pc].opcode; @@ -1772,6 +1774,8 @@ evaluate_subexp_standard (struct type *expect_type, return value_zero (builtin_type (exp->gdbarch)->builtin_int, not_lval); } + else if (TYPE_GNU_IFUNC (ftype)) + return allocate_value (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype))); else if (TYPE_TARGET_TYPE (ftype)) return allocate_value (TYPE_TARGET_TYPE (ftype)); else @@ -1798,6 +1802,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); @@ -1818,6 +1824,7 @@ evaluate_subexp_standard (struct type *expect_type, code = TYPE_CODE (type); } } + do_cleanups (old_chain); switch (code) { @@ -2254,13 +2261,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); @@ -2290,6 +2303,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. */ @@ -2308,13 +2324,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 @@ -2324,7 +2352,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: @@ -2558,14 +2586,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)); @@ -2574,12 +2610,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.")); } @@ -2589,9 +2631,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. */ @@ -2933,7 +2980,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; @@ -2944,12 +2991,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 (exp->language_defn)) { (*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); } @@ -3001,9 +3053,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/f-lang.h b/gdb/f-lang.h index f5bb82d..29cf5ba 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 *, const 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 *, diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c index d35a255..dec81d5 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, const 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 85f698d..2f72b97 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); @@ -134,24 +139,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, val, 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, val, 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, "..."); } } @@ -256,6 +266,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 ac63a9e..e9ba45c 100644 --- a/gdb/findcmd.c +++ b/gdb/findcmd.c @@ -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. @@ -175,17 +208,9 @@ 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; + increase_pattern_buffer (&pattern_buf, &pattern_buf_end, + &pattern_buf_size, val_bytes); - pattern_buf_size *= 2; - pattern_buf = xrealloc (pattern_buf, pattern_buf_size); - pattern_buf_end = pattern_buf + current_offset; - } if (size != '\0') { @@ -240,6 +265,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) { @@ -270,12 +334,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; @@ -283,16 +346,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 e0ca12c..de6311a 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 @@ -401,27 +402,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); @@ -429,33 +419,43 @@ 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)); + { + /* 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)); - VALUE_LVAL (v) = not_lval; - return v; + 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); - VALUE_LVAL (v) = not_lval; - return v; + { + 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; + } case LOC_STATIC: if (overlay_debugging) @@ -496,12 +496,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: @@ -520,7 +531,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 { @@ -563,18 +573,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. */ @@ -611,10 +636,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 @@ -628,7 +654,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/gdbcmd.h b/gdb/gdbcmd.h index 78151dd..da11686 100644 --- a/gdb/gdbcmd.h +++ b/gdb/gdbcmd.h @@ -124,6 +124,10 @@ extern struct cmd_list_element *setchecklist; extern struct cmd_list_element *showchecklist; +/* Chain containing all defined "save" subcommands. */ + +extern struct cmd_list_element *save_cmdlist; + extern void execute_command (char *, int); extern char *execute_command_to_string (char *p, int from_tty); 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..9638368 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -66,6 +66,9 @@ struct thread_info /* Step-resume or longjmp-resume breakpoint. */ struct breakpoint *step_resume_breakpoint; + /* Exception-resume breakpoint. */ + struct breakpoint *exception_resume_breakpoint; + /* Range to single step within. If this is nonzero, respond to a single-step signal by continuing @@ -185,6 +188,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; @@ -221,6 +228,9 @@ extern void delete_thread_silent (ptid_t); /* Delete a step_resume_breakpoint from the thread database. */ extern void delete_step_resume_breakpoint (struct thread_info *); +/* Delete an exception_resume_breakpoint from the thread database. */ +extern void delete_exception_resume_breakpoint (struct thread_info *); + /* Translate the integer thread id (GDB's homegrown id, not the system's) into a "pid" (which may be overloaded with extra thread information). */ extern ptid_t thread_id_to_pid (int); diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 443f6f7..d852a14 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. */ @@ -123,6 +126,11 @@ 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); +/* 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 @@ -153,6 +161,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. */ @@ -278,7 +319,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; } @@ -355,7 +396,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 +767,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 +867,45 @@ create_array_type (struct type *result_type, TYPE_CODE (result_type) = TYPE_CODE_ARRAY; TYPE_TARGET_TYPE (result_type) = element_type; - if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0) - low_bound = high_bound = 0; - CHECK_TYPEDEF (element_type); - /* Be careful when setting the array length. Ada arrays can be - empty arrays with the high_bound being smaller than the low_bound. - In such cases, the array length should be zero. */ - if (high_bound < low_bound) - TYPE_LENGTH (result_type) = 0; - else - TYPE_LENGTH (result_type) = - TYPE_LENGTH (element_type) * (high_bound - low_bound + 1); TYPE_NFIELDS (result_type) = 1; TYPE_FIELDS (result_type) = (struct field *) TYPE_ZALLOC (result_type, sizeof (struct field)); TYPE_INDEX_TYPE (result_type) = range_type; TYPE_VPTR_FIELDNO (result_type) = -1; - /* TYPE_FLAG_TARGET_STUB will take care of zero length arrays */ + /* DWARF blocks may depend on runtime information like + DW_OP_PUSH_OBJECT_ADDRESS not being available during the + CREATE_ARRAY_TYPE time. */ + if (TYPE_RANGE_DATA (range_type)->low.kind != RANGE_BOUND_KIND_CONSTANT + || TYPE_RANGE_DATA (range_type)->high.kind != RANGE_BOUND_KIND_CONSTANT + || 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; } @@ -1353,6 +1414,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 @@ -1486,52 +1646,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) @@ -1539,9 +1683,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; } @@ -1811,6 +1958,8 @@ init_type (enum type_code code, int length, int flags, TYPE_NOTTEXT (type) = 1; if (flags & TYPE_FLAG_FIXED_INSTANCE) TYPE_FIXED_INSTANCE (type) = 1; + if (flags & TYPE_FLAG_GNU_IFUNC) + TYPE_GNU_IFUNC (type) = 1; if (name) TYPE_NAME (type) = obsavestring (name, strlen (name), @@ -3006,33 +3155,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; @@ -3047,8 +3205,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; @@ -3059,6 +3219,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)) @@ -3067,12 +3240,48 @@ 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; + /* TYPE_CODE_RANGE uses TYPE_RANGE_DATA of the union with TYPE_FIELDS. */ + gdb_assert (TYPE_CODE (type) != TYPE_CODE_RANGE); + nfields = TYPE_NFIELDS (type); + TYPE_NFIELDS (new_type) = nfields; TYPE_FIELDS (new_type) = XCALLOC (nfields, struct field); for (i = 0; i < nfields; i++) { @@ -3081,8 +3290,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)); @@ -3109,24 +3318,166 @@ 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) + if (TYPE_CODE (new_type) == TYPE_CODE_RANGE) { TYPE_RANGE_DATA (new_type) = xmalloc (sizeof (struct range_bounds)); *TYPE_RANGE_DATA (new_type) = *TYPE_RANGE_DATA (type); + + switch (TYPE_RANGE_DATA (new_type)->low.kind) + { + case RANGE_BOUND_KIND_CONSTANT: + break; + case RANGE_BOUND_KIND_DWARF_BLOCK: + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type) + || ! has_stack_frames ()) + { + /* We should set 1 for Fortran but how to find the language? */ + TYPE_LOW_BOUND (new_type) = 0; + TYPE_LOW_BOUND_UNDEFINED (new_type) = 1; + } + else + TYPE_LOW_BOUND (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->low.u.dwarf_block); + TYPE_RANGE_DATA (new_type)->low.kind = RANGE_BOUND_KIND_CONSTANT; + break; + case RANGE_BOUND_KIND_DWARF_LOCLIST: + { + CORE_ADDR addr; + + /* `struct dwarf2_loclist_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (! TYPE_NOT_ALLOCATED (new_type) + && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames () + && dwarf_loclist_baton_eval + (TYPE_RANGE_DATA (new_type)->low.u.dwarf_loclist.loclist, + TYPE_RANGE_DATA (new_type)->low.u.dwarf_loclist.type, &addr)) + TYPE_LOW_BOUND (new_type) = addr; + else + { + /* We should set 1 for Fortran but how to find the language? */ + TYPE_LOW_BOUND (new_type) = 0; + TYPE_LOW_BOUND_UNDEFINED (new_type) = 1; + } + TYPE_RANGE_DATA (new_type)->low.kind = RANGE_BOUND_KIND_CONSTANT; + } + break; + } + + switch (TYPE_RANGE_DATA (new_type)->high.kind) + { + case RANGE_BOUND_KIND_CONSTANT: + break; + case RANGE_BOUND_KIND_DWARF_BLOCK: + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type) + || ! has_stack_frames ()) + { + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type) - 1; + TYPE_HIGH_BOUND_UNDEFINED (new_type) = 1; + } + else + TYPE_HIGH_BOUND (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->high.u.dwarf_block); + TYPE_RANGE_DATA (new_type)->high.kind = RANGE_BOUND_KIND_CONSTANT; + break; + case RANGE_BOUND_KIND_DWARF_LOCLIST: + { + CORE_ADDR addr; + + /* `struct dwarf2_loclist_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (! TYPE_NOT_ALLOCATED (new_type) + && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames () + && dwarf_loclist_baton_eval + (TYPE_RANGE_DATA (new_type)->high.u.dwarf_loclist.loclist, + TYPE_RANGE_DATA (new_type)->high.u.dwarf_loclist.type, + &addr)) + TYPE_HIGH_BOUND (new_type) = addr; + else + { + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type) - 1; + TYPE_HIGH_BOUND_UNDEFINED (new_type) = 1; + } + TYPE_RANGE_DATA (new_type)->high.kind = RANGE_BOUND_KIND_CONSTANT; + } + break; + } + + switch (TYPE_RANGE_DATA (new_type)->byte_stride.kind) + { + case RANGE_BOUND_KIND_CONSTANT: + break; + case RANGE_BOUND_KIND_DWARF_BLOCK: + /* `struct dwarf2_locexpr_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (TYPE_NOT_ALLOCATED (new_type) || TYPE_NOT_ASSOCIATED (new_type) + || ! has_stack_frames ()) + TYPE_BYTE_STRIDE (new_type) = 0; + else + TYPE_BYTE_STRIDE (new_type) = dwarf_locexpr_baton_eval + (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_block); + TYPE_RANGE_DATA (new_type)->byte_stride.kind + = RANGE_BOUND_KIND_CONSTANT; + break; + case RANGE_BOUND_KIND_DWARF_LOCLIST: + { + CORE_ADDR addr = 0; + + /* `struct dwarf2_loclist_baton' is too bound to its objfile so + it is expected to be made constant by CHECK_TYPEDEF. + TYPE_NOT_ALLOCATED and TYPE_NOT_ASSOCIATED are not valid for TYPE. + */ + if (! TYPE_NOT_ALLOCATED (new_type) + && ! TYPE_NOT_ASSOCIATED (new_type) && has_stack_frames ()) + dwarf_loclist_baton_eval + (TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_loclist.loclist, + TYPE_RANGE_DATA (new_type)->byte_stride.u.dwarf_loclist.type, + &addr); + TYPE_BYTE_STRIDE (new_type) = addr; + TYPE_RANGE_DATA (new_type)->byte_stride.kind + = RANGE_BOUND_KIND_CONSTANT; + } + break; + } + + /* Convert TYPE_RANGE_HIGH_BOUND_IS_COUNT into a regular bound. */ + if (TYPE_RANGE_HIGH_BOUND_IS_COUNT (new_type)) + { + TYPE_HIGH_BOUND (new_type) = TYPE_LOW_BOUND (new_type) + + TYPE_HIGH_BOUND (new_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 @@ -3143,6 +3494,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. @@ -3165,6 +3527,199 @@ copy_type (const struct type *type) return new_type; } +/* Callback type for main_type_crawl. */ +typedef int (*main_type_crawl_iter) (struct type *type, void *data); + +/* Iterate all main_type structures reachable through any `struct type *' from + TYPE. ITER will be called only for one type of each main_type, use + TYPE_CHAIN traversal to find all the type instances. ITER is being called + for each main_type found. ITER returns non-zero if main_type_crawl should + depth-first enter the specific type. ITER must provide some detection for + reentering the same main_type as this function would otherwise endlessly + loop. */ + +static void +main_type_crawl (struct type *type, main_type_crawl_iter iter, void *data) +{ + struct type *type_iter; + int i; + + if (!type) + return; + + gdb_assert (TYPE_OBJFILE (type) == NULL); + + /* `struct cplus_struct_type' handling is unsupported by this function. */ + gdb_assert ((TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + || !HAVE_CPLUS_STRUCT (type)); + + if (!(*iter) (type, data)) + return; + + /* Iterate all the type instances of this main_type. */ + type_iter = type; + do + { + gdb_assert (TYPE_MAIN_TYPE (type_iter) == TYPE_MAIN_TYPE (type)); + + main_type_crawl (TYPE_POINTER_TYPE (type), iter, data); + main_type_crawl (TYPE_REFERENCE_TYPE (type), iter, data); + + type_iter = TYPE_CHAIN (type_iter); + } + while (type_iter != type); + + for (i = 0; i < TYPE_NFIELDS (type); i++) + main_type_crawl (TYPE_FIELD_TYPE (type, i), iter, data); + + main_type_crawl (TYPE_TARGET_TYPE (type), iter, data); + main_type_crawl (TYPE_VPTR_BASETYPE (type), iter, data); +} + +/* A helper for delete_type which deletes a main_type and the things to which + it refers. TYPE is a type whose main_type we wish to destroy. */ + +static void +delete_main_type (struct type *type) +{ + int i; + + gdb_assert (TYPE_DISCARDABLE (type)); + gdb_assert (TYPE_OBJFILE (type) == NULL); + + xfree (TYPE_NAME (type)); + xfree (TYPE_TAG_NAME (type)); + + for (i = 0; i < TYPE_NFIELDS (type); ++i) + { + xfree (TYPE_FIELD_NAME (type, i)); + + if (TYPE_FIELD_LOC_KIND (type, i) == FIELD_LOC_KIND_PHYSNAME) + xfree (TYPE_FIELD_STATIC_PHYSNAME (type, i)); + } + xfree (TYPE_FIELDS (type)); + + gdb_assert (!HAVE_CPLUS_STRUCT (type)); + + xfree (TYPE_MAIN_TYPE (type)); +} + +/* Delete all the instances on TYPE_CHAIN of TYPE, including their referenced + main_type. TYPE must be a reclaimable type - neither permanent nor objfile + associated. */ + +static void +delete_type_chain (struct type *type) +{ + struct type *type_iter, *type_iter_to_free; + + gdb_assert (TYPE_DISCARDABLE (type)); + gdb_assert (TYPE_OBJFILE (type) == NULL); + + delete_main_type (type); + + type_iter = type; + do + { + type_iter_to_free = type_iter; + type_iter = TYPE_CHAIN (type_iter); + xfree (type_iter_to_free); + } + while (type_iter != type); +} + +/* Hash function for type_discardable_table. */ + +static hashval_t +type_discardable_hash (const void *p) +{ + const struct type *type = p; + + return htab_hash_pointer (TYPE_MAIN_TYPE (type)); +} + +/* Equality function for type_discardable_table. */ + +static int +type_discardable_equal (const void *a, const void *b) +{ + const struct type *left = a; + const struct type *right = b; + + return TYPE_MAIN_TYPE (left) == TYPE_MAIN_TYPE (right); +} + +/* A helper for type_mark_used. */ + +static int +type_mark_used_crawl (struct type *type, void *unused) +{ + if (!TYPE_DISCARDABLE (type)) + return 0; + + if (TYPE_DISCARDABLE_AGE (type) == type_discardable_age_current) + return 0; + + TYPE_DISCARDABLE_AGE (type) = type_discardable_age_current; + + /* Continue the traversal. */ + return 1; +} + +/* Mark TYPE and its connected types as used in this free_all_types pass. */ + +void +type_mark_used (struct type *type) +{ + if (type == NULL) + return; + + if (!TYPE_DISCARDABLE (type)) + return; + + main_type_crawl (type, type_mark_used_crawl, NULL); +} + +/* A traverse callback for type_discardable_table which removes any + type_discardable whose reference count is now zero (unused link). */ + +static int +type_discardable_remove (void **slot, void *unused) +{ + struct type *type = *slot; + + gdb_assert (TYPE_DISCARDABLE (type)); + + if (TYPE_DISCARDABLE_AGE (type) != type_discardable_age_current) + { + delete_type_chain (type); + + htab_clear_slot (type_discardable_table, slot); + } + + return 1; +} + +/* Free all the reclaimable types that have been allocated and that have + currently zero reference counter. + + This function is called after each command, successful or not. Use this + cleanup only in the GDB idle state as GDB only marks those types used by + globally tracked objects (with no autovariable references tracking). */ + +void +free_all_types (void) +{ + /* Mark a new pass. As GDB checks all the entries were visited after each + pass there cannot be any stale entries already containing the changed + value. */ + type_discardable_age_current ^= 1; + + observer_notify_mark_used (); + + htab_traverse (type_discardable_table, type_discardable_remove, NULL); +} /* Helper functions to initialize architecture-specific types. */ @@ -3511,6 +4066,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch) = lookup_pointer_type (builtin_type->builtin_void); builtin_type->builtin_func_ptr = lookup_pointer_type (lookup_function_type (builtin_type->builtin_void)); + builtin_type->builtin_func_func + = lookup_function_type (builtin_type->builtin_func_ptr); /* This type represents a GDB internal function. */ builtin_type->internal_fn @@ -3624,6 +4181,18 @@ objfile_type (struct objfile *objfile) "", objfile); TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol) = objfile_type->builtin_int; + objfile_type->nodebug_text_gnu_ifunc_symbol + = init_type (TYPE_CODE_FUNC, 1, TYPE_FLAG_GNU_IFUNC, + "", + objfile); + TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol) + = objfile_type->nodebug_text_symbol; + objfile_type->nodebug_got_plt_symbol + = init_type (TYPE_CODE_PTR, gdbarch_addr_bit (gdbarch) / 8, 0, + "", + objfile); + TYPE_TARGET_TYPE (objfile_type->nodebug_got_plt_symbol) + = objfile_type->nodebug_text_symbol; objfile_type->nodebug_data_symbol = init_type (TYPE_CODE_INT, gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0, @@ -3678,6 +4247,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 085270e..cb2b88e 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -171,6 +171,7 @@ enum type_flag_value TYPE_FLAG_FIXED_INSTANCE = (1 << 15), TYPE_FLAG_STUB_SUPPORTED = (1 << 16), TYPE_FLAG_NOTTEXT = (1 << 17), + TYPE_FLAG_GNU_IFUNC = (1 << 18), /* Used for error-checking. */ TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED @@ -214,6 +215,11 @@ enum type_instance_flag_value #define TYPE_TARGET_STUB(t) (TYPE_MAIN_TYPE (t)->flag_target_stub) +/* Type needs to be evaluated on each CHECK_TYPEDEF and its results must not be + sticky. */ + +#define TYPE_DYNAMIC(t) (TYPE_MAIN_TYPE (t)->flag_dynamic) + /* Static type. If this is set, the corresponding type had * a static modifier. * Note: This may be unnecessary, since static data members @@ -271,6 +277,12 @@ enum type_instance_flag_value #define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext) +/* Used only for TYPE_CODE_FUNC where it specifies the real function + address is returned by this function call. TYPE_TARGET_TYPE determines the + final returned function type to be presented to user. */ + +#define TYPE_GNU_IFUNC(t) (TYPE_MAIN_TYPE (t)->flag_gnu_ifunc) + /* Type owner. If TYPE_OBJFILE_OWNED is true, the type is owned by the objfile retrieved as TYPE_OBJFILE. Otherweise, the type is owned by an architecture; TYPE_OBJFILE is NULL in this case. */ @@ -285,6 +297,48 @@ enum type_instance_flag_value #define TYPE_DECLARED_CLASS(t) (TYPE_MAIN_TYPE (t)->flag_declared_class) +/* 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. */ @@ -389,11 +443,19 @@ struct main_type unsigned int flag_vector : 1; unsigned int flag_stub_supported : 1; unsigned int flag_nottext : 1; + unsigned int flag_gnu_ifunc : 1; unsigned int flag_fixed_instance : 1; unsigned int flag_objfile_owned : 1; /* True if this type was declared with "class" rather than "struct". */ unsigned int flag_declared_class : 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. */ @@ -467,6 +529,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. @@ -540,13 +616,34 @@ struct main_type struct range_bounds { + struct + { + union + { + LONGEST constant; + struct dwarf2_locexpr_baton *dwarf_block; + struct + { + struct dwarf2_loclist_baton *loclist; + struct type *type; + } + dwarf_loclist; + } + u; + enum range_bound_kind + { + RANGE_BOUND_KIND_CONSTANT, + RANGE_BOUND_KIND_DWARF_BLOCK, + RANGE_BOUND_KIND_DWARF_LOCLIST + } + kind; + } /* 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 @@ -889,9 +986,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 @@ -899,11 +996,16 @@ extern void allocate_gnat_aux_type (struct type *); #define TYPE_CODE(thistype) TYPE_MAIN_TYPE(thistype)->code #define TYPE_NFIELDS(thistype) TYPE_MAIN_TYPE(thistype)->nfields #define TYPE_FIELDS(thistype) TYPE_MAIN_TYPE(thistype)->flds_bnds.fields +#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) \ @@ -920,7 +1022,14 @@ extern void allocate_gnat_aux_type (struct type *); (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++ */ @@ -1141,6 +1250,10 @@ struct builtin_type (*) () can server as a generic function pointer. */ struct type *builtin_func_ptr; + /* `function returning pointer to function (returning void)' type. + The final void return type is not significant for it. */ + struct type *builtin_func_func; + /* Special-purpose types. */ @@ -1181,6 +1294,8 @@ struct objfile_type /* Types used for symbols with no debug information. */ struct type *nodebug_text_symbol; + struct type *nodebug_text_gnu_ifunc_symbol; + struct type *nodebug_got_plt_symbol; struct type *nodebug_data_symbol; struct type *nodebug_unknown_symbol; struct type *nodebug_tls_symbol; @@ -1328,6 +1443,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); @@ -1370,6 +1497,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]) @@ -1432,10 +1561,11 @@ extern void maintenance_print_type (char *, int); extern htab_t create_copied_types_hash (struct objfile *objfile); -extern struct type *copy_type_recursive (struct objfile *objfile, - struct type *type, +extern struct type *copy_type_recursive (struct type *type, htab_t copied_types); extern struct type *copy_type (const struct type *type); +extern void free_all_types (void); + #endif /* GDBTYPES_H */ diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 4fce1ac..144a899 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -747,6 +747,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) { @@ -976,6 +991,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 eaa3644..0921c7e 100644 --- a/gdb/i386-nat.c +++ b/gdb/i386-nat.c @@ -533,6 +533,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. */ @@ -685,6 +696,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/infcall.c b/gdb/infcall.c index 0c9a3af..957ec1d 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -225,6 +225,56 @@ value_arg_coerce (struct gdbarch *gdbarch, struct value *arg, return value_cast (type, arg); } +/* Call gnu-ifunc (STT_GNU_IFUNC - a function returning addresss of a real + function to call). PC is the gnu-ifunc function entry. Function returns + function entry of the gnu-ifunc-resolved function to call. If RETVAL_TYPEP + is not NULL fill in *RETVAL_TYPEP with return type of the gnu-ifunc-resolved + function to call. Keep *RETVAL_TYPEP intact if the return type could not be + found. */ + +static CORE_ADDR +gnu_ifunc_resolve (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + char *name_at_pc; + CORE_ADDR start_at_pc, address; + struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func; + struct value *function, *address_val; + + if (find_pc_partial_function (pc, &name_at_pc, &start_at_pc, NULL) + && start_at_pc == pc) + { + if (resolve_gnu_ifunc (name_at_pc, &address)) + return address; + } + else + name_at_pc = NULL; + + function = allocate_value (func_func_type); + set_value_address (function, pc); + + /* gnu-ifuncs have no arguments. FUNCTION is the function entry address + while ADDRESS is a possible function descriptor.. */ + address_val = call_function_by_hand (function, 0, NULL); + address = value_as_address (address_val); + + if (name_at_pc) + gnu_ifunc_record_cache (gdbarch, name_at_pc, address); + + return gdbarch_convert_from_func_ptr_addr (gdbarch, address, ¤t_target); +} + +static struct type * +find_function_return_type (CORE_ADDR pc) +{ + struct symbol *sym = find_pc_function (pc); + + if (sym != NULL && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == pc + && SYMBOL_TYPE (sym) != NULL) + return TYPE_TARGET_TYPE (SYMBOL_TYPE (sym)); + + return NULL; +} + /* Determine a function's address and its return type from its value. Calls error() if the function is not valid for calling. */ @@ -233,7 +283,6 @@ find_function_addr (struct value *function, struct type **retval_type) { struct type *ftype = check_typedef (value_type (function)); struct gdbarch *gdbarch = get_type_arch (ftype); - enum type_code code = TYPE_CODE (ftype); struct type *value_type = NULL; CORE_ADDR funaddr; @@ -241,24 +290,34 @@ find_function_addr (struct value *function, struct type **retval_type) part of it. */ /* Determine address to call. */ - if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) - { - funaddr = value_address (function); - value_type = TYPE_TARGET_TYPE (ftype); - } - else if (code == TYPE_CODE_PTR) + if (TYPE_CODE (ftype) == TYPE_CODE_FUNC + || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + funaddr = value_address (function); + else if (TYPE_CODE (ftype) == TYPE_CODE_PTR) { funaddr = value_as_address (function); ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); if (TYPE_CODE (ftype) == TYPE_CODE_FUNC || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, + ¤t_target); + } + if (TYPE_CODE (ftype) == TYPE_CODE_FUNC + || TYPE_CODE (ftype) == TYPE_CODE_METHOD) + { + value_type = TYPE_TARGET_TYPE (ftype); + + if (TYPE_GNU_IFUNC (ftype)) { - funaddr = gdbarch_convert_from_func_ptr_addr (gdbarch, funaddr, - ¤t_target); - value_type = TYPE_TARGET_TYPE (ftype); + funaddr = gnu_ifunc_resolve (gdbarch, funaddr); + + /* Skip querying the function symbol if no RETVAL_TYPE has been + asked for. */ + if (retval_type) + value_type = find_function_return_type (funaddr); } } - else if (code == TYPE_CODE_INT) + else if (TYPE_CODE (ftype) == TYPE_CODE_INT) { /* Handle the case of functions lacking debugging info. Their values are characters since their addresses are char */ diff --git a/gdb/infcmd.c b/gdb/infcmd.c index c4cdb06..d213f6a 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -822,7 +822,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; @@ -862,10 +862,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); } @@ -1219,6 +1222,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. @@ -1235,6 +1247,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 (); @@ -1270,7 +1284,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 @@ -1463,6 +1489,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 @@ -1546,6 +1573,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); @@ -1556,6 +1584,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 5abec68..e309277 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -291,6 +291,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 54b1d9f..58d045a 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" @@ -367,6 +369,7 @@ follow_fork (void) parent thread structure's run control related fields, not just these. Initialized to avoid "may be used uninitialized" warnings from gcc. */ struct breakpoint *step_resume_breakpoint = NULL; + struct breakpoint *exception_resume_breakpoint = NULL; CORE_ADDR step_range_start = 0; CORE_ADDR step_range_end = 0; struct frame_id step_frame_id = { 0 }; @@ -419,6 +422,8 @@ follow_fork (void) step_range_start = tp->step_range_start; step_range_end = tp->step_range_end; step_frame_id = tp->step_frame_id; + exception_resume_breakpoint + = clone_momentary_breakpoint (tp->exception_resume_breakpoint); /* For now, delete the parent's sr breakpoint, otherwise, parent/child sr breakpoints are considered duplicates, @@ -429,6 +434,7 @@ follow_fork (void) tp->step_range_start = 0; tp->step_range_end = 0; tp->step_frame_id = null_frame_id; + delete_exception_resume_breakpoint (tp); } parent = inferior_ptid; @@ -470,6 +476,8 @@ follow_fork (void) tp->step_range_start = step_range_start; tp->step_range_end = step_range_end; tp->step_frame_id = step_frame_id; + tp->exception_resume_breakpoint + = exception_resume_breakpoint; } else { @@ -523,6 +531,9 @@ follow_inferior_reset_breakpoints (void) if (tp->step_resume_breakpoint) breakpoint_re_set_thread (tp->step_resume_breakpoint); + if (tp->exception_resume_breakpoint) + breakpoint_re_set_thread (tp->exception_resume_breakpoint); + /* Reinsert all breakpoints in the child. The user may have set breakpoints after catching the fork, in which case those were never set in the child, but only in the parent. This makes @@ -760,6 +771,7 @@ follow_exec (ptid_t pid, char *execd_pathname) /* If there was one, it's gone now. We cannot truly step-to-next statement through an exec(). */ th->step_resume_breakpoint = NULL; + th->exception_resume_breakpoint = NULL; th->step_range_start = 0; th->step_range_end = 0; @@ -2190,6 +2202,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); @@ -2313,6 +2327,7 @@ delete_step_resume_breakpoint_callback (struct thread_info *info, void *data) return 0; delete_step_resume_breakpoint (info); + delete_exception_resume_breakpoint (info); return 0; } @@ -2337,6 +2352,7 @@ delete_step_thread_step_resume_breakpoint (void) struct thread_info *tp = inferior_thread (); delete_step_resume_breakpoint (tp); + delete_exception_resume_breakpoint (tp); } else /* In all-stop mode, delete all step-resume and longjmp-resume @@ -3241,6 +3257,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); @@ -3328,6 +3348,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); @@ -4076,23 +4100,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; @@ -4101,8 +4135,52 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); - gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL); - delete_step_resume_breakpoint (ecs->event_thread); + if (what.is_longjmp) + { + gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL); + delete_step_resume_breakpoint (ecs->event_thread); + } + else + { + /* 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. We stop, because the exception has been + caught. + + 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); + + gdb_assert (ecs->event_thread->exception_resume_breakpoint != NULL); + delete_exception_resume_breakpoint (ecs->event_thread); + + 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)) + { + /* Case 2. Fall through. */ + } + else + { + /* Case 3. */ + keep_going (ecs); + return; + } + } + + /* For Cases 1 and 2, remove the step-resume breakpoint, + if it exists. */ + delete_step_resume_breakpoint (ecs->event_thread); + } ecs->event_thread->stop_step = 1; print_stop_reason (END_STEPPING_RANGE, 0); @@ -5070,6 +5148,97 @@ 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); + /* If the value was optimized out, revert to the old behavior. */ + if (! value_optimized_out (value)) + { + handler = value_as_address (value); + + 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); + bp->thread = tp->num; + inferior_thread ()->exception_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/linux-nat.c b/gdb/linux-nat.c index 93adfcd..34412a6 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -2587,6 +2587,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 @@ -5606,6 +5639,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/linux-tdep.c b/gdb/linux-tdep.c index 07fd67c..2524250 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -23,6 +23,8 @@ #include "auxv.h" #include "target.h" #include "elf/common.h" +#include "value.h" +#include "infcall.h" /* This function is suitable for architectures that don't extend/override the standard siginfo structure. */ diff --git a/gdb/main.c b/gdb/main.c index bfd1213..72faabd 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -39,6 +39,7 @@ #include "interps.h" #include "main.h" +#include "python/python.h" #include "source.h" #include "cli/cli-cmds.h" #include "python/python.h" @@ -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; @@ -443,10 +446,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; @@ -464,6 +471,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; @@ -650,7 +660,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 @@ -890,7 +924,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_flag) { @@ -901,13 +936,25 @@ Can't attach to process and specify a core file at the same time.")); /* Show time and/or space usage. */ do_cleanups (pre_stat_chain); - /* 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. */ } @@ -939,7 +986,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 (_("\ @@ -977,7 +1029,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 28fd610..4e21476 100644 --- a/gdb/maint.c +++ b/gdb/maint.c @@ -909,4 +909,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 310ade9..d8710a1 100644 --- a/gdb/mi/mi-cmd-var.c +++ b/gdb/mi/mi-cmd-var.c @@ -702,7 +702,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/minsyms.c b/gdb/minsyms.c index cb4545c..92d4027 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -337,8 +337,9 @@ lookup_minimal_symbol_text (const char *name, struct objfile *objf) msymbol = msymbol->hash_next) { if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 && - (MSYMBOL_TYPE (msymbol) == mst_text || - MSYMBOL_TYPE (msymbol) == mst_file_text)) + (MSYMBOL_TYPE (msymbol) == mst_text + || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc + || MSYMBOL_TYPE (msymbol) == mst_file_text)) { switch (MSYMBOL_TYPE (msymbol)) { @@ -700,6 +701,16 @@ lookup_minimal_symbol_by_pc (CORE_ADDR pc) return lookup_minimal_symbol_by_pc_section (pc, NULL); } +/* Return non-zero iff PC is in function implementing gnu-ifunc selection. */ + +int +in_gnu_ifunc_stub (CORE_ADDR pc) +{ + struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); + + return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc; +} + /* Find the minimal symbol named NAME, and return both the minsym struct and its objfile. This only checks the linkage name. Sets *OBJFILE_P and returns the minimal symbol, if it is found. If it @@ -769,6 +780,7 @@ prim_record_minimal_symbol (const char *name, CORE_ADDR address, switch (ms_type) { case mst_text: + case mst_text_gnu_ifunc: case mst_file_text: case mst_solib_trampoline: section = SECT_OFF_TEXT (objfile); @@ -1235,7 +1247,8 @@ find_solib_trampoline_target (struct frame_info *frame, CORE_ADDR pc) { ALL_MSYMBOLS (objfile, msymbol) { - if (MSYMBOL_TYPE (msymbol) == mst_text + if ((MSYMBOL_TYPE (msymbol) == mst_text + || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc) && strcmp (SYMBOL_LINKAGE_NAME (msymbol), SYMBOL_LINKAGE_NAME (tsymbol)) == 0) return SYMBOL_VALUE_ADDRESS (msymbol); diff --git a/gdb/p-lang.c b/gdb/p-lang.c index 08738ac..64d2e9f 100644 --- a/gdb/p-lang.c +++ b/gdb/p-lang.c @@ -222,7 +222,11 @@ pascal_printstr (struct ui_file *stream, struct type *type, unsigned int things_printed = 0; int in_quotes = 0; int need_comma = 0; - int width = TYPE_LENGTH (type); + int width; + + /* Preserve TYPE's original type, just set its LENGTH. */ + check_typedef (type); + width = TYPE_LENGTH (type); /* If the string was not truncated due to `set print elements', and the last byte of it is a null, we don't print that, in traditional C diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 4d39bed..d0ddebc 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -38,6 +38,7 @@ #include "p-lang.h" #include "cp-abi.h" #include "cp-support.h" +#include "dwarf2loc.h" @@ -68,8 +69,27 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct type *char_type; LONGEST val; CORE_ADDR addr; + struct cleanup *back_to; + struct type *saved_type = type; + CORE_ADDR saved_address = address; + + back_to = make_cleanup (null_cleanup, 0); + type = object_address_get_data (type, &address); + if (type == NULL) + { + fputs_filtered (object_address_data_not_valid (saved_type), stream); + gdb_flush (stream); + do_cleanups (back_to); + return 0; + } + if (address != saved_address) + { + size_t length = TYPE_LENGTH (type); - CHECK_TYPEDEF (type); + valaddr = xmalloc (length); + make_cleanup (xfree, (gdb_byte *) valaddr); + read_memory (address, (gdb_byte *) valaddr, length); + } switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: @@ -125,8 +145,9 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, { i = 0; } - val_print_array_elements (type, valaddr + embedded_offset, address, stream, - recurse, original_value, options, i); + val_print_array_elements (saved_type, valaddr + embedded_offset, + saved_address, stream, recurse, + original_value, options, i); fprintf_filtered (stream, "}"); } break; @@ -164,6 +185,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, /* Try to print what function it points to. */ print_address_demangle (gdbarch, addr, stream, demangle); /* Return value is irrelevant except for string pointers. */ + do_cleanups (back_to); return (0); } @@ -252,6 +274,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, /* Return number of characters printed, including the terminating '\0' if we reached the end. val_print_string takes care including the terminating '\0' if necessary. */ + do_cleanups (back_to); return i; break; @@ -554,6 +577,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, error (_("Invalid pascal type code %d in symbol table."), TYPE_CODE (type)); } gdb_flush (stream); + do_cleanups (back_to); return (0); } diff --git a/gdb/parse.c b/gdb/parse.c index c885c6a..cbf9c65 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -487,9 +487,21 @@ write_exp_msymbol (struct minimal_symbol *msymbol) pc = gdbarch_convert_from_func_ptr_addr (gdbarch, addr, ¤t_target); if (pc != addr) { + struct minimal_symbol *ifunc_msym = lookup_minimal_symbol_by_pc (pc); + /* In this case, assume we have a code symbol instead of a data symbol. */ - type = mst_text; + + if (ifunc_msym != NULL && MSYMBOL_TYPE (ifunc_msym) == mst_text_gnu_ifunc + && SYMBOL_VALUE_ADDRESS (ifunc_msym) == pc) + { + /* A function descriptor has been resolved but PC is still in the + gnu-ifunc resolver body (such as because inferior does not run to + be able to call it). */ + type = mst_text_gnu_ifunc; + } + else + type = mst_text; section = NULL; addr = pc; } @@ -521,6 +533,11 @@ write_exp_msymbol (struct minimal_symbol *msymbol) write_exp_elt_type (objfile_type (objfile)->nodebug_text_symbol); break; + case mst_text_gnu_ifunc: + write_exp_elt_type (objfile_type (objfile) + ->nodebug_text_gnu_ifunc_symbol); + break; + case mst_data: case mst_file_data: case mst_bss: @@ -528,6 +545,10 @@ write_exp_msymbol (struct minimal_symbol *msymbol) write_exp_elt_type (objfile_type (objfile)->nodebug_data_symbol); break; + case mst_slot_got_plt: + write_exp_elt_type (objfile_type (objfile)->nodebug_got_plt_symbol); + break; + default: write_exp_elt_type (objfile_type (objfile)->nodebug_unknown_symbol); break; @@ -1412,6 +1433,7 @@ parser_fprintf (FILE *x, const char *y, ...) 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) @@ -1453,7 +1475,7 @@ operator_check_standard (struct expression *exp, int pos, struct type *type = elts[pos + 2 + arg].type; struct objfile *objfile = TYPE_OBJFILE (type); - if (objfile && (*objfile_func) (objfile, data)) + if (objfile && objfile_func && (*objfile_func) (objfile, data)) return 1; } } @@ -1471,7 +1493,8 @@ operator_check_standard (struct expression *exp, int pos, /* Check objfile where the variable itself is placed. SYMBOL_OBJ_SECTION (symbol) may be NULL. */ - if ((*objfile_func) (SYMBOL_SYMTAB (symbol)->objfile, data)) + if (objfile_func + && (*objfile_func) (SYMBOL_SYMTAB (symbol)->objfile, data)) return 1; /* Check objfile where is placed the code touching the variable. */ @@ -1484,24 +1507,27 @@ operator_check_standard (struct expression *exp, int pos, /* Invoke callbacks for TYPE and OBJFILE if they were set as non-NULL. */ - if (type && TYPE_OBJFILE (type) + 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, data)) + if (objfile && objfile_func && (*objfile_func) (objfile, data)) return 1; return 0; } -/* Call OBJFILE_FUNC for any TYPE and OBJFILE found being referenced by EXP. - The functions are never called with 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. - */ +/* 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) { @@ -1516,7 +1542,9 @@ exp_iterate (struct expression *exp, pos = endpos - oplen; if (exp->language_defn->la_exp_desc->operator_check (exp, pos, - objfile_func, data)) + type_func, + objfile_func, + data)) return 1; endpos = pos; @@ -1547,7 +1575,26 @@ exp_uses_objfile (struct expression *exp, struct objfile *objfile) { gdb_assert (objfile->separate_debug_objfile_backlink == NULL); - return exp_iterate (exp, exp_uses_objfile_iter, 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 diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index bb79ae1..fbbd600 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -194,6 +194,8 @@ extern void operator_length_standard (const 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); @@ -285,6 +287,7 @@ struct exp_descriptor 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); @@ -323,4 +326,8 @@ extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3); extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile); +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 18ddee7..652b02a 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -2010,6 +2010,24 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw, return ret; } +/* 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) { @@ -2349,6 +2367,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 5ffa099..58d9c79 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -971,6 +971,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)) { @@ -1471,6 +1476,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. @@ -2869,4 +2890,6 @@ Show printing of source filename and line number with ."), NULL, add_com ("eval", no_class, eval_command, _("\ Convert \"printf format string\", arg1, arg2, arg3, ..., argn to\n\ a command line, and call it.")); + + observer_attach_mark_used (print_types_mark_used); } diff --git a/gdb/psymtab.c b/gdb/psymtab.c index 97a4eec..fce19c9 100644 --- a/gdb/psymtab.c +++ b/gdb/psymtab.c @@ -421,6 +421,14 @@ lookup_symbol_aux_psymtabs (struct objfile *objfile, return NULL; } +static void +pre_expand_symtabs_matching_psymtabs (struct objfile *objfile, + int kind, const char *name, + domain_enum domain) +{ + /* Nothing. */ +} + /* Look, in partial_symtab PST, for symbol whose natural name is NAME. Check the global symbols if GLOBAL, the static symbols if not. */ @@ -941,7 +949,7 @@ psymtab_to_fullname (struct partial_symtab *ps) return NULL; } -static char * +static const char * find_symbol_file_from_partial (struct objfile *objfile, const char *name) { struct partial_symtab *pst; @@ -1199,6 +1207,7 @@ const struct quick_symbol_functions psym_functions = forget_cached_source_info_partial, lookup_symtab_via_partial_symtab, lookup_symbol_aux_psymtabs, + pre_expand_symtabs_matching_psymtabs, print_psymtab_stats_for_objfile, dump_psymtabs_for_objfile, relocate_psymtabs, diff --git a/gdb/psymtab.h b/gdb/psymtab.h index 9b8c8df..de8b67e 100644 --- a/gdb/psymtab.h +++ b/gdb/psymtab.h @@ -1,6 +1,6 @@ /* Public partial symbol table definitions. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. This file is part of GDB. @@ -28,4 +28,6 @@ void map_partial_symbol_filenames (void (*) (const char *, const char *, extern const struct quick_symbol_functions psym_functions; +extern const struct quick_symbol_functions dwarf2_gdb_index_functions; + #endif /* PSYMTAB_H */ 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-cmd.c b/gdb/python/py-cmd.c index 2cff4ba..9255336 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 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-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-prettyprint.c b/gdb/python/py-prettyprint.c index 434c8a5..b22c557 100644 --- a/gdb/python/py-prettyprint.c +++ b/gdb/python/py-prettyprint.c @@ -204,10 +204,10 @@ pretty_print_one_value (PyObject *printer, struct value **out_value) && result != Py_None) { *out_value = convert_value_from_python (result); - if (PyErr_Occurred ()) - *out_value = NULL; - Py_DECREF (result); - result = NULL; + if (PyErr_Occurred ()) + *out_value = NULL; + Py_DECREF (result); + result = NULL; } } } @@ -700,14 +700,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-type.c b/gdb/python/py-type.c index b901255..4ff18e5 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. */ @@ -618,8 +626,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) { @@ -637,12 +696,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; } @@ -653,42 +713,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. */ @@ -699,7 +742,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; } @@ -773,6 +819,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-value.c b/gdb/python/py-value.c index 2024021..e8be12d 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 @@ -1067,6 +1068,17 @@ gdbpy_is_value_object (PyObject *obj) return PyObject_TypeCheck (obj, &value_object_type); } +/* 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)); +} + void gdbpy_initialize_values (void) { @@ -1077,6 +1089,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 2b8d301..0af99c8 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -82,10 +82,11 @@ struct language_defn; struct program_space; extern PyObject *gdb_module; -extern PyTypeObject value_object_type; extern PyTypeObject block_object_type; +extern PyTypeObject value_object_type; extern PyTypeObject symbol_object_type; +/* Used in python-inferior.c. */ typedef struct { PyObject_HEAD @@ -126,6 +127,10 @@ PyObject *block_to_block_object (struct block *block, struct objfile *objfile); PyObject *value_to_value_object (struct value *v); PyObject *type_to_type_object (struct type *); PyObject *frame_info_to_frame_object (struct frame_info *frame); +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 *pspace_to_pspace_object (struct program_space *); PyObject *pspy_get_printers (PyObject *, void *); @@ -145,8 +150,11 @@ struct type *type_object_to_type (PyObject *obj); struct symtab *symtab_object_to_symtab (PyObject *obj); struct symtab_and_line *sal_object_to_symtab_and_line (PyObject *obj); +PyObject *gdbpy_get_hook_function (const char *); void gdbpy_initialize_auto_load (void); + 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); @@ -154,6 +162,7 @@ void gdbpy_initialize_symbols (void); void gdbpy_initialize_symtabs (void); void gdbpy_initialize_blocks (void); void gdbpy_initialize_types (void); +void gdbpy_initialize_blocks (void); void gdbpy_initialize_functions (void); void gdbpy_initialize_pspace (void); void gdbpy_initialize_objfile (void); @@ -171,6 +180,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) \ @@ -221,13 +236,14 @@ int gdbpy_is_value_object (PyObject *obj); 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; extern PyObject *gdbpy_enabled_cst; extern PyObject *gdbpy_gdberror_exc; diff --git a/gdb/python/python.c b/gdb/python/python.c index 7346fba..ee6e476 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 @@ -42,10 +43,17 @@ static int gdbpy_should_print_stack = 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[]; @@ -374,6 +382,105 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) 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) @@ -414,6 +521,114 @@ source_python_script (FILE *stream, const 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 @@ -459,6 +674,53 @@ gdbpy_print_stack (void) /* Return the current Progspace. There always is one. */ +/* 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); +} + + + static PyObject * gdbpy_get_current_progspace (PyObject *unused1, PyObject *unused2) @@ -720,6 +982,7 @@ Enables or disables printing of Python stack traces."), gdbpy_initialize_lazy_string (); gdbpy_initialize_thread (); gdbpy_initialize_inferior (); + gdbpy_initialize_events (); PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers = []"); @@ -787,6 +1050,8 @@ static PyMethodDef GdbMethods[] = "Get a value from history" }, { "execute", (PyCFunction) execute_gdb_command, METH_VARARGS | METH_KEYWORDS, "Execute a gdb command" }, + { "cli", gdbpy_cli, METH_NOARGS, + "Enter the gdb CLI" }, { "parameter", gdbpy_parameter, METH_VARARGS, "Return a gdb parameter's value" }, @@ -825,11 +1090,21 @@ a boolean indicating if name is a field of the current implied argument\n\ `this' (when the current language is object-oriented)." }, { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS, "Return the block containing the given pc value, or None." }, + { "solib_address (Long) -> String.\n\ +Return the name of the shared library holding a given address, 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." }, { "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." }, + { "target_charset", gdbpy_target_charset, METH_NOARGS, "target_charset () -> string.\n\ Return the name of the current target charset." }, diff --git a/gdb/python/python.h b/gdb/python/python.h index affd4a4..5407878 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -28,6 +28,8 @@ void eval_python_from_control_command (struct command_line *); void source_python_script (FILE *stream, const 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/solib-svr4.c b/gdb/solib-svr4.c index 1f135d4..489838d 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1278,7 +1278,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR pc) && pc < info->interp_text_sect_high) || (pc >= info->interp_plt_sect_low && pc < info->interp_plt_sect_high) - || in_plt_section (pc, NULL)); + || in_plt_section (pc, NULL) + || in_gnu_ifunc_stub (pc)); } /* Given an executable's ABFD and target, compute the entry-point diff --git a/gdb/symfile.c b/gdb/symfile.c index 42f7ae3..371db0d 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -1059,6 +1059,9 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, const char *name = bfd_get_filename (abfd); const int from_tty = add_flags & SYMFILE_VERBOSE; + if (readnow_symbol_files) + flags |= OBJF_READNOW; + my_cleanups = make_cleanup_bfd_close (abfd); /* Give user a chance to burp if we'd be @@ -1095,7 +1098,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, the gdb startup command line or on a per symbol file basis. Expand all partial symbol tables for this objfile if so. */ - if ((flags & OBJF_READNOW) || readnow_symbol_files) + if ((flags & OBJF_READNOW)) { if (from_tty || info_verbose) { @@ -1533,7 +1536,7 @@ symbol_file_command (char *args, int from_tty) void set_initial_language (void) { - char *filename; + const char *filename; enum language lang = language_unknown; filename = find_main_filename (); @@ -2660,7 +2663,7 @@ init_filename_language_table (void) } enum language -deduce_language_from_filename (char *filename) +deduce_language_from_filename (const char *filename) { int i; char *cp; diff --git a/gdb/symfile.h b/gdb/symfile.h index d53c465..5815354 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -171,6 +171,15 @@ struct quick_symbol_functions int kind, const char *name, domain_enum domain); + /* This is called to expand symbol tables before looking up a + symbol. A backend can choose to implement this and then have its + `lookup_symbol' hook always return NULL, or the reverse. (It + doesn't make sense to implement both.) The arguments are as for + `lookup_symbol'. */ + void (*pre_expand_symtabs_matching) (struct objfile *objfile, + int kind, const char *name, + domain_enum domain); + /* Print statistics about any indices loaded for OBJFILE. The statistics should be printed to gdb_stdout. This is used for "maint print statistics". */ @@ -201,7 +210,7 @@ struct quick_symbol_functions /* Return the file name of the file holding the symbol in OBJFILE named NAME. If no such symbol exists in OBJFILE, return NULL. */ - char *(*find_symbol_file) (struct objfile *objfile, const char *name); + const char *(*find_symbol_file) (struct objfile *objfile, const char *name); /* This method is specific to Ada. It walks the partial symbol tables of OBJFILE looking for a name match. WILD_MATCH and @@ -566,6 +575,7 @@ extern struct cleanup *increment_reading_symtab (void); extern int dwarf2_has_info (struct objfile *); +extern int dwarf2_initialize_objfile (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 62e6b97..00dc613 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -262,6 +262,9 @@ dump_msymbols (struct objfile *objfile, struct ui_file *outfile) case mst_text: ms_type = 'T'; break; + case mst_text_gnu_ifunc: + ms_type = 'i'; + break; case mst_solib_trampoline: ms_type = 'S'; break; diff --git a/gdb/symtab.c b/gdb/symtab.c index 2c4c9e4..28f0450 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -1295,16 +1295,25 @@ lookup_symbol_aux_symtabs (int block_index, const char *name, const struct block *block; struct symtab *s; - ALL_PRIMARY_SYMTABS (objfile, s) + ALL_OBJFILES (objfile) { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, block_index); - sym = lookup_block_symbol (block, name, domain); - if (sym) - { - block_found = block; - return fixup_symbol_section (sym, objfile); - } + if (objfile->sf) + objfile->sf->qf->pre_expand_symtabs_matching (objfile, + block_index, + name, domain); + + ALL_OBJFILE_SYMTABS (objfile, s) + if (s->primary) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, block_index); + sym = lookup_block_symbol (block, name, domain); + if (sym) + { + block_found = block; + return fixup_symbol_section (sym, objfile); + } + } } return NULL; @@ -1547,15 +1556,24 @@ basic_lookup_transparent_type (const char *name) of the desired name as a global, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - ALL_PRIMARY_SYMTABS (objfile, s) + ALL_OBJFILES (objfile) { - bv = BLOCKVECTOR (s); - block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); - if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) - { - return SYMBOL_TYPE (sym); - } + if (objfile->sf) + objfile->sf->qf->pre_expand_symtabs_matching (objfile, + GLOBAL_BLOCK, + name, STRUCT_DOMAIN); + + ALL_OBJFILE_SYMTABS (objfile, s) + if (s->primary) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + sym = lookup_block_symbol (block, name, STRUCT_DOMAIN); + if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym))) + { + return SYMBOL_TYPE (sym); + } + } } ALL_OBJFILES (objfile) @@ -1599,14 +1617,16 @@ basic_lookup_transparent_type (const char *name) /* FIXME: What about languages without main() or specially linked executables that have no main() ? */ -char * +const char * find_main_filename (void) { struct objfile *objfile; - char *result, *name = main_name (); + char *name = main_name (); ALL_OBJFILES (objfile) { + const char *result; + if (!objfile->sf) continue; result = objfile->sf->qf->find_symbol_file (objfile, name); @@ -2914,7 +2934,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[], static enum minimal_symbol_type types3[] = {mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown}; static enum minimal_symbol_type types4[] - = {mst_file_bss, mst_text, mst_abs, mst_unknown}; + = {mst_file_bss, mst_text_gnu_ifunc, mst_abs, mst_unknown}; enum minimal_symbol_type ourtype; enum minimal_symbol_type ourtype2; enum minimal_symbol_type ourtype3; diff --git a/gdb/symtab.h b/gdb/symtab.h index bedc10a..dc284e4 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -277,6 +277,9 @@ enum minimal_symbol_type { mst_unknown = 0, /* Unknown type, the default */ mst_text, /* Generally executable instructions */ + mst_text_gnu_ifunc, /* Executable code returning address + of executable code */ + mst_slot_got_plt, mst_data, /* Generally initialized data */ mst_bss, /* Generally uninitialized data */ mst_abs, /* Generally absolute (nonrelocatable) */ @@ -917,11 +920,25 @@ extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *); /* lookup function from address, return name, start addr and end addr */ -extern int find_pc_partial_function (CORE_ADDR, char **, CORE_ADDR *, - CORE_ADDR *); +extern enum find_pc_partial_function_type + { + FIND_PC_PARTIAL_FUNCTION_NOT_FOUND = 0, + FIND_PC_PARTIAL_FUNCTION_NORMAL, + FIND_PC_PARTIAL_FUNCTION_GNU_IFUNC + } find_pc_partial_function (CORE_ADDR, char **, CORE_ADDR *, CORE_ADDR *); extern void clear_pc_function_cache (void); +extern int resolve_gnu_ifunc (const char *function_name, + CORE_ADDR *function_addressp); + +extern struct minimal_symbol *resolve_gnu_ifunc_by_cache + (const char *function_name); + +extern void gnu_ifunc_record_cache (struct gdbarch *gdbarch, + const char *function_name, + CORE_ADDR function_address); + /* lookup partial symbol table by address and section */ extern struct symtab *find_pc_sect_symtab_via_partial (CORE_ADDR, @@ -996,6 +1013,8 @@ extern struct minimal_symbol *lookup_minimal_symbol_by_pc_name extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR); +extern int in_gnu_ifunc_stub (CORE_ADDR pc); + extern struct minimal_symbol * lookup_minimal_symbol_and_objfile (const char *, struct objfile **); @@ -1137,7 +1156,7 @@ extern char **make_source_files_completion_list (char *, char *); int matching_obj_sections (struct obj_section *, struct obj_section *); -extern char *find_main_filename (void); +extern const char *find_main_filename (void); extern struct symtab *find_line_symtab (struct symtab *, int, int *, int *); @@ -1150,7 +1169,7 @@ extern void skip_prologue_sal (struct symtab_and_line *); extern void clear_symtab_users (void); -extern enum language deduce_language_from_filename (char *); +extern enum language deduce_language_from_filename (const char *); /* symtab.c */ diff --git a/gdb/target.c b/gdb/target.c index 4cabcbd..34b3b60 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -123,6 +123,8 @@ static int debug_to_insert_watchpoint (CORE_ADDR, int, int, static int debug_to_remove_watchpoint (CORE_ADDR, int, int, struct expression *); +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 *); @@ -606,6 +608,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); @@ -739,6 +742,9 @@ update_current_target (void) de_fault (to_remove_watchpoint, (int (*) (CORE_ADDR, int, int, struct expression *)) return_minus_one); + de_fault (to_detach_watchpoints, + (int (*) (void)) + return_zero); de_fault (to_stopped_by_watchpoint, (int (*) (void)) return_zero); @@ -3440,6 +3446,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) { @@ -3687,6 +3706,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 3c8c017..608a742 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -433,6 +433,7 @@ struct target_ops provided with the corresponding target_* macros. */ int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *); int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *); + int (*to_detach_watchpoints) (void); int (*to_stopped_by_watchpoint) (void); int to_have_steppable_watchpoint; @@ -1316,6 +1317,15 @@ extern char *normal_pid_to_str (ptid_t ptid); #define target_remove_watchpoint(addr, len, type, cond) \ (*current_target.to_remove_watchpoint) (addr, len, type, cond) +/* 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) @@ -1369,6 +1379,18 @@ 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); + /* 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 3a33618..f2e11dd 100644 --- a/gdb/testsuite/gdb.base/arrayidx.exp +++ b/gdb/testsuite/gdb.base/arrayidx.exp @@ -57,4 +57,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/gnu-ifunc-lib.c b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c new file mode 100644 index 0000000..680530a --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c @@ -0,0 +1,33 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009, 2010 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 volatile int gnu_ifunc_initialized; +extern int init_stub (int arg); +extern int final (int arg); + +typedef int (*final_t) (int arg); + +asm (".type gnu_ifunc, @gnu_indirect_function"); + +final_t +gnu_ifunc (void) +{ + if (! gnu_ifunc_initialized) + return init_stub; + else + return final; +} diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.c b/gdb/testsuite/gdb.base/gnu-ifunc.c new file mode 100644 index 0000000..106271f --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc.c @@ -0,0 +1,61 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009, 2010 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 +init_stub (int arg) +{ + return 0; +} + +int +final (int arg) +{ + return arg + 1; +} + +/* Make differentiation of how the gnu_ifunc call resolves before and after + calling gnu_ifunc_pre. This ensures the resolved function address is not + being cached anywhere for the debugging purposes. */ + +volatile int gnu_ifunc_initialized; + +static void +gnu_ifunc_pre (void) +{ + assert (!gnu_ifunc_initialized); + + gnu_ifunc_initialized = 1; +} + +extern int gnu_ifunc (int arg); + +int +main (void) +{ + int i; + + gnu_ifunc_pre (); + + i = gnu_ifunc (1); /* break-at-call */ + assert (i == 2); + + gnu_ifunc (2); /* break-at-nextcall */ + + return 0; /* break-at-exit */ +} diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp new file mode 100644 index 0000000..8ecf558 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp @@ -0,0 +1,110 @@ +# Copyright (C) 2009, 2010 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 {[skip_shlib_tests]} { + return 0 +} + +set testfile "gnu-ifunc" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +set libfile "${testfile}-lib" +set libsrc ${libfile}.c +set lib_so ${objdir}/${subdir}/${libfile}.so + +# We need DWARF for the "final" function as we "step" into the function and GDB +# would step-over the "final" function if there would be no line number debug +# information (DWARF) available. +# +# We must not have DWARF for the "gnu_ifunc" function as DWARF has no way to +# express the gnu-ifunc type and it would be considered as a regular function +# due to DWARF by GDB. In ELF gnu-ifunc is expressed by the STT_GNU_IFUNC type. +# +# Both functions need to be in the same shared library file but +# gdb_compile_shlib has no way to specify source-specific compilation options. +# +# Therefore $libfile contains only the gnu-ifunc function with no DWARF +# referencing all the other parts from the main executable with DWARF. + +set lib_opts {} +set exec_opts [list debug shlib=$lib_so] + +if [get_compiler_info ${binfile}] { + return -1 +} + +if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != "" + || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} { + untested "Could not compile either $libsrc or $srcfile." + return -1 +} + +# Start with a fresh gdb. + +clean_restart $testfile +gdb_load_shlibs ${lib_so} + +if ![runto_main] then { + fail "Can't run to main" + return 1; +} + +# The "if" condition is artifical to test regression of a former patch. +gdb_breakpoint "[gdb_get_line_number "break-at-nextcall"] if i && gnu_ifunc (i) != 42" + +gdb_breakpoint [gdb_get_line_number "break-at-call"] +gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*" + +# Test GDB will automatically indirect the call. + +gdb_test "p gnu_ifunc (3)" " = 4" + +# Test GDB will skip the gnu_ifunc resolver on first call. + +gdb_test "step" "\r\nfinal .*" + +# Test GDB will not break before the final chosen implementation. + +# Also test a former patch regression: +# Continuing. +# Error in testing breakpoint condition: +# Attempt to take address of value not located in memory. +# +# Breakpoint 2, main () at ./gdb.base/gnu-ifunc.c:33 + +gdb_test "continue" "Continuing.\r\n\r\nBreakpoint .* (at|in) .*break-at-nextcall.*" \ + "continue to break-at-nextcall" + +gdb_breakpoint "gnu_ifunc" + +gdb_continue_to_breakpoint "nextcall gnu_ifunc" + +gdb_test "frame" "#0 +(0x\[0-9a-f\]+ in +)?final \\(.*" "nextcall gnu_ifunc skipped" + + +# Check any commands not doing an inferior call still compute with address of +# the gnu-ifunc resolver. + +gdb_test "p gnu_ifunc" " = {} 0x\[0-9a-f\]+ " "p gnu_ifunc executing" +gdb_test "info sym gnu_ifunc" "gnu_ifunc in section .*" "info sym gnu_ifunc executing" + +set test "info addr gnu_ifunc" +gdb_test_multiple $test $test { + -re "Symbol \"gnu_ifunc\" is at (0x\[0-9a-f\]+) in .*$gdb_prompt $" { + pass $test + } +} +gdb_test "info sym $expect_out(1,string)" "gnu_ifunc in section .*" "info sym " 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..24a608f --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.exp @@ -0,0 +1,109 @@ +# 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] + +# s390x with glibc-debuginfo.s390x installed used approx. 16MB. +set mb_reserve 40 +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/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..3dad7ca --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb9593.exp @@ -0,0 +1,182 @@ +# 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 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" \ + ".*function1 ().*" \ + "until with no argument 1" + +set line [gdb_get_line_number "marker for until" $testfile.cc] + +gdb_test "until $line" \ + ".*function1 ().*" \ + "next past catch 6" + +gdb_test "until" \ + ".*catch (...).*" \ + "until with no argument 2" + +set line [gdb_get_line_number "until here" $testfile.cc] + +gdb_test "next" \ + ".*next_cases.until ().*" \ + "next past catch 6" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into until" + +gdb_test "until $line" \ + ".*catch (...).*" \ + "until-over-throw" + +gdb_test "next" \ + ".*next_cases.until ().*" \ + "next past catch 7" + +gdb_test "step" \ + ".*function1 ().*" \ + "step into until, for advance" + +gdb_test "advance $line" \ + ".*catch (...).*" \ + "advance-over-throw" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S new file mode 100644 index 0000000..7fb00ea --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S @@ -0,0 +1,212 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 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 */ + +/* We will `break *main' at the very first instruction. */ +#define main_length 1 + + .section .data +vardata: + /* See DW_OP_lit3 + 1 (0-based). */ + .string "seennotseen" + + .section .debug_info +.Lcu1_begin: + .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */ +.Lcu1_start: + .2byte 2 /* DWARF version number */ + .4byte .Ldebug_abbrev0 /* Offset Into Abbrev. Section */ + .byte 4 /* Pointer Size (in bytes) */ + + /* CU die */ + .uleb128 1 /* Abbrev: DW_TAG_compile_unit */ + .4byte .Lproducer /* DW_AT_producer */ + /* Use C++ to exploit a bug in parsing DW_AT_name "". */ + .byte 4 /* DW_AT_language (C++) - */ + .4byte main /* DW_AT_low_pc */ + .byte main_length /* DW_AT_high_pc */ + +.Larray_type: + .uleb128 2 /* Abbrev: DW_TAG_array_type */ + .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */ + + .uleb128 3 /* Abbrev: DW_TAG_subrange_type */ + .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */ + .byte 0 /* DW_AT_lower_bound */ + .4byte .Llen_var-.Lcu1_begin /* DW_AT_upper_bound */ + .byte 0 /* End of children of die */ + + /* DW_AT_upper_bound is referencing an optimized-out variable. */ +.Larrayb_type: + .uleb128 2 /* Abbrev: DW_TAG_array_type */ + .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */ + + .uleb128 3 /* Abbrev: DW_TAG_subrange_type */ + .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */ + .byte 0 /* DW_AT_lower_bound */ + .4byte .Llenb_var-.Lcu1_begin /* DW_AT_upper_bound */ + .byte 0 /* End of children of die */ + +.Luint_type: + .uleb128 4 /* Abbrev: DW_TAG_base_type */ + .4byte .Luint_str /* DW_AT_name */ + .byte 4 /* DW_AT_byte_size */ + .byte 7 /* DW_AT_encoding */ + +.Lchar_type: + .uleb128 4 /* Abbrev: DW_TAG_base_type */ + .4byte .Lchar_str /* DW_AT_name */ + .byte 1 /* DW_AT_byte_size */ + .byte 6 /* DW_AT_encoding */ + +.Llen_var: + .uleb128 5 /* Abbrev: DW_TAG_variable artificial */ + .byte 1 /* DW_AT_artificial */ + .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */ + .4byte .Llen_loclist-.Lloclist /* DW_AT_location */ + + /* optimized-out variable for b_string. */ +.Llenb_var: + .uleb128 7 /* Abbrev: DW_TAG_variable artificial no DW_AT_location */ + .byte 1 /* DW_AT_artificial */ + .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */ + + .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */ + .string "a_string" /* DW_AT_name */ + .4byte .Larray_type-.Lcu1_begin /* DW_AT_type */ + .byte 2f - 1f /* DW_AT_location */ +1: .byte 3 /* DW_OP_addr */ + .4byte vardata /* */ +2: + + /* DW_AT_upper_bound is referencing an optimized-out variable. */ + .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */ + .string "b_string" /* DW_AT_name */ + .4byte .Larrayb_type-.Lcu1_begin /* DW_AT_type */ + .byte 2f - 1f /* DW_AT_location */ +1: .byte 3 /* DW_OP_addr */ + .4byte vardata /* */ +2: + + .byte 0 /* End of children of CU */ +.Lcu1_end: + + .section .debug_loc +.Lloclist: +.Llen_loclist: + .4byte 0 # Location list begin address + .4byte main_length # Location list end address + .value 2f-1f # Location expression size +1: .byte 0x33 # DW_OP_lit3 + .byte 0x9f # DW_OP_stack_value +2: + .quad 0x0 # Location list terminator begin (*.LLST2) + .quad 0x0 # Location list terminator end (*.LLST2) + + .section .debug_abbrev +.Ldebug_abbrev0: + .uleb128 1 /* Abbrev code */ + .uleb128 0x11 /* DW_TAG_compile_unit */ + .byte 0x1 /* has_children */ + .uleb128 0x25 /* DW_AT_producer */ + .uleb128 0xe /* DW_FORM_strp */ + .uleb128 0x13 /* DW_AT_language */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 2 /* Abbrev code */ + .uleb128 0x1 /* TAG: DW_TAG_array_type */ + .byte 0x1 /* DW_children_yes */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 3 /* Abbrev code */ + .uleb128 0x21 /* DW_TAG_subrange_type */ + .byte 0x0 /* no children */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x22 /* DW_AT_lower_bound */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x2f /* DW_AT_upper_bound */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 4 /* Abbrev code */ + .uleb128 0x24 /* DW_TAG_base_type */ + .byte 0x0 /* no_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0xe /* DW_FORM_strp */ + .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 5 /* Abbrev code */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0x0 /* no_children */ + .uleb128 0x34 /* DW_AT_artificial */ + .uleb128 0x0c /* DW_FORM_flag */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x02 /* DW_AT_location */ + .uleb128 0x06 /* DW_FORM_data4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 6 /* Abbrev code */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0x0 /* no_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2 /* DW_AT_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 7 /* Abbrev code */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0x0 /* no_children */ + .uleb128 0x34 /* DW_AT_artificial */ + .uleb128 0x0c /* DW_FORM_flag */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .byte 0x0 /* Terminator */ + +/* String table */ + .section .debug_str +.Lproducer: + .string "GNU C 3.3.3" +.Lchar_str: + .string "char" +.Luint_str: + .string "unsigned int" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp new file mode 100644 index 0000000..5dbed3f --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp @@ -0,0 +1,51 @@ +# Copyright 2010 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 printing variable with dynamic bounds which reference a different +# (artificial in the GCC case) variable containing loclist as its location. +# This testcase uses value (not address) of the referenced variable: +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43762 + +# 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-bound-loclist +if { [prepare_for_testing ${testfile}.exp ${testfile} [list ${testfile}.S main.c] {}] } { + return -1 +} + +# Verify it behaves at least as an unbound array without inferior. + +gdb_test "p a_string" { = 0x[0-9a-f]+ "seennotseen"} +gdb_test "ptype a_string" {type = char \[\]} + +# Not runto_main as dw2-bound-loclist.S handles only the first byte of main. +if ![runto "*main"] { + return -1 +} + +gdb_test "p a_string" { = "seen"} +gdb_test "ptype a_string" {type = char \[4\]} + +gdb_test "p b_string" { = (0x[0-9a-f]+ )?"seennotseen"} +gdb_test "ptype b_string" {type = char \[\]} 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/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 fc8bccc..e053813 100644 --- a/gdb/testsuite/gdb.gdb/selftest.exp +++ b/gdb/testsuite/gdb.gdb/selftest.exp @@ -92,6 +92,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 ".*pre_stat_chain = make_command_stats_cleanup.*$gdb_prompt $" { set description "next over make_command_stats_cleanup 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..55aa80d --- /dev/null +++ b/gdb/testsuite/gdb.java/jnpe.exp @@ -0,0 +1,74 @@ +# 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 +} + +# 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.pascal/arrays.exp b/gdb/testsuite/gdb.pascal/arrays.exp new file mode 100644 index 0000000..ccc6e1e --- /dev/null +++ b/gdb/testsuite/gdb.pascal/arrays.exp @@ -0,0 +1,104 @@ +# 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 +} + +load_lib "pascal.exp" + +set testfile "arrays" +set srcfile ${testfile}.pas +set binfile ${objdir}/${subdir}/${testfile}$EXEEXT + +# These tests only work with fpc, using the -gw3 compile-option +pascal_init +if { $pascal_compiler_is_fpc != 1 } { + return -1 +} + +# Detect if the fpc version is below 2.3.0 +set fpc_generates_dwarf_for_dynamic_arrays 1 +if { ($fpcversion_major < 2) || ( ($fpcversion_major == 2) && ($fpcversion_minor < 3))} { + set fpc_generates_dwarf_for_dynamic_arrays 0 +} + + +if {[gdb_compile_pascal "-gw3 ${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug ]] != "" } { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +set bp_location1 [gdb_get_line_number "set breakpoint 1 here"] +set bp_location2 [gdb_get_line_number "set breakpoint 2 here"] + + +if { [gdb_breakpoint ${srcfile}:${bp_location1}] } { + pass "setting breakpoint 1" +} +if { [gdb_breakpoint ${srcfile}:${bp_location2}] } { + pass "setting breakpoint 2" +} + +# Verify that "start" lands inside the right procedure. +if { [gdb_start_cmd] < 0 } { + untested start + return -1 +} + +gdb_test "" ".* at .*${srcfile}.*" "start" + +gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint" + +gdb_test "print StatArrInt" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61\\}" "Print static array of integer type" +gdb_test "print StatArrInt_" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61\\}" "Print static array of integer" + +gdb_test "cont" "Breakpoint .*:${bp_location2}.*" "Going to second breakpoint" + +gdb_test "print StatArrChar" ".* = 'abcdefghijkl'" "Print static array of char" +gdb_test "print Stat2dArrInt" ".* = \\{\\{0, 1, 2, 3, 4\\}, \\{1, 2, 3, 4, 5\\}, \\{2, 3, 4, 5, 6\\}, \\{3, 4, 5, 6, 7\\}, \\{4, 5, 6, 7, 8\\}, \\{5, 6, 7, 8, 9\\}, \\{6, 7, 8, 9, 10\\}, \\{7, 8, 9, 10, 11\\}, \\{8, 9, 10, 11, 12\\}, \\{9, 10, 11, 12, 13\\}, \\{10, 11, 12, 13, 14\\}, \\{11, 12, 13, 14, 15\\}\\}" "Print static 2-dimensional array of integer" + +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print DynArrInt" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62\\}" "Print dynamic array of integer type" +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print DynArrInt_" ".* = \\{50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62\\}" "Print dynamic array of integer" + +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print s" ".* = 'test'#0'string'" "Print string containing null-char" + +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print DynArrStr" ".* = \\{'dstr0', 'dstr1', 'dstr2', 'dstr3', 'dstr4', 'dstr5', 'dstr6', 'dstr7', 'dstr8', 'dstr9', 'dstr10', 'dstr11', 'dstr12'\\}" "Print dynamic array of string" + +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print StatArrStr" ".* = \\{'str0', 'str1', 'str2', 'str3', 'str4', 'str5', 'str6', 'str7', 'str8', 'str9', 'str10', 'str11', 'str12'\\}" "Print static array of string" + +if { $fpc_generates_dwarf_for_dynamic_arrays == 0} { + setup_xfail "*-*-*" +} +gdb_test "print DynArrChar" ".* = 'abcdefghijklm'" "Print dynamic array of char" + diff --git a/gdb/testsuite/gdb.pascal/arrays.pas b/gdb/testsuite/gdb.pascal/arrays.pas new file mode 100644 index 0000000..295602d --- /dev/null +++ b/gdb/testsuite/gdb.pascal/arrays.pas @@ -0,0 +1,82 @@ +{ + 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 . +} + +program arrays; + +{$mode objfpc}{$h+} + +uses sysutils; + +type TStatArrInt= array[0..11] of integer; + TDynArrInt= array of integer; + TStatArrStr= array[0..12] of string; + TDynArrStr= array of string; + TDynArrChar = array of char; + TStatArrChar = array [0..11] of char; + + TStat2dArrInt = array[0..11,0..4] of integer; + +var StatArrInt: TStatArrInt; + StatArrInt_: Array[0..11] of integer; + DynArrInt: TDynArrInt; + DynArrInt_: Array of integer; + StatArrStr: TStatArrStr; + DynArrStr: TDynArrStr; + StatArrChar: TStatArrChar; + DynArrChar: TDynArrChar; + + Stat2dArrInt: TStat2dArrInt; + + s: string; + + i,j : integer; + +begin + for i := 0 to 11 do + begin + StatArrInt[i]:= i+50; + StatArrInt_[i]:= i+50; + StatArrChar[i]:= chr(ord('a')+i); + for j := 0 to 4 do + Stat2dArrInt[i,j]:=i+j; + end; + writeln(StatArrInt_[0]); + writeln(StatArrInt[0]); { set breakpoint 1 here } + writeln(StatArrChar[0]); + writeln(Stat2dArrInt[0,0]); + + setlength(DynArrInt,13); + setlength(DynArrInt_,13); + setlength(DynArrStr,13); + setlength(DynArrChar,13); + for i := 0 to 12 do + begin + DynArrInt[i]:= i+50; + DynArrInt_[i]:= i+50; + DynArrChar[i]:= chr(ord('a')+i); + StatArrStr[i]:='str'+inttostr(i); + DynArrStr[i]:='dstr'+inttostr(i); + end; + writeln(DynArrInt_[1]); + writeln(DynArrInt[1]); + writeln(DynArrStr[1]); + writeln(StatArrStr[1]); + writeln(DynArrChar[1]); + + s := 'test'#0'string'; + writeln(s); { set breakpoint 2 here } +end. diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp index 0f250d2..84e5038 100644 --- a/gdb/testsuite/gdb.python/py-cmd.exp +++ b/gdb/testsuite/gdb.python/py-cmd.exp @@ -20,24 +20,6 @@ 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 diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp index e1212d3..77f44f5 100644 --- a/gdb/testsuite/gdb.python/py-frame.exp +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -89,8 +89,6 @@ gdb_py_test_silent_cmd "python f0 = f1.newer ()" "get first 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" @@ -105,3 +103,5 @@ gdb_test "python print 'result =', f0.read_var ('variable_which_surely_doesnt_ex gdb_test "python print 'result =', f0.read_var ('a')" " = 1" "test Frame.read_var - success" 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 38c5693..e7f0037 100644 --- a/gdb/testsuite/gdb.python/py-function.exp +++ b/gdb/testsuite/gdb.python/py-function.exp @@ -20,24 +20,6 @@ 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 diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp index 3b2aadd..03bbf3e 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.exp +++ b/gdb/testsuite/gdb.python/py-prettyprint.exp @@ -102,6 +102,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 "print nstype" " = {$nl *.0. = 7,$nl *.1. = 42$nl}" gdb_test "continue" "Program exited normally\." diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index a24bc11..e3043bc 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -313,6 +313,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. @@ -437,6 +446,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/gdb.exp b/gdb/testsuite/lib/gdb.exp index 20e2fb7..b27d25c 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/pascal.exp b/gdb/testsuite/lib/pascal.exp index 9691bc1..13ea8b5 100644 --- a/gdb/testsuite/lib/pascal.exp +++ b/gdb/testsuite/lib/pascal.exp @@ -37,6 +37,9 @@ proc pascal_init {} { global pascal_compiler_is_fpc global gpc_compiler global fpc_compiler + global fpcversion_major + global fpcversion_minor + global fpcversion_release global env if { $pascal_init_done == 1 } { @@ -64,6 +67,20 @@ proc pascal_init {} { set pascal_compiler_is_fpc 1 verbose -log "Free Pascal compiler found" } + + # Detect the fpc-version + if { $pascal_compiler_is_fpc == 1 } { + set fpcversion_major 1 + set fpcversion_minor 0 + set fpcversion_release 0 + set fpcversion [ remote_exec host $fpc_compiler "-iV" ] + if [regexp {.*([0-9]+)\.([0-9]+)\.([0-9]+).?} $fpcversion] { + regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\1} fpcversion_major + regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\2} fpcversion_minor + regsub {.*([0-9]+)\.([0-9]+)\.([0-9]+).?\n?.?} $fpcversion {\3} fpcversion_release + } + verbose -log "Freepascal version: $fpcversion_major.$fpcversion_minor.$fpcversion_release" + } } set pascal_init_done 1 } 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 0b291ba..ae3e4ff 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -90,6 +90,16 @@ delete_step_resume_breakpoint (struct thread_info *tp) } } +void +delete_exception_resume_breakpoint (struct thread_info *tp) +{ + if (tp && tp->exception_resume_breakpoint) + { + delete_breakpoint (tp->exception_resume_breakpoint); + tp->exception_resume_breakpoint = NULL; + } +} + static void clear_thread_inferior_resources (struct thread_info *tp) { @@ -103,6 +113,12 @@ clear_thread_inferior_resources (struct thread_info *tp) tp->step_resume_breakpoint = NULL; } + if (tp->exception_resume_breakpoint) + { + tp->exception_resume_breakpoint->disposition = disp_del_at_next_stop; + tp->exception_resume_breakpoint = NULL; + } + bpstat_clear (&tp->stop_bpstat); discard_all_intermediate_continuations_thread (tp); diff --git a/gdb/top.c b/gdb/top.c index b29e68d..8edac70 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/valarith.c b/gdb/valarith.c index 0c40905..a781636 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -161,12 +161,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) @@ -185,34 +199,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 || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type) - && 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; } @@ -292,6 +309,10 @@ int binop_user_defined_p (enum exp_opcode op, struct value *arg1, struct value *arg2) { + /* FIXME: We should support user defined ops for dynamic types. */ + if (TYPE_DYNAMIC (value_type (arg1)) || TYPE_DYNAMIC (value_type (arg2))) + return 0; + return binop_types_user_defined_p (op, value_type (arg1), value_type (arg2)); } diff --git a/gdb/valops.c b/gdb/valops.c index 7fbad10..8e32405 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" @@ -858,6 +859,65 @@ 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-NULL check_typedef result on TYPE 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. */ + +struct type * +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 NULL; + } + + 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 type; +} + /* Helper function for value_at, value_at_lazy, and value_at_lazy_stack. */ static struct value * @@ -956,15 +1016,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) @@ -1374,7 +1440,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); } @@ -1481,6 +1558,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 @@ -1490,8 +1568,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 diff --git a/gdb/valprint.c b/gdb/valprint.c index ad6268e..fb0ef7a 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -36,6 +36,7 @@ #include "dfp.h" #include "python/python.h" #include "ada-lang.h" +#include "dwarf2loc.h" #include @@ -237,7 +238,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: @@ -1142,6 +1142,7 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, { unsigned int things_printed = 0; unsigned len; + struct type *saved_type = type; struct type *elttype, *index_type; unsigned eltlen; /* Position of the array element we are examining to see @@ -1150,9 +1151,33 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, /* Number of repetitions we have detected so far. */ unsigned int reps; LONGEST low_bound_index = 0; + struct cleanup *back_to; + CORE_ADDR saved_address = address; + + back_to = make_cleanup (null_cleanup, 0); + type = object_address_get_data (type, &address); + if (!type) + { + fputs_filtered (object_address_data_not_valid (type), stream); + do_cleanups (back_to); + return; + } + if (address != saved_address) + { + size_t length = TYPE_LENGTH (type); - elttype = TYPE_TARGET_TYPE (type); - eltlen = TYPE_LENGTH (check_typedef (elttype)); + valaddr = xmalloc (length); + make_cleanup (xfree, (gdb_byte *) valaddr); + read_memory (address, (gdb_byte *) valaddr, length); + } + + /* Skip typedefs but do not resolve TYPE_DYNAMIC. */ + elttype = saved_type; + while (TYPE_CODE (elttype) == TYPE_CODE_TYPEDEF) + elttype = TYPE_TARGET_TYPE (elttype); + elttype = TYPE_TARGET_TYPE (elttype); + + eltlen = TYPE_ARRAY_BYTE_STRIDE_VALUE (type); index_type = TYPE_INDEX_TYPE (type); /* Compute the number of elements in the array. On most arrays, @@ -1160,9 +1185,6 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, is simply the size of the array divided by the size of the elements. But for arrays of elements whose size is zero, we need to look at the bounds. */ - if (eltlen != 0) - len = TYPE_LENGTH (type) / eltlen; - else { LONGEST low, hi; @@ -1236,6 +1258,8 @@ val_print_array_elements (struct type *type, const gdb_byte *valaddr, { fprintf_filtered (stream, "..."); } + + do_cleanups (back_to); } /* Read LEN bytes of target memory at address MEMADDR, placing the diff --git a/gdb/value.c b/gdb/value.c index d552402..b10269c 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -39,6 +39,7 @@ #include "objfiles.h" #include "valprint.h" #include "cli/cli-decode.h" +#include "observer.h" #include "python/python.h" @@ -828,12 +829,15 @@ void set_value_component_location (struct value *component, const struct value *whole) { + CORE_ADDR addr; + if (whole->lval == lval_internalvar) VALUE_LVAL (component) = lval_internalvar_component; else VALUE_LVAL (component) = whole->lval; component->location = whole->location; + if (whole->lval == lval_computed) { struct lval_funcs *funcs = whole->location.computed.funcs; @@ -841,6 +845,12 @@ set_value_component_location (struct value *component, 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); } @@ -973,6 +983,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. @@ -1451,6 +1484,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 @@ -1498,11 +1565,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); } @@ -1517,13 +1583,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: @@ -2387,7 +2453,24 @@ value_from_decfloat (struct type *type, const gdb_byte *dec) struct value * coerce_ref (struct value *arg) { - struct type *value_type_arg_tmp = check_typedef (value_type (arg)); + struct type *value_type_arg_tmp; + + if (TYPE_DYNAMIC (value_type (arg))) + { + struct cleanup *cleanups = make_cleanup (null_cleanup, NULL); + CORE_ADDR address; + + value_type_arg_tmp = value_type (arg); + address = value_raw_address (arg); + value_type_arg_tmp = object_address_get_data (value_type_arg_tmp, + &address); + if (! value_type_arg_tmp) + error (_("Attempt to coerce non-valid value.")); + arg = value_at_lazy (value_type_arg_tmp, address); + do_cleanups (cleanups); + } + else + value_type_arg_tmp = check_typedef (value_type (arg)); if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF) arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp), @@ -2485,4 +2568,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 12cbc0a..a508bf6 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -372,6 +372,10 @@ 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 struct type *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); @@ -729,7 +733,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 b9b8e91..a81d25c 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"