Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.3
gdb
gdb-archer.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gdb-archer.patch of Package gdb
http://sourceware.org/gdb/wiki/ProjectArcher http://sourceware.org/gdb/wiki/ArcherBranchManagement GIT snapshot: commit 897686c0aedb7a6da59b823f22b1d24ec5a1d2ba branch `archer' - the merge of branches: archer-jankratochvil-vla archer-tromey-python archer-tromey-dwz-multifile-rebase (but from post-7.5 FSF GDB commits) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index a41cff9..d7786a6 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -704,7 +704,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ exceptions.c expprint.c \ f-exp.y f-lang.c f-typeprint.c f-valprint.c filesystem.c \ findcmd.c findvar.c frame.c frame-base.c frame-unwind.c \ - gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \ + gdbarch.c arch-utils.c gdb_bfd.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \ go-exp.y go-lang.c go-typeprint.c go-valprint.c \ inf-loop.c \ infcall.c \ @@ -829,7 +829,7 @@ gnulib/import/extra/snippet/warn-on-use.h \ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \ common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \ common/format.h \ -common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h +common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h gdb_bfd.h # Header files that already have srcdir in them, or which are in objdir. @@ -879,7 +879,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ macrotab.o macrocmd.o macroexp.o macroscope.o \ mi-common.o \ event-loop.o event-top.o inf-loop.o completer.o \ - gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o \ + gdbarch.o arch-utils.o gdbtypes.o gdb_bfd.o osabi.o copying.o \ memattr.o mem-break.o target.o parse.o language.o buildsym.o \ findcmd.o \ std-regs.o \ @@ -1307,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 diff --git a/gdb/NEWS b/gdb/NEWS index b281824..4da886c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -1,6 +1,13 @@ What has changed in GDB? (Organized release by release) +*** Changes since GDB 7.5 + +* New commands (for set/show, see "New options" below) + +maint info bfds + List the BFDs known to GDB. + *** Changes in GDB 7.5 * GDB now supports x32 ABI. Visit <http://sites.google.com/site/x32abi/> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index aa090af..e672731 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -12037,6 +12037,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) { @@ -12051,12 +12052,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/bfd-target.c b/gdb/bfd-target.c index 6728800..455d3e6 100644 --- a/gdb/bfd-target.c +++ b/gdb/bfd-target.c @@ -21,6 +21,7 @@ #include "target.h" #include "bfd-target.h" #include "exec.h" +#include "gdb_bfd.h" /* The object that is stored in the target_ops->to_data field has this type. */ @@ -70,7 +71,7 @@ target_bfd_xclose (struct target_ops *t, int quitting) { struct target_bfd_data *data = t->to_data; - bfd_close (data->bfd); + gdb_bfd_unref (data->bfd); xfree (data->table.sections); xfree (data); xfree (t); @@ -84,6 +85,7 @@ target_bfd_reopen (struct bfd *abfd) data = XZALLOC (struct target_bfd_data); data->bfd = abfd; + gdb_bfd_ref (abfd); build_section_table (abfd, &data->table.sections, &data->table.sections_end); t = XZALLOC (struct target_ops); diff --git a/gdb/bfd-target.h b/gdb/bfd-target.h index 71001c5..7f4e628 100644 --- a/gdb/bfd-target.h +++ b/gdb/bfd-target.h @@ -23,9 +23,9 @@ struct bfd; struct target_ops; -/* Given an existing BFD, re-open it as a "struct target_ops". On - close, it will also close the corresponding BFD (which is like - freopen and fdopen). */ +/* Given an existing BFD, re-open it as a "struct target_ops". This + acquires a new reference to the BFD. This reference will be + released when the target is closed. */ struct target_ops *target_bfd_reopen (struct bfd *bfd); #endif diff --git a/gdb/block.c b/gdb/block.c index a0f82ec..097dbf6 100644 --- a/gdb/block.c +++ b/gdb/block.c @@ -692,3 +692,21 @@ block_iter_match_next (const char *name, return block_iter_match_step (iterator, name, compare, 0); } + +/* 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 99c4788..6ceb704 100644 --- a/gdb/block.h +++ b/gdb/block.h @@ -279,4 +279,6 @@ extern struct symbol *block_iter_match_next (const char *name, (sym); \ (sym) = block_iterator_next (&(iter))) +extern struct objfile *block_objfile (const struct block *block); + #endif /* BLOCK_H */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 78fffd3..224ba49 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -15519,6 +15519,24 @@ all_tracepoints (void) return tp_vec; } +#if 0 +/* 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)); + } +} +#endif + /* This help string is used for the break, hbreak, tbreak and thbreak commands. It is defined as a macro to prevent duplication. @@ -16484,4 +16502,7 @@ agent-printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\ automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); +#if 0 + observer_attach_mark_used (breakpoint_types_mark_used); +#endif } diff --git a/gdb/buildsym.c b/gdb/buildsym.c index d547012..e4882fb 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -966,11 +966,14 @@ reset_symtab_globals (void) file's text. If EXPANDABLE is non-zero the STATIC_BLOCK dictionary is made - expandable. */ + expandable. + + If REQUIRED is non-zero, then a symtab is created even if it does + not contain any symbols. */ struct block * end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, - int expandable) + int expandable, int required) { /* Finish the lexical context of the last function in the file; pop the context stack. */ @@ -1038,7 +1041,8 @@ end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, cleanup_undefined_stabs_types (objfile); finish_global_stabs (objfile); - if (pending_blocks == NULL + if (!required + && pending_blocks == NULL && file_symbols == NULL && global_symbols == NULL && have_line_numbers == 0 @@ -1296,7 +1300,7 @@ end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) { struct block *static_block; - static_block = end_symtab_get_static_block (end_addr, objfile, 0); + static_block = end_symtab_get_static_block (end_addr, objfile, 0, 0); return end_symtab_from_static_block (static_block, objfile, section, 0); } @@ -1308,7 +1312,7 @@ end_expandable_symtab (CORE_ADDR end_addr, struct objfile *objfile, { struct block *static_block; - static_block = end_symtab_get_static_block (end_addr, objfile, 1); + static_block = end_symtab_get_static_block (end_addr, objfile, 1, 0); return end_symtab_from_static_block (static_block, objfile, section, 1); } diff --git a/gdb/buildsym.h b/gdb/buildsym.h index 162ee8c..33b34c8 100644 --- a/gdb/buildsym.h +++ b/gdb/buildsym.h @@ -260,7 +260,8 @@ extern char *pop_subfile (void); extern struct block *end_symtab_get_static_block (CORE_ADDR end_addr, struct objfile *objfile, - int expandable); + int expandable, + int required); extern struct symtab *end_symtab_from_static_block (struct block *static_block, struct objfile *objfile, diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index a5892b5..2944c2d 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -624,9 +624,14 @@ c_type_print_varspec_suffix (struct type *type, fprintf_filtered (stream, ")"); fprintf_filtered (stream, "["); - if (get_array_bounds (type, &low_bound, &high_bound)) - fprintf_filtered (stream, "%d", - (int) (high_bound - low_bound + 1)); + 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 (get_array_bounds (type, &low_bound, &high_bound)) + fprintf_filtered (stream, "%d", (int) (high_bound - low_bound + 1)); fprintf_filtered (stream, "]"); c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, diff --git a/gdb/cc-with-dwz.sh b/gdb/cc-with-dwz.sh deleted file mode 100755 index f66deb1..0000000 --- a/gdb/cc-with-dwz.sh +++ /dev/null @@ -1,80 +0,0 @@ -#! /bin/sh -# Wrapper around gcc to run 'dwz' when running the testsuite. - -# Copyright (C) 2010-2012 Free Software Foundation, Inc. -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -# This program requires dwz in addition to gcc. -# -# Example usage: -# -# bash$ cd $objdir/gdb/testsuite -# bash$ runtest \ -# CC_FOR_TARGET="/bin/sh $srcdir/cc-with-dwz.sh gcc" \ -# CXX_FOR_TARGET="/bin/sh $srcdir/cc-with-dwz.sh g++" -# - -myname=cc-with-dwz.sh - -DWZ=${DWZ:-dwz} - -have_link=unknown -next_is_output_file=no -output_file=a.out - -for arg in "$@" -do - if [ "$next_is_output_file" = "yes" ] - then - output_file="$arg" - next_is_output_file=no - continue - fi - - # Poor man's gcc argument parser. - # We don't need to handle all arguments, we just need to know if we're - # doing a link and what the output file is. - # It's not perfect, but it seems to work well enough for the task at hand. - case "$arg" in - "-c") have_link=no ;; - "-E") have_link=no ;; - "-S") have_link=no ;; - "-o") next_is_output_file=yes ;; - esac -done - -if [ "$next_is_output_file" = "yes" ] -then - echo "$myname: Unable to find output file" >&2 - exit 1 -fi - -if [ "$have_link" = "no" ] -then - "$@" - exit $? -fi - -"$@" -rc=$? -[ $rc != 0 ] && exit $rc -if [ ! -f "$output_file" ] -then - echo "$myname: Internal error: $output_file missing." >&2 - exit 1 -fi - -$DWZ "$output_file" > /dev/null 2>&1 - -exit 0 diff --git a/gdb/cc-with-index.sh b/gdb/cc-with-index.sh deleted file mode 100644 index 644ba34..0000000 --- a/gdb/cc-with-index.sh +++ /dev/null @@ -1,126 +0,0 @@ -#! /bin/sh -# Wrapper around gcc to add the .gdb_index section when running the testsuite. - -# Copyright (C) 2010-2012 Free Software Foundation, Inc. -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -# This program requires gdb and objcopy in addition to gcc. -# The default values are gdb from the build tree and objcopy from $PATH. -# They may be overridden by setting environment variables GDB and OBJCOPY -# respectively. -# We assume the current directory is either $obj/gdb or $obj/gdb/testsuite. -# -# Example usage: -# -# bash$ cd $objdir/gdb/testsuite -# bash$ runtest \ -# CC_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh gcc" \ -# CXX_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh g++" -# -# For documentation on index files: info -f gdb.info -n "Index Files" - -myname=cc-with-index.sh - -if [ -z "$GDB" ] -then - if [ -f ./gdb ] - then - GDB="./gdb" - elif [ -f ../gdb ] - then - GDB="../gdb" - elif [ -f ../../gdb ] - then - GDB="../../gdb" - else - echo "$myname: unable to find usable gdb" >&2 - exit 1 - fi -fi - -OBJCOPY=${OBJCOPY:-objcopy} - -have_link=unknown -next_is_output_file=no -output_file=a.out - -for arg in "$@" -do - if [ "$next_is_output_file" = "yes" ] - then - output_file="$arg" - next_is_output_file=no - continue - fi - - # Poor man's gcc argument parser. - # We don't need to handle all arguments, we just need to know if we're - # doing a link and what the output file is. - # It's not perfect, but it seems to work well enough for the task at hand. - case "$arg" in - "-c") have_link=no ;; - "-E") have_link=no ;; - "-S") have_link=no ;; - "-o") next_is_output_file=yes ;; - esac -done - -if [ "$next_is_output_file" = "yes" ] -then - echo "$myname: Unable to find output file" >&2 - exit 1 -fi - -if [ "$have_link" = "no" ] -then - "$@" - exit $? -fi - -index_file="${output_file}.gdb-index" -if [ -f "$index_file" ] -then - echo "$myname: Index file $index_file exists, won't clobber." >&2 - exit 1 -fi - -output_dir="${output_file%/*}" -[ "$output_dir" = "$output_file" ] && output_dir="." - -"$@" -rc=$? -[ $rc != 0 ] && exit $rc -if [ ! -f "$output_file" ] -then - echo "$myname: Internal error: $output_file missing." >&2 - exit 1 -fi - -$GDB --batch-silent -nx -ex "set auto-load no" -ex "file $output_file" -ex "save gdb-index $output_dir" -rc=$? -[ $rc != 0 ] && exit $rc - -# GDB might not always create an index. Cope. -if [ -f "$index_file" ] -then - $OBJCOPY --add-section .gdb_index="$index_file" \ - --set-section-flags .gdb_index=readonly \ - "$output_file" "$output_file" - rc=$? -else - rc=0 -fi - -rm -f "$index_file" -exit $rc diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c index 4a8b5d1..7341f00 100644 --- a/gdb/cli/cli-dump.c +++ b/gdb/cli/cli-dump.c @@ -32,6 +32,7 @@ #include "readline/readline.h" #include "gdbcore.h" #include "cli/cli-utils.h" +#include "gdb_bfd.h" #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE))) @@ -111,12 +112,12 @@ bfd_openr_with_cleanup (const char *filename, const char *target) { bfd *ibfd; - ibfd = bfd_openr (filename, target); + ibfd = gdb_bfd_openr (filename, target); if (ibfd == NULL) error (_("Failed to open %s: %s."), filename, bfd_errmsg (bfd_get_error ())); - make_cleanup_bfd_close (ibfd); + make_cleanup_bfd_unref (ibfd); if (!bfd_check_format (ibfd, bfd_object)) error (_("'%s' is not a recognized file format."), filename); @@ -131,11 +132,11 @@ bfd_openw_with_cleanup (const char *filename, const char *target, if (*mode == 'w') /* Write: create new file */ { - obfd = bfd_openw (filename, target); + obfd = gdb_bfd_openw (filename, target); if (obfd == NULL) error (_("Failed to open %s: %s."), filename, bfd_errmsg (bfd_get_error ())); - make_cleanup_bfd_close (obfd); + make_cleanup_bfd_unref (obfd); if (!bfd_set_format (obfd, bfd_object)) error (_("bfd_openw_with_cleanup: %s."), bfd_errmsg (bfd_get_error ())); } diff --git a/gdb/coffread.c b/gdb/coffread.c index b0a8b82..0c7e6d9 100644 --- a/gdb/coffread.c +++ b/gdb/coffread.c @@ -653,13 +653,14 @@ coff_symfile_read (struct objfile *objfile, int symfile_flags) char *debugfile; debugfile = find_separate_debug_file_by_debuglink (objfile); + make_cleanup (xfree, debugfile); if (debugfile) { bfd *abfd = symfile_bfd_open (debugfile); + make_cleanup_bfd_unref (abfd); symbol_file_add_separate (abfd, symfile_flags, objfile); - xfree (debugfile); } } diff --git a/gdb/contrib/cc-with-tweaks.sh b/gdb/contrib/cc-with-tweaks.sh new file mode 100755 index 0000000..7d7932c --- /dev/null +++ b/gdb/contrib/cc-with-tweaks.sh @@ -0,0 +1,162 @@ +#! /bin/sh +# Wrapper around gcc to tweak the output in various ways when running +# the testsuite. + +# Copyright (C) 2010-2012 Free Software Foundation, Inc. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This program requires gdb and objcopy in addition to gcc. +# The default values are gdb from the build tree and objcopy from $PATH. +# They may be overridden by setting environment variables GDB and OBJCOPY +# respectively. +# We assume the current directory is either $obj/gdb or $obj/gdb/testsuite. +# +# Example usage: +# +# bash$ cd $objdir/gdb/testsuite +# bash$ runtest \ +# CC_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS gcc" \ +# CXX_FOR_TARGET="/bin/sh $srcdir/gdb/contrib/cc-with-tweaks.sh ARGS g++" +# +# For documentation on index files: info -f gdb.info -n "Index Files" +# For information about 'dwz', see the announcement: +# http://gcc.gnu.org/ml/gcc/2012-04/msg00686.html +# (More documentation is to come.) + +# ARGS determine what is done. They can be: +# -z compress using dwz +# -m compress using dwz -m +# -i make an index +# If nothing is given, no changes are made + +myname=cc-with-tweaks.sh + +if [ -z "$GDB" ] +then + if [ -f ./gdb ] + then + GDB="./gdb" + elif [ -f ../gdb ] + then + GDB="../gdb" + elif [ -f ../../gdb ] + then + GDB="../../gdb" + else + echo "$myname: unable to find usable gdb" >&2 + exit 1 + fi +fi + +OBJCOPY=${OBJCOPY:-objcopy} + +DWZ=${DWZ:-dwz} + +have_link=unknown +next_is_output_file=no +output_file=a.out + +want_index=false +want_dwz=false +want_multi=false + +while [ $# -gt 0 ]; do + case "$1" in + -z) want_dwz=true ;; + -i) want_index=true ;; + -m) want_multi=true ;; + *) break ;; + esac + shift +done + +for arg in "$@" +do + if [ "$next_is_output_file" = "yes" ] + then + output_file="$arg" + next_is_output_file=no + continue + fi + + # Poor man's gcc argument parser. + # We don't need to handle all arguments, we just need to know if we're + # doing a link and what the output file is. + # It's not perfect, but it seems to work well enough for the task at hand. + case "$arg" in + "-c") have_link=no ;; + "-E") have_link=no ;; + "-S") have_link=no ;; + "-o") next_is_output_file=yes ;; + esac +done + +if [ "$next_is_output_file" = "yes" ] +then + echo "$myname: Unable to find output file" >&2 + exit 1 +fi + +if [ "$have_link" = "no" ] +then + "$@" + exit $? +fi + +index_file="${output_file}.gdb-index" +if [ "$want_index" = true ] && [ -f "$index_file" ] +then + echo "$myname: Index file $index_file exists, won't clobber." >&2 + exit 1 +fi + +output_dir="${output_file%/*}" +[ "$output_dir" = "$output_file" ] && output_dir="." + +"$@" +rc=$? +[ $rc != 0 ] && exit $rc +if [ ! -f "$output_file" ] +then + echo "$myname: Internal error: $output_file missing." >&2 + exit 1 +fi + +if [ "$want_index" = true ]; then + $GDB --batch-silent -nx -ex "set auto-load no" -ex "file $output_file" -ex "save gdb-index $output_dir" + rc=$? + [ $rc != 0 ] && exit $rc + + # GDB might not always create an index. Cope. + if [ -f "$index_file" ] + then + $OBJCOPY --add-section .gdb_index="$index_file" \ + --set-section-flags .gdb_index=readonly \ + "$output_file" "$output_file" + rc=$? + else + rc=0 + fi + [ $rc != 0 ] && exit $rc +fi + +if [ "$want_dwz" = true ]; then + $DWZ "$output_file" > /dev/null 2>&1 +elif [ "$want_multi" = true ]; then + cp $output_file ${output_file}.alt + $DWZ -m ${output_file}.dwz "$output_file" ${output_file}.alt > /dev/null 2>&1 +fi + +rm -f "$index_file" +exit $rc diff --git a/gdb/corelow.c b/gdb/corelow.c index dd62560..340b149 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -46,6 +46,7 @@ #include "filenames.h" #include "progspace.h" #include "objfiles.h" +#include "gdb_bfd.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -215,9 +216,7 @@ core_close (int quitting) core_data = NULL; } - name = bfd_get_filename (core_bfd); - gdb_bfd_close_or_warn (core_bfd); - xfree (name); + gdb_bfd_unref (core_bfd); core_bfd = NULL; } core_vec = NULL; @@ -319,9 +318,9 @@ core_open (char *filename, int from_tty) if (scratch_chan < 0) perror_with_name (filename); - temp_bfd = bfd_fopen (filename, gnutarget, - write_files ? FOPEN_RUB : FOPEN_RB, - scratch_chan); + temp_bfd = gdb_bfd_fopen (filename, gnutarget, + write_files ? FOPEN_RUB : FOPEN_RB, + scratch_chan); if (temp_bfd == NULL) perror_with_name (filename); @@ -332,7 +331,7 @@ core_open (char *filename, int from_tty) /* FIXME: should be checking for errors from bfd_close (for one thing, on error it does not free all the storage associated with the bfd). */ - make_cleanup_bfd_close (temp_bfd); + make_cleanup_bfd_unref (temp_bfd); error (_("\"%s\" is not a core dump: %s"), filename, bfd_errmsg (bfd_get_error ())); } @@ -340,7 +339,7 @@ core_open (char *filename, int from_tty) /* Looks semi-reasonable. Toss the old core file and work on the new. */ - discard_cleanups (old_chain); /* Don't free filename any more */ + do_cleanups (old_chain); unpush_target (&core_ops); core_bfd = temp_bfd; old_chain = make_cleanup (core_close_cleanup, 0 /*ignore*/); diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index 87c6dd4..1c26652 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -52,14 +52,25 @@ SYSCALLS_FILES = \ PYTHON_DIR = python PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR) PYTHON_FILES = \ + gdb/FrameIterator.py \ + gdb/FrameWrapper.py \ gdb/__init__.py \ - gdb/types.py \ - gdb/printing.py \ - gdb/prompt.py \ + gdb/backtrace.py \ gdb/command/__init__.py \ + gdb/command/backtrace.py \ + gdb/command/ignore_errors.py \ + gdb/command/pahole.py \ gdb/command/pretty_printers.py \ gdb/command/prompt.py \ - gdb/command/explore.py + gdb/command/explore.py \ + gdb/command/require.py \ + gdb/command/upto.py \ + gdb/function/__init__.py \ + gdb/function/caller_is.py \ + gdb/function/in_scope.py \ + gdb/printing.py \ + gdb/prompt.py \ + gdb/types.py FLAGS_TO_PASS = \ "prefix=$(prefix)" \ diff --git a/gdb/defs.h b/gdb/defs.h index 1c6fa79..ec08348 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -315,7 +315,7 @@ extern struct cleanup *make_cleanup_close (int fd); extern struct cleanup *make_cleanup_fclose (FILE *file); -extern struct cleanup *make_cleanup_bfd_close (bfd *abfd); +extern struct cleanup *make_cleanup_bfd_unref (bfd *abfd); struct obstack; extern struct cleanup *make_cleanup_obstack_free (struct obstack *obstack); @@ -353,6 +353,8 @@ extern struct cleanup *make_cleanup_restore_page_info (void); extern struct cleanup * set_batch_flag_and_make_cleanup_restore_page_info (void); +extern struct cleanup *make_cleanup_restore_selected_frame (void); + extern char *gdb_realpath (const char *); extern char *xfullpath (const char *); diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 68ea817..5945bac 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -1200,6 +1200,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} @@ -22563,8 +22573,6 @@ containing @code{end}. For example: @smallexample (@value{GDBP}) python -Type python script -End with a line saying just "end". >print 23 >end 23 @@ -22578,6 +22586,14 @@ controlled using @code{set python print-stack}: if @code{full}, then full Python stack printing is enabled; if @code{none}, then Python stack and message printing is disabled; if @code{message}, the default, only the message component of the error is printed. + +@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} @@ -22599,6 +22615,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 @@ -34536,6 +34560,11 @@ Shared library events. @end table +@kindex maint info bfds +@item maint info bfds +This prints information about each @code{bfd} object that is known to +@value{GDBN}. @xref{Top, , BFD, bfd, The Binary File Descriptor Library}. + @kindex set displaced-stepping @kindex show displaced-stepping @cindex displaced stepping support diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index 5e00f1f..c5c432b 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 6827ed8..c63b901 100644 --- a/gdb/doc/observer.texi +++ b/gdb/doc/observer.texi @@ -230,6 +230,11 @@ the current top-level prompt. Variable gdb_datadir has been set. The value may not necessarily change. @end deftypefun +@c @deftypefun void mark_used (void) +@c Mark any possibly reclaimable objects as used during a mark-and-sweep garbage +@c collector pass. Currently only @code{type_mark_used} marker is supported. +@c @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/dsrec.c b/gdb/dsrec.c index d2c99b2..f39d0ed 100644 --- a/gdb/dsrec.c +++ b/gdb/dsrec.c @@ -23,6 +23,7 @@ #include <time.h> #include "gdb_assert.h" #include "gdb_string.h" +#include "gdb_bfd.h" extern void report_transfer_performance (unsigned long, time_t, time_t); @@ -56,19 +57,22 @@ load_srec (struct serial *desc, const char *file, bfd_vma load_offset, int reclen; time_t start_time, end_time; unsigned long data_count = 0; + struct cleanup *cleanup; srec = (char *) alloca (maxrecsize + 1); - abfd = bfd_openr (file, 0); + abfd = gdb_bfd_openr (file, 0); if (!abfd) { printf_filtered (_("Unable to open file %s\n"), file); return; } + cleanup = make_cleanup_bfd_unref (abfd); if (bfd_check_format (abfd, bfd_object) == 0) { printf_filtered (_("File is not an object file\n")); + do_cleanups (cleanup); return; } @@ -170,6 +174,7 @@ load_srec (struct serial *desc, const char *file, bfd_vma load_offset, serial_flush_input (desc); report_transfer_performance (data_count, start_time, end_time); + do_cleanups (cleanup); } /* diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 214b371..d9b3751 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -1480,6 +1480,14 @@ execute_stack_op (struct dwarf_expr_context *ctx, } break; + case DW_OP_push_object_address: + if (ctx->funcs->get_object_address == NULL) + error (_("DWARF-2 expression error: DW_OP_push_object_address must " + "have a value to push.")); + result = (ctx->funcs->get_object_address) (ctx->baton); + result_val = value_from_ulongest (address_type, result); + break; + default: error (_("Unhandled dwarf expression opcode 0x%x"), op); } diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 19efbfd..0e0e498 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -78,12 +78,8 @@ struct dwarf_expr_context_funcs This can throw an exception if the index is out of range. */ CORE_ADDR (*get_addr_index) (void *baton, unsigned int index); -#if 0 - /* Not yet implemented. */ - /* Return the `object address' for DW_OP_push_object_address. */ CORE_ADDR (*get_object_address) (void *baton); -#endif }; /* The location of a value. */ diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 38e4814..46a033d 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -293,6 +293,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. */ @@ -352,16 +355,14 @@ static void dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, const gdb_byte **start, size_t *length) { - if (SYMBOL_LOCATION_BATON (framefunc) == NULL) - *length = 0; - else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs) + if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs) { struct dwarf2_loclist_baton *symbaton; symbaton = SYMBOL_LOCATION_BATON (framefunc); *start = dwarf2_find_location_expression (symbaton, length, pc); } - else + else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_locexpr_funcs) { struct dwarf2_locexpr_baton *symbaton; @@ -374,10 +375,23 @@ dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, else *length = 0; } + else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_missing_funcs) + { + struct dwarf2_locexpr_baton *symbaton; + + symbaton = SYMBOL_LOCATION_BATON (framefunc); + gdb_assert (symbaton == NULL); + *length = 0; + } + else + internal_error (__FILE__, __LINE__, + _("Unsupported SYMBOL_COMPUTED_OPS %p for \"%s\""), + SYMBOL_COMPUTED_OPS (framefunc), + SYMBOL_PRINT_NAME (framefunc)); if (*length == 0) 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 @@ -445,6 +459,85 @@ dwarf_expr_dwarf_call (struct dwarf_expr_context *ctx, cu_offset die_offset) ctx->funcs->get_frame_pc, ctx->baton); } +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 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 = dwarf2_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; +} + /* Callback function for dwarf2_evaluate_loc_desc. */ static struct type * @@ -1139,10 +1232,12 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, saved_ctx.gdbarch = ctx->gdbarch; saved_ctx.addr_size = ctx->addr_size; + saved_ctx.ref_addr_size = ctx->ref_addr_size; saved_ctx.offset = ctx->offset; saved_ctx.baton = ctx->baton; ctx->gdbarch = get_objfile_arch (dwarf2_per_cu_objfile (baton_local.per_cu)); ctx->addr_size = dwarf2_per_cu_addr_size (baton_local.per_cu); + ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (baton_local.per_cu); ctx->offset = dwarf2_per_cu_text_offset (baton_local.per_cu); ctx->baton = &baton_local; @@ -1150,10 +1245,95 @@ dwarf_expr_push_dwarf_reg_entry_value (struct dwarf_expr_context *ctx, ctx->gdbarch = saved_ctx.gdbarch; ctx->addr_size = saved_ctx.addr_size; + ctx->ref_addr_size = saved_ctx.ref_addr_size; ctx->offset = saved_ctx.offset; ctx->baton = saved_ctx.baton; } +static CORE_ADDR dwarf_expr_get_addr_index (void *baton, unsigned int index); + +/* Virtual method table for dwarf2_evaluate_loc_desc_full below. */ + +static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs = +{ + dwarf_expr_read_reg, + dwarf_expr_read_mem, + dwarf_expr_frame_base, + dwarf_expr_frame_cfa, + dwarf_expr_frame_pc, + dwarf_expr_tls_address, + dwarf_expr_dwarf_call, + dwarf_expr_get_base_type, + dwarf_expr_push_dwarf_reg_entry_value, + dwarf_expr_get_addr_index, + dwarf_expr_object_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 void +dwarf_expr_prep_ctx (struct dwarf_expr_context *ctx, struct frame_info *frame, + const gdb_byte *data, size_t size, + struct dwarf2_per_cu_data *per_cu) +{ + struct dwarf_expr_baton baton; + struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); + volatile struct gdb_exception ex; + + baton.frame = frame; + baton.per_cu = per_cu; + baton.object_address = object_address; + + ctx->gdbarch = get_objfile_arch (objfile); + ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (per_cu); + ctx->offset = dwarf2_per_cu_text_offset (per_cu); + ctx->baton = &baton; + ctx->funcs = &dwarf_expr_ctx_funcs; + + dwarf_expr_eval (ctx, data, size); +} + +/* 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; + + ctx = new_dwarf_expr_context (); + back_to = make_cleanup_free_dwarf_expr_context (ctx); + + dwarf_expr_prep_ctx (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_address (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; +} + /* Callback function for dwarf2_evaluate_loc_desc. Fetch the address indexed by DW_OP_GNU_addr_index. */ @@ -2088,22 +2268,6 @@ invalid_synthetic_pointer (void) "referenced via synthetic pointer")); } -/* Virtual method table for dwarf2_evaluate_loc_desc_full below. */ - -static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs = -{ - dwarf_expr_read_reg, - dwarf_expr_read_mem, - dwarf_expr_frame_base, - dwarf_expr_frame_cfa, - dwarf_expr_frame_pc, - dwarf_expr_tls_address, - dwarf_expr_dwarf_call, - dwarf_expr_get_base_type, - dwarf_expr_push_dwarf_reg_entry_value, - dwarf_expr_get_addr_index -}; - /* Evaluate a location description, starting at DATA and with length SIZE, to find the current location of variable of TYPE in the context of FRAME. BYTE_OFFSET is applied after the contents are @@ -2116,7 +2280,6 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, LONGEST byte_offset) { struct value *retval; - struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; struct cleanup *old_chain, *value_chain; struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); @@ -2128,29 +2291,18 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, if (size == 0) return allocate_optimized_out_value (type); - baton.frame = frame; - baton.per_cu = per_cu; - ctx = new_dwarf_expr_context (); old_chain = make_cleanup_free_dwarf_expr_context (ctx); value_chain = make_cleanup_value_free_to_mark (value_mark ()); - ctx->gdbarch = get_objfile_arch (objfile); - ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); - ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (per_cu); - ctx->offset = dwarf2_per_cu_text_offset (per_cu); - ctx->baton = &baton; - ctx->funcs = &dwarf_expr_ctx_funcs; - TRY_CATCH (ex, RETURN_MASK_ERROR) { - dwarf_expr_eval (ctx, data, size); + dwarf_expr_prep_ctx (ctx, frame, data, size, per_cu); } if (ex.reason < 0) { if (ex.error == NOT_AVAILABLE_ERROR) { - do_cleanups (old_chain); retval = allocate_value (type); mark_value_bytes_unavailable (retval, 0, TYPE_LENGTH (type)); return retval; @@ -2214,6 +2366,16 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, int in_stack_memory = dwarf_expr_fetch_in_stack_memory (ctx, 0); do_cleanups (value_chain); + + /* Frame may be needed for check_typedef of TYPE_DYNAMIC. */ + make_cleanup_restore_selected_frame (); + select_frame (frame); + + /* 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_lazy (type); VALUE_LVAL (retval) = lval_memory; if (in_stack_memory) @@ -4130,8 +4292,7 @@ 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_variable_at_entry, @@ -4140,6 +4301,48 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = { 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_variable, /* read_variable_at_entry */ + missing_read_needs_frame, + missing_describe_location, + missing_tracepoint_var_ref +}; + /* Provide a prototype to silence -Wmissing-prototypes. */ extern initialize_file_ftype _initialize_dwarf2loc; diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h index e9d06a3..bfa6776 100644 --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -127,6 +127,15 @@ 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); /* Compile a DWARF location expression to an agent expression. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index deee5a2..b2f052b 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -64,20 +64,12 @@ #include "gdbcore.h" /* for gnutarget */ #include "gdb/gdb-index.h" #include <ctype.h> +#include "gdb_bfd.h" #include <fcntl.h> #include "gdb_string.h" #include "gdb_assert.h" #include <sys/types.h> -#ifdef HAVE_ZLIB_H -#include <zlib.h> -#endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#ifndef MAP_FAILED -#define MAP_FAILED ((void *) -1) -#endif -#endif typedef struct symbol *symbolp; DEF_VEC_P (symbolp); @@ -95,8 +87,6 @@ static int check_physname = 0; /* When non-zero, do not reject deprecated .gdb_index sections. */ static int use_deprecated_index_sections = 0; -static int pagesize; - /* When set, the file that we're processing is known to have debugging info for C++ namespaces. GCC 3.3.x did not produce this information, but later versions do. */ @@ -110,10 +100,6 @@ struct dwarf2_section_info asection *asection; gdb_byte *buffer; bfd_size_type size; - /* Not NULL if the section was actually mmapped. */ - void *map_addr; - /* Page aligned size of mmapped area. */ - bfd_size_type map_len; /* True if we have tried to read this section. */ int readin; }; @@ -247,6 +233,10 @@ struct dwarf2_per_objfile This is NULL if the table hasn't been allocated yet. */ htab_t dwo_files; + /* The shared '.dwz' file, if one exists. This is used when the + original data was compressed using 'dwz -m'. */ + struct dwz_file *dwz_file; + /* A flag indicating wether this objfile has a section loaded at a VMA of 0. */ int has_section_at_zero; @@ -505,15 +495,13 @@ struct dwarf2_cu struct dwarf2_per_cu_data { - /* The start offset and length of this compilation unit. 2**29-1 - bytes should suffice to store the length of any compilation unit - - if it doesn't, GDB will fall over anyway. + /* The start offset and length of this compilation unit. NOTE: Unlike comp_unit_head.length, this length includes initial_length_size. If the DIE refers to a DWO file, this is always of the original die, not the DWO file. */ sect_offset offset; - unsigned int length : 29; + unsigned int length; /* Flag indicating this compilation unit will be read in before any of the current compilation units are processed. */ @@ -528,6 +516,9 @@ struct dwarf2_per_cu_data /* Non-zero if this CU is from .debug_types. */ unsigned int is_debug_types : 1; + /* Non-zero if this CU is from the .dwz file. */ + unsigned int is_dwz : 1; + /* The section this CU/TU lives in. If the DIE refers to a DWO file, this is always the original die, not the DWO file. */ @@ -715,6 +706,22 @@ struct dwo_file htab_t tus; }; +/* This represents a '.dwz' file. */ + +struct dwz_file +{ + /* A dwz file can only contain a few sections. */ + struct dwarf2_section_info abbrev; + struct dwarf2_section_info info; + struct dwarf2_section_info str; + struct dwarf2_section_info line; + struct dwarf2_section_info macro; + struct dwarf2_section_info gdb_index; + + /* The dwz's BFD. */ + bfd *dwz_bfd; +}; + /* Struct used to pass misc. parameters to read_die_and_children, et al. which are used for both .debug_info and .debug_types dies. All parameters here are unchanging for the life of the call. This @@ -828,6 +835,12 @@ struct partial_die_info /* Flag set if fixup_partial_die has been called on this die. */ unsigned int fixup_called : 1; + /* Flag set if DW_TAG_imported_unit uses DW_FORM_GNU_ref_alt. */ + unsigned int is_dwz : 1; + + /* Flag set if spec_offset uses DW_FORM_GNU_ref_alt. */ + unsigned int spec_is_dwz : 1; + /* The name of this DIE. Normally the value of DW_AT_name, but sometimes a default name for unnamed DIEs. */ char *name; @@ -1213,7 +1226,7 @@ static gdb_byte *read_partial_die (const struct die_reader_specs *, unsigned int, gdb_byte *); -static struct partial_die_info *find_partial_die (sect_offset, +static struct partial_die_info *find_partial_die (sect_offset, int, struct dwarf2_cu *); static void fixup_partial_die (struct partial_die_info *, @@ -1258,6 +1271,8 @@ static char *read_indirect_string (bfd *, gdb_byte *, const struct comp_unit_head *, unsigned int *); +static char *read_indirect_string_from_dwz (struct dwz_file *, LONGEST); + static ULONGEST read_unsigned_leb128 (bfd *, gdb_byte *, unsigned int *); static LONGEST read_signed_leb128 (bfd *, gdb_byte *, unsigned int *); @@ -1509,6 +1524,9 @@ static void fill_in_loclist_baton (struct dwarf2_cu *cu, struct dwarf2_loclist_baton *baton, struct attribute *attr); +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); @@ -1524,7 +1542,7 @@ static hashval_t partial_die_hash (const void *item); static int partial_die_eq (const void *item_lhs, const void *item_rhs); static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit - (sect_offset offset, struct objfile *objfile); + (sect_offset offset, unsigned int offset_in_dwz, struct objfile *objfile); static void init_one_comp_unit (struct dwarf2_cu *cu, struct dwarf2_per_cu_data *per_cu); @@ -1541,6 +1559,9 @@ static void age_cached_comp_units (void); static void free_one_cached_comp_unit (struct dwarf2_per_cu_data *); +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 *); @@ -1569,6 +1590,9 @@ static struct type *get_die_type_at_offset (sect_offset, 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, @@ -1587,6 +1611,12 @@ static void find_file_and_directory (struct die_info *die, static char *file_full_name (int file, struct line_header *lh, const char *comp_dir); +static gdb_byte *read_and_check_comp_unit_head + (struct comp_unit_head *header, + struct dwarf2_section_info *section, + struct dwarf2_section_info *abbrev_section, gdb_byte *info_ptr, + int is_debug_types_section); + static void init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table, int use_existing_cu, int keep, @@ -1608,8 +1638,6 @@ static struct dwo_unit *lookup_dwo_type_unit static void free_dwo_file_cleanup (void *); -static void munmap_section_buffer (struct dwarf2_section_info *); - static void process_cu_includes (void); #if WORDS_BIGENDIAN @@ -1779,85 +1807,6 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) dwarf2_per_objfile->has_section_at_zero = 1; } -/* Decompress a section that was compressed using zlib. Store the - decompressed buffer, and its size, in OUTBUF and OUTSIZE. */ - -static void -zlib_decompress_section (struct objfile *objfile, asection *sectp, - gdb_byte **outbuf, bfd_size_type *outsize) -{ - bfd *abfd = sectp->owner; -#ifndef HAVE_ZLIB_H - error (_("Support for zlib-compressed DWARF data (from '%s') " - "is disabled in this copy of GDB"), - bfd_get_filename (abfd)); -#else - bfd_size_type compressed_size = bfd_get_section_size (sectp); - gdb_byte *compressed_buffer = xmalloc (compressed_size); - struct cleanup *cleanup = make_cleanup (xfree, compressed_buffer); - bfd_size_type uncompressed_size; - gdb_byte *uncompressed_buffer; - z_stream strm; - int rc; - int header_size = 12; - - if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 - || bfd_bread (compressed_buffer, - compressed_size, abfd) != compressed_size) - error (_("Dwarf Error: Can't read DWARF data from '%s'"), - bfd_get_filename (abfd)); - - /* Read the zlib header. In this case, it should be "ZLIB" followed - by the uncompressed section size, 8 bytes in big-endian order. */ - if (compressed_size < header_size - || strncmp (compressed_buffer, "ZLIB", 4) != 0) - error (_("Dwarf Error: Corrupt DWARF ZLIB header from '%s'"), - bfd_get_filename (abfd)); - uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; - uncompressed_size += compressed_buffer[11]; - - /* It is possible the section consists of several compressed - buffers concatenated together, so we uncompress in a loop. */ - strm.zalloc = NULL; - strm.zfree = NULL; - strm.opaque = NULL; - strm.avail_in = compressed_size - header_size; - strm.next_in = (Bytef*) compressed_buffer + header_size; - strm.avail_out = uncompressed_size; - uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack, - uncompressed_size); - rc = inflateInit (&strm); - while (strm.avail_in > 0) - { - if (rc != Z_OK) - error (_("Dwarf Error: setting up DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - strm.next_out = ((Bytef*) uncompressed_buffer - + (uncompressed_size - strm.avail_out)); - rc = inflate (&strm, Z_FINISH); - if (rc != Z_STREAM_END) - error (_("Dwarf Error: zlib error uncompressing from '%s': %d"), - bfd_get_filename (abfd), rc); - rc = inflateReset (&strm); - } - rc = inflateEnd (&strm); - if (rc != Z_OK - || strm.avail_out != 0) - error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"), - bfd_get_filename (abfd), rc); - - do_cleanups (cleanup); - *outbuf = uncompressed_buffer; - *outsize = uncompressed_size; -#endif -} - /* A helper function that decides whether a section is empty, or not present. */ @@ -1884,56 +1833,27 @@ dwarf2_read_section (struct objfile *objfile, struct dwarf2_section_info *info) if (info->readin) return; info->buffer = NULL; - info->map_addr = NULL; info->readin = 1; if (dwarf2_section_empty_p (info)) return; - /* Note that ABFD may not be from OBJFILE, e.g. a DWO section. */ abfd = sectp->owner; - /* Check if the file has a 4-byte header indicating compression. */ - if (info->size > sizeof (header) - && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0 - && bfd_bread (header, sizeof (header), abfd) == sizeof (header)) - { - /* Upon decompression, update the buffer and its size. */ - if (strncmp (header, "ZLIB", sizeof (header)) == 0) - { - zlib_decompress_section (objfile, sectp, &info->buffer, - &info->size); - return; - } - } - -#ifdef HAVE_MMAP - 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. */ - - if (info->size > 4 * pagesize && (sectp->flags & SEC_RELOC) == 0) + /* If the section has relocations, we must read it ourselves. + Otherwise we attach it to the BFD. */ + if ((sectp->flags & SEC_RELOC) == 0) { - info->buffer = bfd_mmap (abfd, 0, info->size, PROT_READ, - MAP_PRIVATE, sectp->filepos, - &info->map_addr, &info->map_len); + const gdb_byte *bytes = gdb_bfd_map_section (sectp, &info->size); - if ((caddr_t)info->buffer != MAP_FAILED) - { -#if HAVE_POSIX_MADVISE - posix_madvise (info->map_addr, info->map_len, POSIX_MADV_WILLNEED); -#endif - return; - } + /* We have to cast away const here for historical reasons. + Fixing dwarf2read to be const-correct would be quite nice. */ + info->buffer = (gdb_byte *) bytes; + return; } -#endif - /* If we get here, we are a normal, not-compressed section. */ - info->buffer = buf - = obstack_alloc (&objfile->objfile_obstack, info->size); + buf = obstack_alloc (&objfile->objfile_obstack, info->size); + info->buffer = buf; /* When debugging .o files, we may need to apply relocations; see http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html . @@ -2009,6 +1929,111 @@ dwarf2_get_section_info (struct objfile *objfile, *sizep = info->size; } +/* A helper function to find the sections for a .dwz file. */ + +static void +locate_dwz_sections (bfd *abfd, asection *sectp, void *arg) +{ + struct dwz_file *dwz_file = arg; + + /* Note that we only support the standard ELF names, because .dwz + is ELF-only (at the time of writing). */ + if (section_is_p (sectp->name, &dwarf2_elf_names.abbrev)) + { + dwz_file->abbrev.asection = sectp; + dwz_file->abbrev.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.info)) + { + dwz_file->info.asection = sectp; + dwz_file->info.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.str)) + { + dwz_file->str.asection = sectp; + dwz_file->str.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.line)) + { + dwz_file->line.asection = sectp; + dwz_file->line.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.macro)) + { + dwz_file->macro.asection = sectp; + dwz_file->macro.size = bfd_get_section_size (sectp); + } + else if (section_is_p (sectp->name, &dwarf2_elf_names.gdb_index)) + { + dwz_file->gdb_index.asection = sectp; + dwz_file->gdb_index.size = bfd_get_section_size (sectp); + } +} + +/* Open the separate '.dwz' debug file, if needed. Error if the file + cannot be found. */ + +static struct dwz_file * +dwarf2_get_dwz_file (void) +{ + bfd *abfd, *dwz_bfd; + asection *section; + gdb_byte *data; + struct cleanup *cleanup; + const char *filename; + struct dwz_file *result; + + if (dwarf2_per_objfile->dwz_file != NULL) + return dwarf2_per_objfile->dwz_file; + + abfd = dwarf2_per_objfile->objfile->obfd; + section = bfd_get_section_by_name (abfd, ".gnu_debugaltlink"); + if (section == NULL) + error (_("could not find '.gnu_debugaltlink' section")); + if (!bfd_malloc_and_get_section (abfd, section, &data)) + error (_("could not read '.gnu_debugaltlink' section: %s"), + bfd_errmsg (bfd_get_error ())); + cleanup = make_cleanup (xfree, data); + + filename = data; + if (!IS_ABSOLUTE_PATH (filename)) + { + char *abs = gdb_realpath (dwarf2_per_objfile->objfile->name); + char *rel; + + make_cleanup (xfree, abs); + abs = ldirname (abs); + make_cleanup (xfree, abs); + + rel = concat (abs, SLASH_STRING, filename, (char *) NULL); + make_cleanup (xfree, rel); + filename = rel; + } + + /* The format is just a NUL-terminated file name, followed by the + build-id. For now, though, we ignore the build-id. */ + dwz_bfd = gdb_bfd_open (filename, gnutarget, -1); + if (dwz_bfd == NULL) + error (_("could not read '%s': %s"), filename, + bfd_errmsg (bfd_get_error ())); + + if (!bfd_check_format (dwz_bfd, bfd_object)) + { + gdb_bfd_unref (dwz_bfd); + error (_("file '%s' was not usable: %s"), filename, + bfd_errmsg (bfd_get_error ())); + } + + result = OBSTACK_ZALLOC (&dwarf2_per_objfile->objfile->objfile_obstack, + struct dwz_file); + result->dwz_bfd = dwz_bfd; + + bfd_map_over_sections (dwz_bfd, locate_dwz_sections, result); + + do_cleanups (cleanup); + + return result; +} /* DWARF quick_symbols_functions support. */ @@ -2279,23 +2304,19 @@ extract_cu_value (const char *bytes, ULONGEST *result) 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. */ +/* A helper for create_cus_from_index that handles a given list of + CUs. */ static int -create_cus_from_index (struct objfile *objfile, const gdb_byte *cu_list, - offset_type cu_list_elements) +create_cus_from_index_list (struct objfile *objfile, + const gdb_byte *cu_list, offset_type n_elements, + struct dwarf2_section_info *section, + int is_dwz, + int base_offset) { offset_type i; - 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) + for (i = 0; i < n_elements; i += 2) { struct dwarf2_per_cu_data *the_cu; ULONGEST offset, length; @@ -2310,15 +2331,45 @@ create_cus_from_index (struct objfile *objfile, const gdb_byte *cu_list, the_cu->offset.sect_off = offset; the_cu->length = length; the_cu->objfile = objfile; - the_cu->info_or_types_section = &dwarf2_per_objfile->info; + the_cu->info_or_types_section = section; 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; + the_cu->is_dwz = is_dwz; + dwarf2_per_objfile->all_comp_units[base_offset + i / 2] = the_cu; } 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, + const gdb_byte *cu_list, offset_type cu_list_elements, + const gdb_byte *dwz_list, offset_type dwz_elements) +{ + struct dwz_file *dwz; + + dwarf2_per_objfile->n_comp_units = (cu_list_elements + dwz_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 *)); + + if (!create_cus_from_index_list (objfile, cu_list, cu_list_elements, + &dwarf2_per_objfile->info, 0, 0)) + return 0; + + if (dwz_elements == 0) + return 1; + + dwz = dwarf2_get_dwz_file (); + return create_cus_from_index_list (objfile, dwz_list, dwz_elements, + &dwz->info, 1, cu_list_elements / 2); +} + /* Create the signatured type hash table from the index. */ static int @@ -2508,33 +2559,44 @@ find_slot_in_mapped_hash (struct mapped_index *index, const char *name, } } -/* Read the index file. If everything went ok, initialize the "quick" - elements of all the CUs and return 1. Otherwise, return 0. */ +/* A helper function that reads the .gdb_index from SECTION and fills + in MAP. FILENAME is the name of the file containing the section; + it is used for error reporting. DEPRECATED_OK is nonzero if it is + ok to use deprecated sections. + + CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are + out parameters that are filled in with information about the CU and + TU lists in the section. + + Returns 1 if all went well, 0 otherwise. */ static int -dwarf2_read_index (struct objfile *objfile) +read_index_from_section (struct objfile *objfile, + const char *filename, + int deprecated_ok, + struct dwarf2_section_info *section, + struct mapped_index *map, + const gdb_byte **cu_list, + offset_type *cu_list_elements, + const gdb_byte **types_list, + offset_type *types_list_elements) { char *addr; - struct mapped_index *map; + offset_type version; offset_type *metadata; - const gdb_byte *cu_list; - const gdb_byte *types_list = NULL; - offset_type version, cu_list_elements; - offset_type types_list_elements = 0; int i; - if (dwarf2_section_empty_p (&dwarf2_per_objfile->gdb_index)) + if (dwarf2_section_empty_p (section)) return 0; /* Older elfutils strip versions could keep the section in the main executable while splitting it for the separate debug info file. */ - if ((bfd_get_file_flags (dwarf2_per_objfile->gdb_index.asection) - & SEC_HAS_CONTENTS) == 0) + if ((bfd_get_file_flags (section->asection) & SEC_HAS_CONTENTS) == 0) return 0; - dwarf2_read_section (objfile, &dwarf2_per_objfile->gdb_index); + dwarf2_read_section (objfile, section); - addr = dwarf2_per_objfile->gdb_index.buffer; + addr = section->buffer; /* Version check. */ version = MAYBE_SWAP (*(offset_type *) addr); /* Versions earlier than 3 emitted every copy of a psymbol. This @@ -2547,7 +2609,7 @@ dwarf2_read_index (struct objfile *objfile) if (!warning_printed) { warning (_("Skipping obsolete .gdb_index section in %s."), - objfile->name); + filename); warning_printed = 1; } return 0; @@ -2560,7 +2622,7 @@ dwarf2_read_index (struct objfile *objfile) set breakpoints on inlined functions by name, so we ignore these indices unless the user has done "set use-deprecated-index-sections on". */ - if (version < 6 && !use_deprecated_index_sections) + if (version < 6 && !deprecated_ok) { static int warning_printed = 0; if (!warning_printed) @@ -2569,7 +2631,7 @@ dwarf2_read_index (struct objfile *objfile) Skipping deprecated .gdb_index section in %s.\n\ Do \"set use-deprecated-index-sections on\" before the file is read\n\ to use the section anyway."), - objfile->name); + filename); warning_printed = 1; } return 0; @@ -2579,22 +2641,21 @@ to use the section anyway."), if (version > 7) return 0; - map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index); map->version = version; - map->total_size = dwarf2_per_objfile->gdb_index.size; + map->total_size = section->size; metadata = (offset_type *) (addr + sizeof (offset_type)); i = 0; - cu_list = addr + MAYBE_SWAP (metadata[i]); - cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i])) - / 8); + *cu_list = addr + MAYBE_SWAP (metadata[i]); + *cu_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - MAYBE_SWAP (metadata[i])) + / 8); ++i; - types_list = addr + MAYBE_SWAP (metadata[i]); - types_list_elements = ((MAYBE_SWAP (metadata[i + 1]) - - MAYBE_SWAP (metadata[i])) - / 8); + *types_list = addr + MAYBE_SWAP (metadata[i]); + *types_list_elements = ((MAYBE_SWAP (metadata[i + 1]) + - MAYBE_SWAP (metadata[i])) + / 8); ++i; map->address_table = addr + MAYBE_SWAP (metadata[i]); @@ -2610,11 +2671,55 @@ to use the section anyway."), map->constant_pool = addr + MAYBE_SWAP (metadata[i]); + return 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) +{ + struct mapped_index local_map, *map; + const gdb_byte *cu_list, *types_list, *dwz_list = NULL; + offset_type cu_list_elements, types_list_elements, dwz_list_elements = 0; + + if (!read_index_from_section (objfile, objfile->name, + use_deprecated_index_sections, + &dwarf2_per_objfile->gdb_index, &local_map, + &cu_list, &cu_list_elements, + &types_list, &types_list_elements)) + return 0; + /* Don't use the index if it's empty. */ - if (map->symbol_table_slots == 0) + if (local_map.symbol_table_slots == 0) return 0; - if (!create_cus_from_index (objfile, cu_list, cu_list_elements)) + /* If there is a .dwz file, read it so we can get its CU list as + well. */ + if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + struct mapped_index dwz_map; + const gdb_byte *dwz_types_ignore; + offset_type dwz_types_elements_ignore; + + if (!read_index_from_section (objfile, bfd_get_filename (dwz->dwz_bfd), + 1, + &dwz->gdb_index, &dwz_map, + &dwz_list, &dwz_list_elements, + &dwz_types_ignore, + &dwz_types_elements_ignore)) + { + warning (_("could not read '.gdb_index' section from %s; skipping"), + bfd_get_filename (dwz->dwz_bfd)); + return 0; + } + } + + if (!create_cus_from_index (objfile, cu_list, cu_list_elements, + dwz_list, dwz_list_elements)) return 0; if (types_list_elements) @@ -2635,7 +2740,10 @@ to use the section anyway."), return 0; } - create_addrmap_from_index (objfile, map); + create_addrmap_from_index (objfile, &local_map); + + map = obstack_alloc (&objfile->objfile_obstack, sizeof (struct mapped_index)); + *map = local_map; dwarf2_per_objfile->index_table = map; dwarf2_per_objfile->using_index = 1; @@ -3686,6 +3794,22 @@ read_comp_unit_head (struct comp_unit_head *cu_header, return info_ptr; } +/* Helper function that returns the proper abbrev section for + THIS_CU. */ + +static struct dwarf2_section_info * +get_abbrev_section_for_cu (struct dwarf2_per_cu_data *this_cu) +{ + struct dwarf2_section_info *abbrev; + + if (this_cu->is_dwz) + abbrev = &dwarf2_get_dwz_file ()->abbrev; + else + abbrev = &dwarf2_per_objfile->abbrev; + + return abbrev; +} + /* Subroutine of read_and_check_comp_unit_head and read_and_check_type_unit_head to simplify them. Perform various error checking on the header. */ @@ -3704,8 +3828,7 @@ error_check_comp_unit_head (struct comp_unit_head *header, filename); if (header->abbrev_offset.sect_off - >= dwarf2_section_size (dwarf2_per_objfile->objfile, - &dwarf2_per_objfile->abbrev)) + >= dwarf2_section_size (dwarf2_per_objfile->objfile, abbrev_section)) error (_("Dwarf Error: bad offset (0x%lx) in compilation unit header " "(offset 0x%lx + 6) [in module %s]"), (long) header->abbrev_offset.sect_off, (long) header->offset.sect_off, @@ -3942,6 +4065,7 @@ create_debug_types_hash_table (struct dwo_file *dwo_file, { bfd *abfd; gdb_byte *info_ptr, *end_ptr; + struct dwarf2_section_info *abbrev_section; dwarf2_read_section (objfile, section); info_ptr = section->buffer; @@ -3953,6 +4077,11 @@ create_debug_types_hash_table (struct dwo_file *dwo_file, not present, in which case section->asection will be NULL. */ abfd = section->asection->owner; + if (dwo_file) + abbrev_section = &dwo_file->sections.abbrev; + else + abbrev_section = &dwarf2_per_objfile->abbrev; + if (types_htab == NULL) { if (dwo_file) @@ -4192,7 +4321,8 @@ init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu, dwarf2_read_section (objfile, section); begin_info_ptr = info_ptr = section->buffer + this_cu->offset.sect_off; - abbrev_section = &dwarf2_per_objfile->abbrev; + + abbrev_section = get_abbrev_section_for_cu (this_cu); if (use_existing_cu && this_cu->cu != NULL) { @@ -4574,7 +4704,7 @@ init_cutu_and_read_dies_simple (struct dwarf2_per_cu_data *this_cu, void *data) { init_cutu_and_read_dies_no_follow (this_cu, - &dwarf2_per_objfile->abbrev, + get_abbrev_section_for_cu (this_cu), NULL, die_reader_func, data); } @@ -5202,6 +5332,9 @@ set_partial_user (struct objfile *objfile) struct partial_symtab *pst = per_cu->v.psymtab; int j; + if (pst == NULL) + continue; + for (j = 0; j < pst->number_of_dependencies; ++j) { /* Set the 'user' field only if it is not already set. */ @@ -5296,38 +5429,32 @@ load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu) load_partial_comp_unit_reader, NULL); } -/* Create a list of all compilation units in OBJFILE. - This is only done for -readnow and building partial symtabs. */ - static void -create_all_comp_units (struct objfile *objfile) +read_comp_units_from_section (struct objfile *objfile, + struct dwarf2_section_info *section, + unsigned int is_dwz, + int *n_allocated, + int *n_comp_units, + struct dwarf2_per_cu_data ***all_comp_units) { - int n_allocated; - int n_comp_units; - struct dwarf2_per_cu_data **all_comp_units; gdb_byte *info_ptr; + bfd *abfd = section->asection->owner; - dwarf2_read_section (objfile, &dwarf2_per_objfile->info); - info_ptr = dwarf2_per_objfile->info.buffer; + dwarf2_read_section (objfile, section); - n_comp_units = 0; - n_allocated = 10; - all_comp_units = xmalloc (n_allocated - * sizeof (struct dwarf2_per_cu_data *)); + info_ptr = section->buffer; - while (info_ptr < dwarf2_per_objfile->info.buffer - + dwarf2_per_objfile->info.size) + while (info_ptr < section->buffer + section->size) { unsigned int length, initial_length_size; struct dwarf2_per_cu_data *this_cu; sect_offset offset; - offset.sect_off = info_ptr - dwarf2_per_objfile->info.buffer; + offset.sect_off = info_ptr - section->buffer; /* Read just enough information to find out where the next compilation unit is. */ - length = read_initial_length (objfile->obfd, info_ptr, - &initial_length_size); + length = read_initial_length (abfd, info_ptr, &initial_length_size); /* Save the compilation unit for later lookup. */ this_cu = obstack_alloc (&objfile->objfile_obstack, @@ -5335,20 +5462,50 @@ 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->is_dwz = is_dwz; this_cu->objfile = objfile; - this_cu->info_or_types_section = &dwarf2_per_objfile->info; + this_cu->info_or_types_section = section; - if (n_comp_units == n_allocated) + if (*n_comp_units == *n_allocated) { - n_allocated *= 2; - all_comp_units = xrealloc (all_comp_units, - n_allocated - * sizeof (struct dwarf2_per_cu_data *)); + *n_allocated *= 2; + *all_comp_units = xrealloc (*all_comp_units, + *n_allocated + * sizeof (struct dwarf2_per_cu_data *)); } - all_comp_units[n_comp_units++] = this_cu; + (*all_comp_units)[*n_comp_units] = this_cu; + ++*n_comp_units; info_ptr = info_ptr + this_cu->length; } +} + +/* Create a list of all compilation units in OBJFILE. + This is only done for -readnow and building partial symtabs. */ + +static void +create_all_comp_units (struct objfile *objfile) +{ + int n_allocated; + int n_comp_units; + struct dwarf2_per_cu_data **all_comp_units; + + n_comp_units = 0; + n_allocated = 10; + all_comp_units = xmalloc (n_allocated + * sizeof (struct dwarf2_per_cu_data *)); + + read_comp_units_from_section (objfile, &dwarf2_per_objfile->info, 0, + &n_allocated, &n_comp_units, &all_comp_units); + + if (bfd_get_section_by_name (objfile->obfd, ".gnu_debugaltlink") != NULL) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + read_comp_units_from_section (objfile, &dwz->info, 1, + &n_allocated, &n_comp_units, + &all_comp_units); + } dwarf2_per_objfile->all_comp_units = obstack_alloc (&objfile->objfile_obstack, @@ -5441,6 +5598,7 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc, } per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset, + pdi->is_dwz, cu->objfile); /* Go read the partial unit, if needed. */ @@ -5498,7 +5656,8 @@ partial_die_parent_scope (struct partial_die_info *pdi, real_pdi = pdi; while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); parent = real_pdi->die_parent; if (parent == NULL) @@ -5998,6 +6157,9 @@ skip_one_die (const struct die_reader_specs *reader, gdb_byte *info_ptr, else info_ptr += cu->header.offset_size; break; + case DW_FORM_GNU_ref_alt: + info_ptr += cu->header.offset_size; + break; case DW_FORM_addr: info_ptr += cu->header.addr_size; break; @@ -6027,6 +6189,7 @@ skip_one_die (const struct die_reader_specs *reader, gdb_byte *info_ptr, break; case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: info_ptr += cu->header.offset_size; break; case DW_FORM_exprloc: @@ -6694,7 +6857,9 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu, it, by scanning the DIE's below the compilation unit. */ get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu); - static_block = end_symtab_get_static_block (highpc + baseaddr, objfile, 0); + static_block + = end_symtab_get_static_block (highpc + baseaddr, objfile, 0, + per_cu->s.imported_symtabs != NULL); /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges. Also, DW_AT_ranges may record ranges not belonging to any child DIEs @@ -6845,9 +7010,11 @@ process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu) struct dwarf2_per_cu_data *per_cu; struct symtab *imported_symtab; sect_offset offset; + int is_dwz; offset = dwarf2_get_ref_die_offset (attr); - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz); + per_cu = dwarf2_find_containing_comp_unit (offset, is_dwz, cu->objfile); /* Queue the unit, if needed. */ if (maybe_queue_comp_unit (cu, per_cu, cu->language)) @@ -8116,24 +8283,21 @@ try_open_dwo_file (const char *file_name) if (desc < 0) return NULL; - sym_bfd = bfd_fopen (absolute_name, gnutarget, FOPEN_RB, desc); + sym_bfd = gdb_bfd_open (absolute_name, gnutarget, desc); if (!sym_bfd) { xfree (absolute_name); return NULL; } + xfree (absolute_name); bfd_set_cacheable (sym_bfd, 1); if (!bfd_check_format (sym_bfd, bfd_object)) { - bfd_close (sym_bfd); /* This also closes desc. */ - xfree (absolute_name); + gdb_bfd_unref (sym_bfd); /* This also closes desc. */ return NULL; } - /* bfd_usrdata exists for applications and libbfd must not touch it. */ - gdb_assert (bfd_usrdata (sym_bfd) == NULL); - return sym_bfd; } @@ -8325,20 +8489,7 @@ free_dwo_file (struct dwo_file *dwo_file, struct objfile *objfile) struct dwarf2_section_info *section; gdb_assert (dwo_file->dwo_bfd != objfile->obfd); - bfd_close (dwo_file->dwo_bfd); - - munmap_section_buffer (&dwo_file->sections.abbrev); - munmap_section_buffer (&dwo_file->sections.info); - munmap_section_buffer (&dwo_file->sections.line); - munmap_section_buffer (&dwo_file->sections.loc); - munmap_section_buffer (&dwo_file->sections.str); - munmap_section_buffer (&dwo_file->sections.str_offsets); - - for (ix = 0; - VEC_iterate (dwarf2_section_info_def, dwo_file->sections.types, - ix, section); - ++ix) - munmap_section_buffer (section); + gdb_bfd_unref (dwo_file->dwo_bfd); VEC_free (dwarf2_section_info_def, dwo_file->sections.types); } @@ -10721,6 +10872,29 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) new_symbol (die, this_type, cu); } +/* Create a new array dimension referencing its target type TYPE. + + Multidimensional arrays are internally represented as a stack of + singledimensional arrays being referenced by their TYPE_TARGET_TYPE. */ + +static struct type * +create_single_array_dimension (struct type *type, struct type *range_type, + struct die_info *die, struct dwarf2_cu *cu) +{ + type = create_array_type (NULL, type, range_type); + + /* These generic type attributes need to be fetched by + evaluate_subexp_standard <multi_f77_subscript>'s call of + value_subscripted_rvalue only for the innermost array type. */ + fetch_die_type_attrs (die, type, cu); + + /* These generic type attributes are checked for allocated/associated + validity while accessing FIELD_LOC_KIND_DWARF_BLOCK. */ + fetch_die_type_attrs (die, range_type, cu); + + return type; +} + /* Extract all information from a DW_TAG_array_type DIE and put it in the DIE's type field. For now, this only handles one dimensional arrays. */ @@ -10734,7 +10908,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; @@ -10787,17 +10961,19 @@ 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); + + /* Data locations should be set only for the outermost dimension as they + would be confusing for the dereferenced offset on the inner ones. */ + 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)); /* Understand Dwarf2 support for vector types (like they occur on the PowerPC w/ AltiVec). Gcc just adds another attribute to the @@ -11281,29 +11457,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) + if (attr && attr_form_is_block (attr)) { - length = DW_UNSND (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 = safe_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); @@ -11607,7 +11868,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) struct type *base_type; struct type *range_type; struct attribute *attr; - LONGEST low, high; + LONGEST low; int low_default_is_valid; char *name; LONGEST negative_mask; @@ -11663,42 +11924,6 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) "- DIE at 0x%x [in module %s]"), die->offset.sect_off, cu->objfile->name); - attr = dwarf2_attr (die, DW_AT_upper_bound, cu); - if (attr) - { - if (attr_form_is_block (attr) || 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); - } - else - { - attr = dwarf2_attr (die, DW_AT_count, cu); - if (attr) - { - int count = dwarf2_get_attr_constant_value (attr, 1); - high = low + count - 1; - } - else - { - /* Unspecified array length. */ - high = low - 1; - } - } - /* Dwarf-2 specifications explicitly allows to create subrange types without specifying a base type. In that case, the base type must be set to the type of @@ -11737,24 +11962,163 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) } } - negative_mask = + /* LOW_BOUND and HIGH_BOUND are set for real below. */ + range_type = create_range_type (NULL, base_type, 0, -1); + TYPE_UNSIGNED (range_type) = 0; + + 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; - range_type = create_range_type (NULL, base_type, low, high); + /* 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. */ - /* 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_is_block (attr)) - TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; + attr = dwarf2_attr (die, DW_AT_lower_bound, cu); + 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; - /* Ada expects an empty array on no boundary attributes. */ - if (attr == NULL && cu->language != language_ada) - TYPE_HIGH_BOUND_UNDEFINED (range_type) = 1; + 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 || (!attr_form_is_block (attr) && !attr_form_is_constant (attr) + && !is_ref_attr (attr))) + { + attr = dwarf2_attr (die, DW_AT_count, cu); + /* It does not hurt but it is needlessly ineffective in check_typedef. */ + if (attr && (attr_form_is_block (attr) || attr_form_is_constant (attr))) + { + TYPE_RANGE_HIGH_BOUND_IS_COUNT (range_type) = 1; + TYPE_DYNAMIC (range_type) = 1; + } + /* Pass it now as the regular DW_AT_upper_bound. */ + } + + if (attr && attr_form_is_block (attr) && 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 + { + LONGEST high; + + if (attr && attr_form_is_constant (attr)) + high = dwarf2_get_attr_constant_value (attr, 0); + else + { + /* Ada expects an empty array on no boundary attributes. */ + if (cu->language != language_ada) + 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; + } + + /* 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; + + 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)->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) @@ -12544,6 +12908,8 @@ read_partial_die (const struct die_reader_specs *reader, case DW_AT_extension: part_die->has_specification = 1; part_die->spec_offset = dwarf2_get_ref_die_offset (&attr); + part_die->spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); break; case DW_AT_sibling: /* Ignore absolute siblings, they might point outside of @@ -12590,7 +12956,11 @@ read_partial_die (const struct die_reader_specs *reader, case DW_AT_import: if (part_die->tag == DW_TAG_imported_unit) - part_die->d.offset = dwarf2_get_ref_die_offset (&attr); + { + part_die->d.offset = dwarf2_get_ref_die_offset (&attr); + part_die->is_dwz = (attr.form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz); + } break; default: @@ -12661,13 +13031,14 @@ find_partial_die_in_comp_unit (sect_offset offset, struct dwarf2_cu *cu) DW_FORM_ref_sig8). */ static struct partial_die_info * -find_partial_die (sect_offset offset, struct dwarf2_cu *cu) +find_partial_die (sect_offset offset, int offset_in_dwz, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct dwarf2_per_cu_data *per_cu = NULL; struct partial_die_info *pd = NULL; - if (offset_in_cu_p (&cu->header, offset)) + if (offset_in_dwz == cu->per_cu->is_dwz + && offset_in_cu_p (&cu->header, offset)) { pd = find_partial_die_in_comp_unit (offset, cu); if (pd != NULL) @@ -12686,7 +13057,8 @@ find_partial_die (sect_offset offset, struct dwarf2_cu *cu) (long) cu->header.offset.sect_off, (long) offset.sect_off, bfd_get_filename (objfile->obfd)); } - per_cu = dwarf2_find_containing_comp_unit (offset, objfile); + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + objfile); if (per_cu->cu == NULL || per_cu->cu->partial_dies == NULL) load_partial_comp_unit (per_cu); @@ -12744,7 +13116,8 @@ guess_partial_die_structure_name (struct partial_die_info *struct_pdi, real_pdi = struct_pdi; while (real_pdi->has_specification) - real_pdi = find_partial_die (real_pdi->spec_offset, cu); + real_pdi = find_partial_die (real_pdi->spec_offset, + real_pdi->spec_is_dwz, cu); if (real_pdi->die_parent != NULL) return; @@ -12792,7 +13165,8 @@ fixup_partial_die (struct partial_die_info *part_die, { struct partial_die_info *spec_die; - spec_die = find_partial_die (part_die->spec_offset, cu); + spec_die = find_partial_die (part_die->spec_offset, + part_die->spec_is_dwz, cu); fixup_partial_die (spec_die, cu); @@ -12880,6 +13254,10 @@ read_attribute_value (const struct die_reader_specs *reader, &cu->header, &bytes_read); info_ptr += bytes_read; break; + case DW_FORM_GNU_ref_alt: + DW_UNSND (attr) = read_offset (abfd, info_ptr, &cu->header, &bytes_read); + info_ptr += bytes_read; + break; case DW_FORM_addr: DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read); info_ptr += bytes_read; @@ -12922,10 +13300,25 @@ read_attribute_value (const struct die_reader_specs *reader, info_ptr += bytes_read; break; case DW_FORM_strp: - DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, - &bytes_read); - DW_STRING_IS_CANONICAL (attr) = 0; - info_ptr += bytes_read; + if (!cu->per_cu->is_dwz) + { + DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, + &bytes_read); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + break; + } + /* FALLTHROUGH */ + case DW_FORM_GNU_strp_alt: + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + LONGEST str_offset = read_offset (abfd, info_ptr, cu_header, + &bytes_read); + + DW_STRING (attr) = read_indirect_string_from_dwz (dwz, str_offset); + DW_STRING_IS_CANONICAL (attr) = 0; + info_ptr += bytes_read; + } break; case DW_FORM_exprloc: case DW_FORM_block: @@ -13037,6 +13430,10 @@ read_attribute_value (const struct die_reader_specs *reader, bfd_get_filename (abfd)); } + /* Super hack. */ + if (cu->per_cu->is_dwz && is_ref_attr (attr)) + attr->form = DW_FORM_GNU_ref_alt; + /* We have seen instances where the compiler tried to emit a byte size attribute of -1 which ended up being encoded as an unsigned 0xffffffff. Although 0xffffffff is technically a valid size value, @@ -13333,6 +13730,30 @@ read_indirect_string_at_offset (bfd *abfd, LONGEST str_offset) return (char *) (dwarf2_per_objfile->str.buffer + str_offset); } +/* Read a string at offset STR_OFFSET in the .debug_str section from + the .dwz file DWZ. Throw an error if the offset is too large. If + the string consists of a single NUL byte, return NULL; otherwise + return a pointer to the string. */ + +static char * +read_indirect_string_from_dwz (struct dwz_file *dwz, LONGEST str_offset) +{ + dwarf2_read_section (dwarf2_per_objfile->objfile, &dwz->str); + + if (dwz->str.buffer == NULL) + error (_("DW_FORM_GNU_strp_alt used without .debug_str " + "section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + if (str_offset >= dwz->str.size) + error (_("DW_FORM_GNU_strp_alt pointing outside of " + ".debug_str section [in module %s]"), + bfd_get_filename (dwz->dwz_bfd)); + gdb_assert (HOST_CHAR_BIT == 8); + if (dwz->str.buffer[str_offset] == '\0') + return NULL; + return (char *) (dwz->str.buffer + str_offset); +} + static char * read_indirect_string (bfd *abfd, gdb_byte *buf, const struct comp_unit_head *cu_header, @@ -13804,6 +14225,30 @@ add_file_name (struct line_header *lh, fe->symtab = NULL; } +/* A convenience function to find the proper .debug_line section for a + CU. */ + +static struct dwarf2_section_info * +get_debug_line_section (struct dwarf2_cu *cu) +{ + struct dwarf2_section_info *section; + + /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the + DWO file. */ + if (cu->dwo_unit && cu->per_cu->is_debug_types) + section = &cu->dwo_unit->dwo_file->sections.line; + else if (cu->per_cu->is_dwz) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + section = &dwz->line; + } + else + section = &dwarf2_per_objfile->line; + + return section; +} + /* Read the statement program header starting at OFFSET in .debug_line, or .debug_line.dwo. Return a pointer to a struct line_header, allocated using xmalloc. @@ -13824,13 +14269,7 @@ dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu) struct dwarf2_section_info *section; bfd *abfd; - /* For TUs in DWO files, the DW_AT_stmt_list attribute lives in the - DWO file. */ - if (cu->dwo_unit && cu->per_cu->is_debug_types) - section = &cu->dwo_unit->dwo_file->sections.line; - else - section = &dwarf2_per_objfile->line; - + section = get_debug_line_section (cu); dwarf2_read_section (dwarf2_per_objfile->objfile, section); if (section->buffer == NULL) { @@ -14155,7 +14594,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, GCd by the linker. Ignore it. PR gdb/12528 */ long line_offset - = line_ptr - dwarf2_per_objfile->line.buffer; + = line_ptr - get_debug_line_section (cu)->buffer; complaint (&symfile_complaints, _(".debug_line address at offset 0x%lx is 0 " @@ -14534,10 +14973,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); if (SYMBOL_COMPUTED_OPS (sym) == &dwarf2_loclist_funcs) cu->has_loclist = 1; @@ -14578,6 +15019,8 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, else sym = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol); OBJSTAT (objfile, n_syms++); + /* 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_SET_LANGUAGE (sym, cu->language); @@ -15001,6 +15444,7 @@ dwarf2_const_value_attr (struct attribute *attr, struct type *type, case DW_FORM_string: case DW_FORM_strp: case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: /* DW_STRING is already allocated on the objfile obstack, point directly to it. */ *bytes = (gdb_byte *) DW_STRING (attr); @@ -15187,7 +15631,15 @@ lookup_die_type (struct die_info *die, struct attribute *attr, /* First see if we have it cached. */ - if (is_ref_attr (attr)) + if (attr->form == DW_FORM_GNU_ref_alt) + { + struct dwarf2_per_cu_data *per_cu; + sect_offset offset = dwarf2_get_ref_die_offset (attr); + + per_cu = dwarf2_find_containing_comp_unit (offset, 1, cu->objfile); + this_type = get_die_type_at_offset (offset, per_cu); + } + else if (is_ref_attr (attr)) { sect_offset offset = dwarf2_get_ref_die_offset (attr); @@ -15352,6 +15804,9 @@ read_type_die_1 (struct die_info *die, struct dwarf2_cu *cu) break; } + if (this_type) + finalize_type (this_type); + return this_type; } @@ -15960,6 +16415,10 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) fprintf_unfiltered (f, "ref address: "); fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); break; + case DW_FORM_GNU_ref_alt: + fprintf_unfiltered (f, "alt ref address: "); + fputs_filtered (hex_string (DW_UNSND (&die->attrs[i])), f); + break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: @@ -15991,6 +16450,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die) case DW_FORM_string: case DW_FORM_strp: case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: fprintf_unfiltered (f, "string: \"%s\" (%s canonicalized)", DW_STRING (&die->attrs[i]) ? DW_STRING (&die->attrs[i]) : "", @@ -16094,6 +16554,7 @@ is_ref_attr (struct attribute *attr) case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: + case DW_FORM_GNU_ref_alt: return 1; default: return 0; @@ -16171,7 +16632,8 @@ follow_die_ref_or_sig (struct die_info *src_die, struct attribute *attr, Returns NULL if OFFSET is invalid. */ static struct die_info * -follow_die_offset (sect_offset offset, struct dwarf2_cu **ref_cu) +follow_die_offset (sect_offset offset, int offset_in_dwz, + struct dwarf2_cu **ref_cu) { struct die_info temp_die; struct dwarf2_cu *target_cu, *cu = *ref_cu; @@ -16188,11 +16650,13 @@ follow_die_offset (sect_offset offset, struct dwarf2_cu **ref_cu) if (! offset_in_cu_p (&cu->header, offset)) return NULL; } - else if (! offset_in_cu_p (&cu->header, offset)) + else if (offset_in_dwz != cu->per_cu->is_dwz + || ! offset_in_cu_p (&cu->header, offset)) { struct dwarf2_per_cu_data *per_cu; - per_cu = dwarf2_find_containing_comp_unit (offset, cu->objfile); + per_cu = dwarf2_find_containing_comp_unit (offset, offset_in_dwz, + cu->objfile); /* If necessary, add it to the queue and load its DIEs. */ if (maybe_queue_comp_unit (cu, per_cu, cu->language)) @@ -16224,7 +16688,10 @@ follow_die_ref (struct die_info *src_die, struct attribute *attr, struct dwarf2_cu *cu = *ref_cu; struct die_info *die; - die = follow_die_offset (offset, ref_cu); + die = follow_die_offset (offset, + (attr->form == DW_FORM_GNU_ref_alt + || cu->per_cu->is_dwz), + ref_cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced from DIE " "at 0x%x [in module %s]"), @@ -16255,7 +16722,7 @@ dwarf2_fetch_die_location_block (cu_offset offset_in_cu, load_cu (per_cu); cu = per_cu->cu; - die = follow_die_offset (offset, &cu); + die = follow_die_offset (offset, per_cu->is_dwz, &cu); if (!die) error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"), offset.sect_off, per_cu->objfile->name); @@ -17049,6 +17516,7 @@ skip_form_bytes (bfd *abfd, gdb_byte *bytes, gdb_byte *buffer_end, case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_GNU_strp_alt: bytes += offset_size; break; @@ -17204,7 +17672,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, struct macro_source_file *current_file, struct line_header *lh, char *comp_dir, struct dwarf2_section_info *section, - int section_is_gnu, + int section_is_gnu, int section_is_dwz, unsigned int offset_size, struct objfile *objfile, htab_t include_hash) @@ -17255,6 +17723,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, case DW_MACRO_GNU_undef: case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_GNU_define_indirect_alt: + case DW_MACRO_GNU_undef_indirect_alt: { unsigned int bytes_read; int line; @@ -17277,11 +17747,21 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, str_offset = read_offset_1 (abfd, mac_ptr, offset_size); mac_ptr += offset_size; - body = read_indirect_string_at_offset (abfd, str_offset); + if (macinfo_type == DW_MACRO_GNU_define_indirect_alt + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt + || section_is_dwz) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + body = read_indirect_string_from_dwz (dwz, str_offset); + } + else + body = read_indirect_string_at_offset (abfd, str_offset); } is_define = (macinfo_type == DW_MACRO_GNU_define - || macinfo_type == DW_MACRO_GNU_define_indirect); + || macinfo_type == DW_MACRO_GNU_define_indirect + || macinfo_type == DW_MACRO_GNU_define_indirect_alt); if (! current_file) { /* DWARF violation as no main source is present. */ @@ -17305,7 +17785,8 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, else { gdb_assert (macinfo_type == DW_MACRO_GNU_undef - || macinfo_type == DW_MACRO_GNU_undef_indirect); + || macinfo_type == DW_MACRO_GNU_undef_indirect + || macinfo_type == DW_MACRO_GNU_undef_indirect_alt); macro_undef (current_file, line, body); } } @@ -17380,6 +17861,7 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, break; case DW_MACRO_GNU_transparent_include: + case DW_MACRO_GNU_transparent_include_alt: { LONGEST offset; void **slot; @@ -17398,13 +17880,32 @@ dwarf_decode_macro_bytes (bfd *abfd, gdb_byte *mac_ptr, gdb_byte *mac_end, } else { + bfd *include_bfd = abfd; + struct dwarf2_section_info *include_section = section; + struct dwarf2_section_info alt_section; + gdb_byte *include_mac_end = mac_end; + int is_dwz = section_is_dwz; + *slot = mac_ptr; - dwarf_decode_macro_bytes (abfd, - section->buffer + offset, - mac_end, current_file, + if (macinfo_type == DW_MACRO_GNU_transparent_include_alt) + { + struct dwz_file *dwz = dwarf2_get_dwz_file (); + + dwarf2_read_section (dwarf2_per_objfile->objfile, + &dwz->macro); + + include_bfd = dwz->macro.asection->owner; + include_section = &dwz->macro; + include_mac_end = dwz->macro.buffer + dwz->macro.size; + is_dwz = 1; + } + + dwarf_decode_macro_bytes (include_bfd, + include_section->buffer + offset, + include_mac_end, current_file, lh, comp_dir, - section, section_is_gnu, + section, section_is_gnu, is_dwz, offset_size, objfile, include_hash); htab_remove_elt (include_hash, mac_ptr); @@ -17571,6 +18072,8 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset, case DW_MACRO_GNU_define_indirect: case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_GNU_define_indirect_alt: + case DW_MACRO_GNU_undef_indirect_alt: { unsigned int bytes_read; @@ -17581,6 +18084,7 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset, break; case DW_MACRO_GNU_transparent_include: + case DW_MACRO_GNU_transparent_include_alt: /* Note that, according to the spec, a transparent include chain cannot call DW_MACRO_GNU_start_file. So, we can just skip this opcode. */ @@ -17623,7 +18127,8 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset, slot = htab_find_slot (include_hash, mac_ptr, INSERT); *slot = mac_ptr; dwarf_decode_macro_bytes (abfd, mac_ptr, mac_end, - current_file, lh, comp_dir, section, section_is_gnu, + current_file, lh, comp_dir, section, + section_is_gnu, 0, offset_size, objfile, include_hash); do_cleanups (cleanup); } @@ -17721,62 +18226,100 @@ fill_in_loclist_baton (struct dwarf2_cu *cu, baton->from_dwo = cu->dwo_unit != NULL; } -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) +{ + struct objfile *objfile = dwarf2_per_objfile->objfile; + struct dwarf2_locexpr_baton *baton; + + gdb_assert (attr_form_is_block (attr)); + + baton = obstack_alloc (&objfile->objfile_obstack, sizeof (*baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); + + /* Note that we're just copying the block's data pointer + here, not the actual data. We're still pointing into the + info_buffer for SYM's objfile; right now we never release + that buffer, but when we do clean up properly this may + need to change. */ + baton->size = DW_BLOCK (attr)->size; + baton->data = DW_BLOCK (attr)->data; + gdb_assert (baton->size == 0 || baton->data != NULL); + + return baton; +} + +static struct dwarf2_loclist_baton * +dwarf2_attr_to_loclist_baton (struct attribute *attr, struct dwarf2_cu *cu) { struct objfile *objfile = dwarf2_per_objfile->objfile; struct dwarf2_section_info *section = cu_debug_loc_section (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, section); - if (attr_form_is_section_offset (attr) + if (!(attr_form_is_section_offset (attr) /* .debug_loc{,.dwo} 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_section_size (objfile, section)) - { - struct dwarf2_loclist_baton *baton; + && DW_UNSND (attr) < dwarf2_section_size (objfile, section))) + return NULL; - baton = obstack_alloc (&objfile->objfile_obstack, - sizeof (struct dwarf2_loclist_baton)); + baton = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_loclist_baton)); - fill_in_loclist_baton (cu, baton, attr); + fill_in_loclist_baton (cu, baton, attr); - if (cu->base_known == 0) - complaint (&symfile_complaints, - _("Location list used without " - "specifying the 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 (&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; - } + 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; } } @@ -17878,28 +18421,35 @@ dwarf2_per_cu_text_offset (struct dwarf2_per_cu_data *per_cu) static struct dwarf2_per_cu_data * dwarf2_find_containing_comp_unit (sect_offset offset, + unsigned int offset_in_dwz, struct objfile *objfile) { struct dwarf2_per_cu_data *this_cu; int low, high; + const sect_offset *cu_off; low = 0; high = dwarf2_per_objfile->n_comp_units - 1; while (high > low) { + struct dwarf2_per_cu_data *mid_cu; int mid = low + (high - low) / 2; - if (dwarf2_per_objfile->all_comp_units[mid]->offset.sect_off - >= offset.sect_off) + mid_cu = dwarf2_per_objfile->all_comp_units[mid]; + cu_off = &mid_cu->offset; + if (mid_cu->is_dwz > offset_in_dwz + || (mid_cu->is_dwz == offset_in_dwz + && cu_off->sect_off >= offset.sect_off)) high = mid; else low = mid + 1; } gdb_assert (low == high); - if (dwarf2_per_objfile->all_comp_units[low]->offset.sect_off - > offset.sect_off) + this_cu = dwarf2_per_objfile->all_comp_units[low]; + cu_off = &this_cu->offset; + if (this_cu->is_dwz != offset_in_dwz || cu_off->sect_off > offset.sect_off) { - if (low == 0) + if (low == 0 || this_cu->is_dwz != offset_in_dwz) error (_("Dwarf Error: could not find partial DIE containing " "offset 0x%lx [in module %s]"), (long) offset.sect_off, bfd_get_filename (objfile->obfd)); @@ -18140,6 +18690,25 @@ per_cu_offset_and_type_eq (const void *item_lhs, const void *item_rhs) && ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off); } +/* 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_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. @@ -18164,6 +18733,8 @@ set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) struct dwarf2_per_cu_offset_and_type **slot, ofs; struct objfile *objfile = cu->objfile; + 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 @@ -18341,53 +18912,13 @@ show_dwarf2_cmd (char *args, int from_tty) cmd_show_list (show_dwarf2_cmdlist, from_tty, ""); } -/* If section described by INFO was mmapped, munmap it now. */ - -static void -munmap_section_buffer (struct dwarf2_section_info *info) -{ - if (info->map_addr != NULL) - { -#ifdef HAVE_MMAP - int res; - - res = munmap (info->map_addr, info->map_len); - gdb_assert (res == 0); -#else - /* Without HAVE_MMAP, we should never be here to begin with. */ - gdb_assert_not_reached ("no mmap support"); -#endif - } -} - -/* munmap debug sections for OBJFILE, if necessary. */ +/* Free data associated with OBJFILE, if necessary. */ static void dwarf2_per_objfile_free (struct objfile *objfile, void *d) { struct dwarf2_per_objfile *data = d; int ix; - struct dwarf2_section_info *section; - - /* This is sorted according to the order they're defined in to make it easier - to keep in sync. */ - munmap_section_buffer (&data->info); - munmap_section_buffer (&data->abbrev); - munmap_section_buffer (&data->line); - munmap_section_buffer (&data->loc); - munmap_section_buffer (&data->macinfo); - munmap_section_buffer (&data->macro); - munmap_section_buffer (&data->str); - munmap_section_buffer (&data->ranges); - munmap_section_buffer (&data->addr); - munmap_section_buffer (&data->frame); - munmap_section_buffer (&data->eh_frame); - munmap_section_buffer (&data->gdb_index); - - for (ix = 0; - VEC_iterate (dwarf2_section_info_def, data->types, ix, section); - ++ix) - munmap_section_buffer (section); for (ix = 0; ix < dwarf2_per_objfile->n_comp_units; ++ix) VEC_free (dwarf2_per_cu_ptr, @@ -18397,6 +18928,9 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d) if (data->dwo_files) free_dwo_files (data->dwo_files, objfile); + + if (data->dwz_file && data->dwz_file->dwz_bfd) + gdb_bfd_unref (data->dwz_file->dwz_bfd); } diff --git a/gdb/elfread.c b/gdb/elfread.c index 1edfb27..0b54b8a 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -44,6 +44,7 @@ #include "gdbthread.h" #include "regcache.h" #include "bcache.h" +#include "gdb_bfd.h" extern void _initialize_elfread (void); @@ -1108,7 +1109,7 @@ build_id_verify (const char *filename, struct build_id *check) int retval = 0; /* We expect to be silent on the non-existing files. */ - abfd = bfd_open_maybe_remote (filename); + abfd = gdb_bfd_open_maybe_remote (filename); if (abfd == NULL) return 0; @@ -1123,7 +1124,7 @@ build_id_verify (const char *filename, struct build_id *check) else retval = 1; - gdb_bfd_close_or_warn (abfd); + gdb_bfd_unref (abfd); xfree (found); @@ -1444,10 +1445,12 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags) if (debugfile) { + struct cleanup *cleanup = make_cleanup (xfree, debugfile); bfd *abfd = symfile_bfd_open (debugfile); + make_cleanup_bfd_unref (abfd); symbol_file_add_separate (abfd, symfile_flags, objfile); - xfree (debugfile); + do_cleanups (cleanup); } } diff --git a/gdb/eval.c b/gdb/eval.c index 7d3a8b9..f69dff0 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -41,6 +41,7 @@ #include "gdb_obstack.h" #include "objfiles.h" #include "python/python.h" +#include "dwarf2loc.h" #include "gdb_assert.h" @@ -500,27 +501,217 @@ init_array_element (struct value *array, struct value *element, } static struct value * -value_f90_subarray (struct value *array, - struct expression *exp, int *pos, enum noside noside) +value_f90_subarray (struct value *array, struct expression *exp, int *pos, + int nargs, enum noside noside) { - int pc = (*pos) + 1; - LONGEST low_bound, high_bound; - struct type *range = check_typedef (TYPE_INDEX_TYPE (value_type (array))); - enum f90_range_type range_type = longest_to_int (exp->elts[pc].longconst); - - *pos += 3; - - if (range_type == LOW_BOUND_DEFAULT || range_type == BOTH_BOUND_DEFAULT) - low_bound = TYPE_LOW_BOUND (range); + /* Type to use for the newly allocated value ARRAY. */ + struct type *new_array_type; + + /* Type being iterated for each dimension. */ + struct type *type, *type_last_target; + + /* Pointer in the last holder to the type of current dimension. */ + struct type **typep = &new_array_type; + + struct subscript_index + { + enum { SUBSCRIPT_RANGE, SUBSCRIPT_NUMBER } kind; + union + { + struct subscript_range + { + enum f90_range_type f90_range_type; + LONGEST low_bound, high_bound; + } + range; + LONGEST number; + }; + } + *subscript_array; + struct type **type_array; + int i; + struct cleanup *old_chain; + CORE_ADDR value_byte_address, value_byte_offset = 0; + htab_t copied_types; + struct value *saved_array; + + old_chain = make_cleanup (null_cleanup, 0); + object_address_set (value_raw_address (array)); + + if (value_optimized_out (array) + || (VALUE_LVAL (array) != not_lval + && VALUE_LVAL (array) != lval_memory + && VALUE_LVAL (array) != lval_internalvar_component + && VALUE_LVAL (array) != lval_internalvar)) + error (_("value being subranged must be in memory")); + type = check_typedef (value_type (array)); + f_object_address_data_valid_or_error (type); + + copied_types = create_copied_types_hash (NULL); + type = copy_type_recursive (type, copied_types); + htab_delete (copied_types); + + if (nargs != calc_f77_array_dims (type)) + error (_("Wrong number of subscripts")); + + if (TYPE_DATA_LOCATION_IS_ADDR (type)) + { + value_byte_address = (TYPE_DATA_LOCATION_ADDR (type) + + value_offset (array)); + TYPE_DATA_LOCATION_IS_ADDR (type) = 0; + TYPE_DATA_LOCATION_DWARF_BLOCK (type) = NULL; + } else - low_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + { + gdb_assert (TYPE_DATA_LOCATION_DWARF_BLOCK (type) == NULL); + value_byte_address = value_address (array); + } + + new_array_type = type; + + subscript_array = alloca (sizeof (*subscript_array) * nargs); + + gdb_assert (nargs > 0); + + /* Now that we know we have a legal array subscript expression + let us actually find out where this element exists in the array. */ + + /* Take array indices left to right. */ + for (i = 0; i < nargs; i++) + { + struct subscript_index *index = &subscript_array[i]; + + if (exp->elts[*pos].opcode == OP_F90_RANGE) + { + int pc = (*pos) + 1; + struct subscript_range *range; + + index->kind = SUBSCRIPT_RANGE; + range = &index->range; + + *pos += 3; + range->f90_range_type = longest_to_int (exp->elts[pc].longconst); + + if (range->f90_range_type == HIGH_BOUND_DEFAULT + || range->f90_range_type == NONE_BOUND_DEFAULT) + range->low_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, + pos, noside)); + + if (range->f90_range_type == LOW_BOUND_DEFAULT + || range->f90_range_type == NONE_BOUND_DEFAULT) + range->high_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, + pos, noside)); + } + else + { + struct value *val; + + index->kind = SUBSCRIPT_NUMBER; - if (range_type == HIGH_BOUND_DEFAULT || range_type == BOTH_BOUND_DEFAULT) - high_bound = TYPE_HIGH_BOUND (range); + /* Evaluate each subscript; it must be a legal integer in F77. */ + val = evaluate_subexp_with_coercion (exp, pos, noside); + index->number = value_as_long (val); + } + } + + /* Internal type of array is arranged right to left. */ + for (i = nargs - 1; i >= 0; i--) + { + struct subscript_index *index = &subscript_array[i]; + struct type *range_type = TYPE_INDEX_TYPE (type); + + switch (index->kind) + { + case SUBSCRIPT_RANGE: + { + struct subscript_range *range = &index->range; + CORE_ADDR byte_offset; + + if (range->f90_range_type == LOW_BOUND_DEFAULT + || range->f90_range_type == BOTH_BOUND_DEFAULT) + range->low_bound = TYPE_LOW_BOUND (range_type); + + if (range->f90_range_type == HIGH_BOUND_DEFAULT + || range->f90_range_type == BOTH_BOUND_DEFAULT) + range->high_bound = TYPE_HIGH_BOUND (range_type); + + if (range->low_bound < TYPE_LOW_BOUND (range_type) + || (!TYPE_HIGH_BOUND_UNDEFINED (range_type) + && range->high_bound > TYPE_HIGH_BOUND (range_type))) + error (_("slice out of range")); + + byte_offset = ((range->low_bound - TYPE_LOW_BOUND (range_type)) + * TYPE_ARRAY_BYTE_STRIDE_VALUE (type)); + TYPE_LOW_BOUND (range_type) = range->low_bound; + TYPE_HIGH_BOUND (range_type) = range->high_bound; + if (range->f90_range_type == LOW_BOUND_DEFAULT + || range->f90_range_type == NONE_BOUND_DEFAULT) + TYPE_HIGH_BOUND_UNDEFINED (range_type) = 0; + + typep = &TYPE_TARGET_TYPE (type); + value_byte_offset += byte_offset; + type = TYPE_TARGET_TYPE (type); + } + break; + + case SUBSCRIPT_NUMBER: + { + CORE_ADDR byte_offset; + + if (index->number < TYPE_LOW_BOUND (range_type) + || (!TYPE_HIGH_BOUND_UNDEFINED (range_type) + && index->number > TYPE_HIGH_BOUND (range_type))) + error (_("no such vector element")); + + byte_offset = ((index->number - TYPE_LOW_BOUND (range_type)) + * TYPE_ARRAY_BYTE_STRIDE_VALUE (type)); + + type = TYPE_TARGET_TYPE (type); + *typep = type; + value_byte_offset += byte_offset; + } + break; + } + } + + type_last_target = type; + type_array = alloca (sizeof (*type_array) * nargs); + i = 0; + for (type = new_array_type; type != type_last_target; + type = TYPE_TARGET_TYPE (type)) + type_array[i++] = type; + while (i > 0) + { + struct type *type = type_array[--i]; + + /* Force TYPE_LENGTH (type) recalculation. */ + TYPE_TARGET_STUB (type) = 1; + check_typedef (type); + } + + saved_array = array; + array = allocate_value_lazy (new_array_type); + VALUE_LVAL (array) = VALUE_LVAL (saved_array); + if (VALUE_LVAL (saved_array) == lval_internalvar_component) + VALUE_LVAL (array) = lval_internalvar; else - high_bound = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + VALUE_LVAL (array) = VALUE_LVAL (saved_array); + VALUE_FRAME_ID (array) = VALUE_FRAME_ID (saved_array); + if (VALUE_LVAL (array) != lval_internalvar) + set_value_address (array, value_byte_address + value_byte_offset); + + if (!value_lazy (saved_array)) + { + allocate_value_contents (array); + set_value_lazy (array, 0); - return value_slice (array, low_bound, high_bound - low_bound + 1); + memcpy (value_contents_writeable (array), + value_contents (saved_array) + value_byte_offset, + TYPE_LENGTH (new_array_type)); + } + + do_cleanups (old_chain); + return array; } @@ -818,6 +1009,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; @@ -1892,6 +2084,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); @@ -1912,23 +2106,13 @@ evaluate_subexp_standard (struct type *expect_type, code = TYPE_CODE (type); } } + do_cleanups (old_chain); switch (code) { case TYPE_CODE_ARRAY: - if (exp->elts[*pos].opcode == OP_F90_RANGE) - return value_f90_subarray (arg1, exp, pos, noside); - else - goto multi_f77_subscript; - case TYPE_CODE_STRING: - if (exp->elts[*pos].opcode == OP_F90_RANGE) - return value_f90_subarray (arg1, exp, pos, noside); - else - { - arg2 = evaluate_subexp_with_coercion (exp, pos, noside); - return value_subscript (arg1, value_as_long (arg2)); - } + return value_f90_subarray (arg1, exp, pos, nargs, noside); case TYPE_CODE_PTR: case TYPE_CODE_FUNC: @@ -2361,49 +2545,6 @@ evaluate_subexp_standard (struct type *expect_type, } return (arg1); - multi_f77_subscript: - { - LONGEST subscript_array[MAX_FORTRAN_DIMS]; - int ndimensions = 1, i; - struct value *array = arg1; - - if (nargs > MAX_FORTRAN_DIMS) - error (_("Too many subscripts for F77 (%d Max)"), MAX_FORTRAN_DIMS); - - ndimensions = calc_f77_array_dims (type); - - if (nargs != ndimensions) - error (_("Wrong number of subscripts")); - - gdb_assert (nargs > 0); - - /* Now that we know we have a legal array subscript expression - let us actually find out where this element exists in the array. */ - - /* Take array indices left to right. */ - for (i = 0; i < nargs; i++) - { - /* Evaluate each subscript; it must be a legal integer in F77. */ - arg2 = evaluate_subexp_with_coercion (exp, pos, noside); - - /* Fill in the subscript array. */ - - subscript_array[i] = value_as_long (arg2); - } - - /* Internal type of array is arranged right to left. */ - for (i = nargs; i > 0; i--) - { - struct type *array_type = check_typedef (value_type (array)); - LONGEST index = subscript_array[i - 1]; - - lower = f77_get_lowerbound (array_type); - array = value_subscripted_rvalue (array, index, lower); - } - - return array; - } - case BINOP_LOGICAL_AND: arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); if (noside == EVAL_SKIP) @@ -2635,15 +2776,23 @@ 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)); @@ -2652,12 +2801,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.")); } @@ -2667,9 +2822,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. */ @@ -3011,7 +3171,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; @@ -3022,13 +3182,18 @@ 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 && !TYPE_VECTOR (type) && 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); } @@ -3080,9 +3245,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); @@ -3113,18 +3282,25 @@ parse_and_eval_type (char *p, int length) int calc_f77_array_dims (struct type *array_type) { - int ndimen = 1; - struct type *tmp_type; + switch (TYPE_CODE (array_type)) + { + case TYPE_CODE_STRING: + return 1; - if ((TYPE_CODE (array_type) != TYPE_CODE_ARRAY)) - error (_("Can't get dimensions for a non-array type")); + case TYPE_CODE_ARRAY: + { + int ndimen = 1; - tmp_type = array_type; + while ((array_type = TYPE_TARGET_TYPE (array_type))) + { + if (TYPE_CODE (array_type) == TYPE_CODE_ARRAY) + ++ndimen; + } + return ndimen; + } - while ((tmp_type = TYPE_TARGET_TYPE (tmp_type))) - { - if (TYPE_CODE (tmp_type) == TYPE_CODE_ARRAY) - ++ndimen; + default: + error (_("Can't get dimensions for a non-array/non-string type")); } - return ndimen; + } diff --git a/gdb/exec.c b/gdb/exec.c index 6ba1986..e076609 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -33,6 +33,7 @@ #include "arch-utils.h" #include "gdbthread.h" #include "progspace.h" +#include "gdb_bfd.h" #include <fcntl.h> #include "readline/readline.h" @@ -98,10 +99,8 @@ exec_close (void) if (exec_bfd) { bfd *abfd = exec_bfd; - char *name = bfd_get_filename (abfd); - gdb_bfd_close_or_warn (abfd); - xfree (name); + gdb_bfd_unref (abfd); /* Removing target sections may close the exec_ops target. Clear exec_bfd before doing so to prevent recursion. */ @@ -128,17 +127,13 @@ exec_close_1 (int quitting) vp = nxt; nxt = vp->nxt; - /* if there is an objfile associated with this bfd, - free_objfile() will do proper cleanup of objfile *and* bfd. */ - if (vp->objfile) { free_objfile (vp->objfile); need_symtab_cleanup = 1; } - else if (vp->bfd != exec_bfd) - /* FIXME-leak: We should be freeing vp->name too, I think. */ - gdb_bfd_close_or_warn (vp->bfd); + + gdb_bfd_unref (vp->bfd); xfree (vp); } @@ -230,11 +225,14 @@ exec_file_attach (char *filename, int from_tty) &scratch_pathname); } #endif + + cleanups = make_cleanup (xfree, scratch_pathname); + if (scratch_chan < 0) perror_with_name (filename); - exec_bfd = bfd_fopen (scratch_pathname, gnutarget, - write_files ? FOPEN_RUB : FOPEN_RB, - scratch_chan); + exec_bfd = gdb_bfd_fopen (scratch_pathname, gnutarget, + write_files ? FOPEN_RUB : FOPEN_RB, + scratch_chan); if (!exec_bfd) { @@ -242,13 +240,6 @@ exec_file_attach (char *filename, int from_tty) scratch_pathname, bfd_errmsg (bfd_get_error ())); } - /* At this point, scratch_pathname and exec_bfd->name both point to the - same malloc'd string. However exec_close() will attempt to free it - via the exec_bfd->name pointer, so we need to make another copy and - leave exec_bfd as the new owner of the original copy. */ - scratch_pathname = xstrdup (scratch_pathname); - cleanups = make_cleanup (xfree, scratch_pathname); - if (!bfd_check_format_matches (exec_bfd, bfd_object, &matching)) { /* Make sure to close exec_bfd, or else "run" might try to use @@ -554,6 +545,7 @@ map_vmap (bfd *abfd, bfd *arch) memset ((char *) vp, '\0', sizeof (*vp)); vp->nxt = 0; vp->bfd = abfd; + gdb_bfd_ref (abfd); vp->name = bfd_get_filename (arch ? arch : abfd); vp->member = arch ? bfd_get_filename (abfd) : ""; diff --git a/gdb/f-exp.y b/gdb/f-exp.y index 33c7418..4db1bfa 100644 --- a/gdb/f-exp.y +++ b/gdb/f-exp.y @@ -298,7 +298,9 @@ arglist : subrange { arglist_len = 1; } ; -arglist : arglist ',' exp %prec ABOVE_COMMA +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + | arglist ',' subrange %prec ABOVE_COMMA { arglist_len++; } ; diff --git a/gdb/f-lang.h b/gdb/f-lang.h index 4aae3c5..51a4e1e 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 void 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 a95ef84..830917d 100644 --- a/gdb/f-typeprint.c +++ b/gdb/f-typeprint.c @@ -31,7 +31,7 @@ #include "gdbcore.h" #include "target.h" #include "f-lang.h" - +#include "dwarf2loc.h" #include "gdb_string.h" #include <errno.h> @@ -48,6 +48,34 @@ void f_type_print_varspec_prefix (struct type *, struct ui_file *, void f_type_print_base (struct type *, struct ui_file *, int, int); +const char * +f_object_address_data_valid_print_to_stream (struct type *type, + struct ui_file *stream) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + /* Assuming the content printed to STREAM should not be localized. */ + fprintf_filtered (stream, "<%s>", msg); + } + + return msg; +} + +void +f_object_address_data_valid_or_error (struct type *type) +{ + const char *msg; + + msg = object_address_data_not_valid (type); + if (msg != NULL) + { + error (_("Cannot access it because the %s."), _(msg)); + } +} + /* LEVEL is the depth to indent lines by. */ void @@ -57,6 +85,9 @@ f_print_type (struct type *type, 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') @@ -164,6 +195,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 4359f6f..8ff834b 100644 --- a/gdb/f-valprint.c +++ b/gdb/f-valprint.c @@ -54,15 +54,17 @@ int f77_array_offset_tbl[MAX_FORTRAN_DIMS + 1][2]; /* The following macro gives us the size of the nth dimension, Where n is 1 based. */ -#define F77_DIM_SIZE(n) (f77_array_offset_tbl[n][1]) +#define F77_DIM_COUNT(n) (f77_array_offset_tbl[n][1]) -/* The following gives us the offset for row n where n is 1-based. */ +/* The following gives us the element size for row n where n is 1-based. */ -#define F77_DIM_OFFSET(n) (f77_array_offset_tbl[n][0]) +#define F77_DIM_BYTE_STRIDE(n) (f77_array_offset_tbl[n][0]) int f77_get_lowerbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_LOWER_BOUND_IS_UNDEFINED (type)) error (_("Lower bound may not be '*' in F77")); @@ -72,14 +74,17 @@ f77_get_lowerbound (struct type *type) int f77_get_upperbound (struct type *type) { + f_object_address_data_valid_or_error (type); + if (TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type)) { - /* We have an assumed size array on our hands. Assume that - upper_bound == lower_bound so that we show at least 1 element. - If the user wants to see more elements, let him manually ask for 'em - and we'll subscript the array and show him. */ + /* We have an assumed size array on our hands. As type_length_get + already assumes a length zero of arrays with underfined bounds VALADDR + passed to the Fortran functions does not contained the real inferior + memory content. User should request printing of specific array + elements instead. */ - return f77_get_lowerbound (type); + return f77_get_lowerbound (type) - 1; } return TYPE_ARRAY_UPPER_BOUND_VALUE (type); @@ -135,24 +140,29 @@ f77_create_arrayprint_offset_tbl (struct type *type, struct ui_file *stream) upper = f77_get_upperbound (tmp_type); lower = f77_get_lowerbound (tmp_type); - F77_DIM_SIZE (ndimen) = upper - lower + 1; + F77_DIM_COUNT (ndimen) = upper - lower + 1; + + F77_DIM_BYTE_STRIDE (ndimen) = + TYPE_ARRAY_BYTE_STRIDE_VALUE (tmp_type); tmp_type = TYPE_TARGET_TYPE (tmp_type); ndimen++; } - /* Now we multiply eltlen by all the offsets, so that later we + /* Now we multiply eltlen by all the BYTE_STRIDEs, so that later we can print out array elements correctly. Up till now we - know an offset to apply to get the item but we also + know an eltlen to apply to get the item but we also have to know how much to add to get to the next item. */ ndimen--; eltlen = TYPE_LENGTH (tmp_type); - F77_DIM_OFFSET (ndimen) = eltlen; + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; while (--ndimen > 0) { - eltlen *= F77_DIM_SIZE (ndimen + 1); - F77_DIM_OFFSET (ndimen) = eltlen; + eltlen *= F77_DIM_COUNT (ndimen + 1); + if (F77_DIM_BYTE_STRIDE (ndimen) == 0) + F77_DIM_BYTE_STRIDE (ndimen) = eltlen; } } @@ -174,37 +184,35 @@ 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, - embedded_offset + i * F77_DIM_OFFSET (nss), + embedded_offset + i * F77_DIM_BYTE_STRIDE (nss), address, 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, - embedded_offset + i * F77_DIM_OFFSET (ndimensions), + embedded_offset + i * F77_DIM_BYTE_STRIDE (ndimensions), address, 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, "..."); } } @@ -270,6 +278,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; + CHECK_TYPEDEF (type); switch (TYPE_CODE (type)) { diff --git a/gdb/findvar.c b/gdb/findvar.c index 66bcebe..e59e5f2 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -35,6 +35,7 @@ #include "block.h" #include "objfiles.h" #include "language.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 @@ -438,7 +439,10 @@ minsym_lookup_iterator_cb (struct objfile *objfile, void *cb_data) } /* A default implementation for the "la_read_var_value" hook in - the language vector which should work in most situations. */ + the language vector which should work in most situations. + 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 * default_read_var_value (struct symbol *var, struct frame_info *frame) @@ -446,16 +450,6 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) struct value *v; struct type *type = SYMBOL_TYPE (var); CORE_ADDR addr; - int len; - - /* Call check_typedef on our type to make sure that, if TYPE is - a TYPE_CODE_TYPEDEF, its length is set to the length of the target type - instead of zero. However, we do not replace the typedef type by the - target type, because we want to keep the typedef in order to be able to - set the returned value type description correctly. */ - check_typedef (type); - - len = TYPE_LENGTH (type); if (symbol_read_needs_frame (var)) gdb_assert (frame); @@ -465,7 +459,7 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) case LOC_CONST: /* Put the constant back in target format. */ v = allocate_value (type); - store_signed_integer (value_contents_raw (v), len, + store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type), gdbarch_byte_order (get_type_arch (type)), (LONGEST) SYMBOL_VALUE (var)); VALUE_LVAL (v) = not_lval; @@ -490,12 +484,12 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) case LOC_CONST_BYTES: v = allocate_value (type); - memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), len); + memcpy (value_contents_raw (v), SYMBOL_VALUE_BYTES (var), + TYPE_LENGTH (type)); VALUE_LVAL (v) = not_lval; return v; case LOC_STATIC: - v = allocate_value_lazy (type); if (overlay_debugging) addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (var), SYMBOL_OBJ_SECTION (var)); @@ -509,7 +503,6 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) error (_("Unknown argument list address for `%s'."), SYMBOL_PRINT_NAME (var)); addr += SYMBOL_VALUE (var); - v = allocate_value_lazy (type); break; case LOC_REF_ARG: @@ -524,14 +517,12 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) argref += SYMBOL_VALUE (var); ref = value_at (lookup_pointer_type (type), argref); addr = value_as_address (ref); - v = allocate_value_lazy (type); break; } case LOC_LOCAL: addr = get_frame_locals_address (frame); addr += SYMBOL_VALUE (var); - v = allocate_value_lazy (type); break; case LOC_TYPEDEF: @@ -540,7 +531,6 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) break; case LOC_BLOCK: - v = allocate_value_lazy (type); if (overlay_debugging) addr = symbol_overlayed_address (BLOCK_START (SYMBOL_BLOCK_VALUE (var)), SYMBOL_OBJ_SECTION (var)); @@ -566,7 +556,6 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) SYMBOL_PRINT_NAME (var)); addr = value_as_address (regval); - v = allocate_value_lazy (type); } else { @@ -615,7 +604,6 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) if (obj_section && (obj_section->the_bfd_section->flags & SEC_THREAD_LOCAL) != 0) addr = target_translate_tls_address (obj_section->objfile, addr); - v = allocate_value_lazy (type); } break; @@ -628,6 +616,10 @@ default_read_var_value (struct symbol *var, struct frame_info *frame) break; } + /* ADDR is set here for ALLOCATE_VALUE's CHECK_TYPEDEF for + DW_OP_PUSH_OBJECT_ADDRESS. */ + object_address_set (addr); + v = allocate_value_lazy (type); VALUE_LVAL (v) = lval_memory; set_value_address (v, addr); return v; @@ -723,10 +715,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)) { int optim, unavail, ok; @@ -741,7 +734,7 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame) VALUE_LVAL (v) = lval_register; VALUE_FRAME_ID (v) = get_frame_id (frame); VALUE_REGNUM (v) = regnum; - ok = gdbarch_register_to_value (gdbarch, frame, regnum, type1, + ok = gdbarch_register_to_value (gdbarch, frame, regnum, type, value_contents_raw (v), &optim, &unavail); diff --git a/gdb/gcore.c b/gdb/gcore.c index aedda41..a45e787 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -33,6 +33,7 @@ #include <fcntl.h> #include "regcache.h" #include "regset.h" +#include "gdb_bfd.h" /* The largest amount of memory to read from the target at once. We must throttle it to limit the amount of memory used by GDB during @@ -50,7 +51,7 @@ static int gcore_memory_sections (bfd *); bfd * create_gcore_bfd (char *filename) { - bfd *obfd = bfd_openw (filename, default_gcore_target ()); + bfd *obfd = gdb_bfd_openw (filename, default_gcore_target ()); if (!obfd) error (_("Failed to open '%s' for output."), filename); @@ -110,7 +111,7 @@ do_bfd_delete_cleanup (void *arg) bfd *obfd = arg; const char *filename = obfd->filename; - bfd_close (arg); + gdb_bfd_unref (arg); unlink (filename); } @@ -154,7 +155,7 @@ gcore_command (char *args, int from_tty) fprintf_filtered (gdb_stdout, "Saved corefile %s\n", corefilename); discard_cleanups (old_chain); - bfd_close (obfd); + gdb_bfd_unref (obfd); } static unsigned long diff --git a/gdb/gdb-gdb.gdb.in b/gdb/gdb-gdb.gdb.in index ffb7f53..a2e7e94 100644 --- a/gdb/gdb-gdb.gdb.in +++ b/gdb/gdb-gdb.gdb.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/gdb_bfd.c b/gdb/gdb_bfd.c new file mode 100644 index 0000000..fac8776 --- /dev/null +++ b/gdb/gdb_bfd.c @@ -0,0 +1,670 @@ +/* Definitions for BFD wrappers used by GDB. + + Copyright (C) 2011, 2012 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdb_bfd.h" +#include "gdb_assert.h" +#include "gdb_string.h" +#include "ui-out.h" +#include "gdbcmd.h" +#include "hashtab.h" +#ifdef HAVE_ZLIB_H +#include <zlib.h> +#endif +#ifdef HAVE_MMAP +#include <sys/mman.h> +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif +#endif + +/* An object of this type is stored in the section's user data when + mapping a section. */ + +struct gdb_bfd_section_data +{ + /* Size of the data. */ + bfd_size_type size; + /* If the data was mmapped, this is the length of the map. */ + bfd_size_type map_len; + /* The data. If NULL, the section data has not been read. */ + void *data; + /* If the data was mmapped, this is the map address. */ + void *map_addr; +}; + +/* A hash table holding every BFD that gdb knows about. This is not + to be confused with 'gdb_bfd_cache', which is used for sharing + BFDs; in contrast, this hash is used just to implement + "maint info bfd". */ + +static htab_t all_bfds; + +/* See gdb_bfd.h. */ + +void +gdb_bfd_stash_filename (struct bfd *abfd) +{ + char *name = bfd_get_filename (abfd); + char *data; + + data = bfd_alloc (abfd, strlen (name) + 1); + strcpy (data, name); + + /* Unwarranted chumminess with BFD. */ + abfd->filename = data; +} + +/* An object of this type is stored in each BFD's user data. */ + +struct gdb_bfd_data +{ + /* The reference count. */ + int refc; + + /* The mtime of the BFD at the point the cache entry was made. */ + time_t mtime; +}; + +/* A hash table storing all the BFDs maintained in the cache. */ + +static htab_t gdb_bfd_cache; + +/* The type of an object being looked up in gdb_bfd_cache. We use + htab's capability of storing one kind of object (BFD in this case) + and using a different sort of object for searching. */ + +struct gdb_bfd_cache_search +{ + /* The filename. */ + const char *filename; + /* The mtime. */ + time_t mtime; +}; + +/* A hash function for BFDs. */ + +static hashval_t +hash_bfd (const void *b) +{ + const bfd *abfd = b; + + /* It is simplest to just hash the filename. */ + return htab_hash_string (bfd_get_filename (abfd)); +} + +/* An equality function for BFDs. Note that this expects the caller + to search using struct gdb_bfd_cache_search only, not BFDs. */ + +static int +eq_bfd (const void *a, const void *b) +{ + const bfd *abfd = a; + const struct gdb_bfd_cache_search *s = b; + struct gdb_bfd_data *gdata = bfd_usrdata (abfd); + + return (gdata->mtime == s->mtime + && strcmp (bfd_get_filename (abfd), s->filename) == 0); +} + +/* See gdb_bfd.h. */ + +struct bfd * +gdb_bfd_open (const char *name, const char *target, int fd) +{ + hashval_t hash; + void **slot; + bfd *abfd; + struct gdb_bfd_cache_search search; + struct stat st; + + if (gdb_bfd_cache == NULL) + gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL, + xcalloc, xfree); + + if (fd == -1) + { + fd = open (name, O_RDONLY | O_BINARY); + if (fd == -1) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + } + + search.filename = name; + if (fstat (fd, &st) < 0) + { + /* Weird situation here. */ + search.mtime = 0; + } + else + search.mtime = st.st_mtime; + + /* Note that this must compute the same result as hash_bfd. */ + hash = htab_hash_string (name); + /* Note that we cannot use htab_find_slot_with_hash here, because + opening the BFD may fail; and this would violate hashtab + invariants. */ + abfd = htab_find_with_hash (gdb_bfd_cache, &search, hash); + if (abfd != NULL) + { + close (fd); + gdb_bfd_ref (abfd); + return abfd; + } + + abfd = bfd_fopen (name, target, FOPEN_RB, fd); + if (abfd == NULL) + return NULL; + + slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT); + gdb_assert (!*slot); + *slot = abfd; + + gdb_bfd_stash_filename (abfd); + gdb_bfd_ref (abfd); + return abfd; +} + +/* A helper function that releases any section data attached to the + BFD. */ + +static void +free_one_bfd_section (bfd *abfd, asection *sectp, void *ignore) +{ + struct gdb_bfd_section_data *sect = bfd_get_section_userdata (abfd, sectp); + + if (sect != NULL && sect->data != NULL) + { +#ifdef HAVE_MMAP + if (sect->map_addr != NULL) + { + int res; + + res = munmap (sect->map_addr, sect->map_len); + gdb_assert (res == 0); + } + else +#endif + xfree (sect->data); + } +} + +/* Close ABFD, and warn if that fails. */ + +static int +gdb_bfd_close_or_warn (struct bfd *abfd) +{ + int ret; + char *name = bfd_get_filename (abfd); + + bfd_map_over_sections (abfd, free_one_bfd_section, NULL); + + ret = bfd_close (abfd); + + if (!ret) + warning (_("cannot close \"%s\": %s"), + name, bfd_errmsg (bfd_get_error ())); + + return ret; +} + +/* See gdb_bfd.h. */ + +void +gdb_bfd_ref (struct bfd *abfd) +{ + struct gdb_bfd_data *gdata; + void **slot; + + if (abfd == NULL) + return; + + gdata = bfd_usrdata (abfd); + + if (gdata != NULL) + { + gdata->refc += 1; + return; + } + + gdata = bfd_zalloc (abfd, sizeof (struct gdb_bfd_data)); + gdata->refc = 1; + gdata->mtime = bfd_get_mtime (abfd); + bfd_usrdata (abfd) = gdata; + + /* This is the first we've seen it, so add it to the hash table. */ + slot = htab_find_slot (all_bfds, abfd, INSERT); + gdb_assert (slot && !*slot); + *slot = abfd; +} + +/* See gdb_bfd.h. */ + +void +gdb_bfd_unref (struct bfd *abfd) +{ + struct gdb_bfd_data *gdata; + struct gdb_bfd_cache_search search; + void **slot; + + if (abfd == NULL) + return; + + gdata = bfd_usrdata (abfd); + gdb_assert (gdata->refc >= 1); + + gdata->refc -= 1; + if (gdata->refc > 0) + return; + + search.filename = bfd_get_filename (abfd); + + if (gdb_bfd_cache && search.filename) + { + hashval_t hash = htab_hash_string (search.filename); + void **slot; + + search.mtime = gdata->mtime; + slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, + NO_INSERT); + + if (slot && *slot) + htab_clear_slot (gdb_bfd_cache, slot); + } + + bfd_usrdata (abfd) = NULL; /* Paranoia. */ + + htab_remove_elt (all_bfds, abfd); + + gdb_bfd_close_or_warn (abfd); +} + +/* A helper function that returns the section data descriptor + associated with SECTION. If no such descriptor exists, a new one + is allocated and cleared. */ + +static struct gdb_bfd_section_data * +get_section_descriptor (asection *section) +{ + struct gdb_bfd_section_data *result; + + result = bfd_get_section_userdata (section->owner, section); + + if (result == NULL) + { + result = bfd_zalloc (section->owner, sizeof (*result)); + bfd_set_section_userdata (section->owner, section, result); + } + + return result; +} + +/* Decompress a section that was compressed using zlib. Store the + decompressed buffer, and its size, in DESCRIPTOR. */ + +static void +zlib_decompress_section (asection *sectp, + struct gdb_bfd_section_data *descriptor) +{ + bfd *abfd = sectp->owner; +#ifndef HAVE_ZLIB_H + error (_("Support for zlib-compressed data (from '%s', section '%s') " + "is disabled in this copy of GDB"), + bfd_get_filename (abfd), + bfd_get_section_name (sectp)); +#else + bfd_size_type compressed_size = bfd_get_section_size (sectp); + gdb_byte *compressed_buffer = xmalloc (compressed_size); + struct cleanup *cleanup = make_cleanup (xfree, compressed_buffer); + struct cleanup *inner_cleanup; + bfd_size_type uncompressed_size; + gdb_byte *uncompressed_buffer; + z_stream strm; + int rc; + int header_size = 12; + struct dwarf2_per_bfd_section *section_data; + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (compressed_buffer, + compressed_size, abfd) != compressed_size) + error (_("can't read data from '%s', section '%s'"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp)); + + /* Read the zlib header. In this case, it should be "ZLIB" followed + by the uncompressed section size, 8 bytes in big-endian order. */ + if (compressed_size < header_size + || strncmp (compressed_buffer, "ZLIB", 4) != 0) + error (_("corrupt ZLIB header from '%s', section '%s'"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp)); + uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8; + uncompressed_size += compressed_buffer[11]; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + strm.avail_in = compressed_size - header_size; + strm.next_in = (Bytef*) compressed_buffer + header_size; + strm.avail_out = uncompressed_size; + uncompressed_buffer = xmalloc (uncompressed_size); + inner_cleanup = make_cleanup (xfree, uncompressed_buffer); + rc = inflateInit (&strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + error (_("setting up uncompression in '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + strm.next_out = ((Bytef*) uncompressed_buffer + + (uncompressed_size - strm.avail_out)); + rc = inflate (&strm, Z_FINISH); + if (rc != Z_STREAM_END) + error (_("zlib error uncompressing from '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + rc = inflateReset (&strm); + } + rc = inflateEnd (&strm); + if (rc != Z_OK + || strm.avail_out != 0) + error (_("concluding uncompression in '%s', section '%s': %d"), + bfd_get_filename (abfd), + bfd_get_section_name (abfd, sectp), + rc); + + discard_cleanups (inner_cleanup); + do_cleanups (cleanup); + + /* Attach the data to the BFD section. */ + descriptor->data = uncompressed_buffer; + descriptor->size = uncompressed_size; +#endif +} + +/* See gdb_bfd.h. */ + +const gdb_byte * +gdb_bfd_map_section (asection *sectp, bfd_size_type *size) +{ + bfd *abfd; + gdb_byte *buf, *retbuf; + unsigned char header[4]; + struct gdb_bfd_section_data *descriptor; + + gdb_assert ((sectp->flags & SEC_RELOC) == 0); + gdb_assert (size != NULL); + + abfd = sectp->owner; + + descriptor = get_section_descriptor (sectp); + + /* If the data was already read for this BFD, just reuse it. */ + if (descriptor->data != NULL) + goto done; + + /* Check if the file has a 4-byte header indicating compression. */ + if (bfd_get_section_size (sectp) > sizeof (header) + && bfd_seek (abfd, sectp->filepos, SEEK_SET) == 0 + && bfd_bread (header, sizeof (header), abfd) == sizeof (header)) + { + /* Upon decompression, update the buffer and its size. */ + if (strncmp (header, "ZLIB", sizeof (header)) == 0) + { + zlib_decompress_section (sectp, descriptor); + goto done; + } + } + +#ifdef HAVE_MMAP + { + /* The page size, used when mmapping. */ + static int pagesize; + + if (pagesize == 0) + pagesize = getpagesize (); + + /* Only try to mmap sections which are large enough: we don't want + to waste space due to fragmentation. */ + + if (bfd_get_section_size (sectp) > 4 * pagesize) + { + descriptor->size = bfd_get_section_size (sectp); + descriptor->data = bfd_mmap (abfd, 0, descriptor->size, PROT_READ, + MAP_PRIVATE, sectp->filepos, + &descriptor->map_addr, + &descriptor->map_len); + + if ((caddr_t)descriptor->data != MAP_FAILED) + { +#if HAVE_POSIX_MADVISE + posix_madvise (descriptor->map_addr, descriptor->map_len, + POSIX_MADV_WILLNEED); +#endif + goto done; + } + + /* On failure, clear out the section data and try again. */ + memset (descriptor, 0, sizeof (*descriptor)); + } + } +#endif /* HAVE_MMAP */ + + /* If we get here, we are a normal, not-compressed section. */ + + descriptor->size = bfd_get_section_size (sectp); + descriptor->data = xmalloc (descriptor->size); + + if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 + || bfd_bread (descriptor->data, bfd_get_section_size (sectp), + abfd) != bfd_get_section_size (sectp)) + { + xfree (descriptor->data); + descriptor->data = NULL; + error (_("Can't read data for section '%s'"), + bfd_get_filename (abfd)); + } + + done: + gdb_assert (descriptor->data != NULL); + *size = descriptor->size; + return descriptor->data; +} + + + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_fopen (const char *filename, const char *target, const char *mode, + int fd) +{ + bfd *result = bfd_fopen (filename, target, mode, fd); + + if (result) + { + gdb_bfd_stash_filename (result); + gdb_bfd_ref (result); + } + + return result; +} + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_openr (const char *filename, const char *target) +{ + bfd *result = bfd_openr (filename, target); + + if (result) + { + gdb_bfd_stash_filename (result); + gdb_bfd_ref (result); + } + + return result; +} + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_openw (const char *filename, const char *target) +{ + bfd *result = bfd_openw (filename, target); + + if (result) + { + gdb_bfd_stash_filename (result); + gdb_bfd_ref (result); + } + + return result; +} + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_openr_iovec (const char *filename, const char *target, + void *(*open_func) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread_func) (struct bfd *nbfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close_func) (struct bfd *nbfd, + void *stream), + int (*stat_func) (struct bfd *abfd, + void *stream, + struct stat *sb)) +{ + bfd *result = bfd_openr_iovec (filename, target, + open_func, open_closure, + pread_func, close_func, stat_func); + + if (result) + { + gdb_bfd_ref (result); + gdb_bfd_stash_filename (result); + } + + return result; +} + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_openr_next_archived_file (bfd *archive, bfd *previous) +{ + bfd *result = bfd_openr_next_archived_file (archive, previous); + + if (result) + { + gdb_bfd_ref (result); + /* No need to stash the filename here. */ + } + + return result; +} + +/* See gdb_bfd.h. */ + +bfd * +gdb_bfd_fdopenr (const char *filename, const char *target, int fd) +{ + bfd *result = bfd_fdopenr (filename, target, fd); + + if (result) + { + gdb_bfd_ref (result); + gdb_bfd_stash_filename (result); + } + + return result; +} + + + +/* A callback for htab_traverse that prints a single BFD. */ + +static int +print_one_bfd (void **slot, void *data) +{ + bfd *abfd = *slot; + struct gdb_bfd_data *gdata = bfd_usrdata (abfd); + struct ui_out *uiout = data; + struct cleanup *inner; + + inner = make_cleanup_ui_out_tuple_begin_end (uiout, NULL); + ui_out_field_int (uiout, "refcount", gdata->refc); + ui_out_field_string (uiout, "addr", host_address_to_string (abfd)); + ui_out_field_string (uiout, "filename", bfd_get_filename (abfd)); + ui_out_text (uiout, "\n"); + do_cleanups (inner); + + return 1; +} + +/* Implement the 'maint info bfd' command. */ + +static void +maintenance_info_bfds (char *arg, int from_tty) +{ + struct cleanup *cleanup; + struct ui_out *uiout = current_uiout; + + cleanup = make_cleanup_ui_out_table_begin_end (uiout, 3, -1, "bfds"); + ui_out_table_header (uiout, 10, ui_left, "refcount", "Refcount"); + ui_out_table_header (uiout, 18, ui_left, "addr", "Address"); + ui_out_table_header (uiout, 40, ui_left, "filename", "Filename"); + + ui_out_table_body (uiout); + htab_traverse (all_bfds, print_one_bfd, uiout); + + do_cleanups (cleanup); +} + +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_gdb_bfd; + +void +_initialize_gdb_bfd (void) +{ + all_bfds = htab_create_alloc (10, htab_hash_pointer, htab_eq_pointer, + NULL, xcalloc, xfree); + + add_cmd ("bfds", class_maintenance, maintenance_info_bfds, _("\ +List the BFDs that are currently open."), + &maintenanceinfolist); +} diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h new file mode 100644 index 0000000..f131ba7 --- /dev/null +++ b/gdb/gdb_bfd.h @@ -0,0 +1,106 @@ +/* Definitions for BFD wrappers used by GDB. + + Copyright (C) 2011, 2012 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef GDB_BFD_H +#define GDB_BFD_H + +/* Make a copy ABFD's filename using bfd_alloc, and reassign it to the + BFD. This ensures that the BFD's filename has the same lifetime as + the BFD itself. */ + +void gdb_bfd_stash_filename (struct bfd *abfd); + +/* Open a read-only (FOPEN_RB) BFD given arguments like bfd_fopen. + Returns NULL on error. On success, returns a new reference to the + BFD, which must be freed with gdb_bfd_unref. BFDs returned by this + call are shared among all callers opening the same file. If FD is + not -1, then after this call it is owned by BFD. */ + +struct bfd *gdb_bfd_open (const char *name, const char *target, int fd); + +/* Increment the reference count of ABFD. It is fine for ABFD to be + NULL; in this case the function does nothing. */ + +void gdb_bfd_ref (struct bfd *abfd); + +/* Decrement the reference count of ABFD. If this is the last + reference, ABFD will be freed. If ABFD is NULL, this function does + nothing. */ + +void gdb_bfd_unref (struct bfd *abfd); + +/* Try to read or map the contents of the section SECT. If + successful, the section data is returned and *SIZE is set to the + size of the section data; this may not be the same as the size + according to bfd_get_section_size if the section was compressed. + The returned section data is associated with the BFD and will be + destroyed when the BFD is destroyed. There is no other way to free + it; for temporary uses of section data, see + bfd_malloc_and_get_section. SECT may not have relocations. This + function will throw on error. */ + +const gdb_byte *gdb_bfd_map_section (asection *section, bfd_size_type *size); + + + +/* A wrapper for bfd_fopen that initializes the gdb-specific reference + count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_fopen (const char *, const char *, const char *, int); + +/* A wrapper for bfd_openr that initializes the gdb-specific reference + count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_openr (const char *, const char *); + +/* A wrapper for bfd_openw that initializes the gdb-specific reference + count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_openw (const char *, const char *); + +/* A wrapper for bfd_openr_iovec that initializes the gdb-specific + reference count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_openr_iovec (const char *filename, const char *target, + void *(*open_func) (struct bfd *nbfd, + void *open_closure), + void *open_closure, + file_ptr (*pread_func) (struct bfd *nbfd, + void *stream, + void *buf, + file_ptr nbytes, + file_ptr offset), + int (*close_func) (struct bfd *nbfd, + void *stream), + int (*stat_func) (struct bfd *abfd, + void *stream, + struct stat *sb)); + +/* A wrapper for bfd_openr_next_archived_file that initializes the + gdb-specific reference count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_openr_next_archived_file (bfd *archive, bfd *previous); + +/* A wrapper for bfd_fdopenr that initializes the gdb-specific + reference count and calls gdb_bfd_stash_filename. */ + +bfd *gdb_bfd_fdopenr (const char *filename, const char *target, int fd); + +#endif /* GDB_BFD_H */ diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 8142ab9..a2953cc 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -37,6 +37,9 @@ #include "gdb_assert.h" #include "hashtab.h" #include "exceptions.h" +#include "observer.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" /* Initialize BADNESS constants. */ @@ -141,7 +144,16 @@ static void print_bit_vector (B_TYPE *, int); 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); +static LONGEST type_length_get (struct type *type, struct type *target_type, + int full_span); +#if 0 +/* 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; +#endif /* Allocate a new OBJFILE-associated type structure and fill it with some defaults. Space for the type structure is allocated @@ -172,6 +184,43 @@ alloc_type (struct objfile *objfile) return type; } +#if 0 +/* 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; +} +#endif + +/* 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 0 + if (TYPE_DISCARDABLE (parent_type)) + set_type_as_discardable (new_type); +#endif + + 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. */ @@ -297,7 +346,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; } @@ -374,7 +423,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; } @@ -784,6 +833,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; @@ -927,26 +977,31 @@ 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_DYNAMIC (element_type)) + TYPE_LENGTH (result_type) = 0; + else + { + CHECK_TYPEDEF (element_type); + TYPE_LENGTH (result_type) = type_length_get (result_type, element_type, + 0); + } 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; } @@ -1468,6 +1523,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_ERROR_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; +} + /* Find the real type of TYPE. This function returns the real type, after removing all layers of typedefs, and completing opaque or stub types. Completion changes the TYPE argument, but stripping of @@ -1634,52 +1788,37 @@ check_typedef (struct type *type) } } - if (TYPE_TARGET_STUB (type)) + /* copy_type_recursive automatically makes the resulting type containing only + constant values expected by the callers of this function. */ + if (TYPE_DYNAMIC (type)) + { + htab_t copied_types; + + copied_types = create_copied_types_hash (NULL); + type = copy_type_recursive (type, copied_types); + htab_delete (copied_types); + + gdb_assert (TYPE_DYNAMIC (type) == 0); + /* Force TYPE_LENGTH (type) recalculation. */ + TYPE_DYNAMIC (type) = 1; + } + + 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)) { /* Nothing we can do. */ } 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) @@ -1687,6 +1826,7 @@ check_typedef (struct type *type) TYPE_LENGTH (type) = TYPE_LENGTH (target_type); TYPE_TARGET_STUB (type) = 0; } + TYPE_DYNAMIC (type) = 0; } type = make_qualified_type (type, instance_flags, NULL); @@ -3345,33 +3485,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; @@ -3386,9 +3535,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; @@ -3399,6 +3549,21 @@ copy_type_recursive (struct objfile *objfile, TYPE_OBJFILE_OWNED (new_type) = 0; TYPE_OWNER (new_type).gdbarch = get_type_arch (type); +#if 0 + /* 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); +#endif + + /* 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)) @@ -3407,12 +3572,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++) { @@ -3421,8 +3622,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)); @@ -3453,24 +3654,184 @@ 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); + if (TYPE_LOW_BOUND (new_type) >= 0) + TYPE_UNSIGNED (new_type) = 1; + } + 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; + if (TYPE_LOW_BOUND (new_type) >= 0) + TYPE_UNSIGNED (new_type) = 1; + } + 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); + + if (TYPE_CODE (new_type) == TYPE_CODE_ARRAY) + { + struct type *new_index_type = TYPE_INDEX_TYPE (new_type); + + if (TYPE_BYTE_STRIDE (new_index_type) == 0) + TYPE_BYTE_STRIDE (new_index_type) + = TYPE_LENGTH (TYPE_TARGET_TYPE (new_type)); + } + /* Maybe copy the type_specific bits. NOTE drow/2005-12-09: We do not copy the C++-specific bits like @@ -3487,6 +3848,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. @@ -3509,6 +3881,201 @@ copy_type (const struct type *type) return new_type; } +#if 0 +/* 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); +} +#endif /* Helper functions to initialize architecture-specific types. */ @@ -4042,6 +4609,13 @@ void _initialize_gdbtypes (void) { gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init); + +#if 0 + type_discardable_table = htab_create_alloc (20, type_discardable_hash, + type_discardable_equal, NULL, + xcalloc, xfree); +#endif + 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 17bfbc5..72e9cc5 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -228,6 +228,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 @@ -311,6 +316,50 @@ enum type_instance_flag_value #define TYPE_FLAG_ENUM(t) (TYPE_MAIN_TYPE (t)->flag_flag_enum) +#if 0 +/* 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) +#endif + +/* 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. */ @@ -421,6 +470,15 @@ struct main_type /* True if this type was declared with "class" rather than "struct". */ unsigned int flag_declared_class : 1; +#if 0 + unsigned int flag_discardable : 1; + unsigned int flag_discardable_age : 1; +#endif + 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; /* True if this is an enum type with disjoint values. This affects how the enum is printed. */ @@ -501,6 +559,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. @@ -583,13 +655,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 @@ -1054,9 +1147,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 @@ -1064,11 +1157,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) \ @@ -1085,7 +1183,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++ */ @@ -1531,6 +1636,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); @@ -1576,6 +1693,10 @@ extern int is_public_ancestor (struct type *, struct type *); extern int is_unique_ancestor (struct type *, struct value *); +#if 0 +extern void type_mark_used (struct type *type); +#endif + /* Overload resolution */ #define LENGTH_MATCH(bv) ((bv)->rank[0]) @@ -1651,10 +1772,13 @@ 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); +#if 0 +extern void free_all_types (void); +#endif + #endif /* GDBTYPES_H */ diff --git a/gdb/jit.c b/gdb/jit.c index 568d17b..cdd9f49 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -38,6 +38,7 @@ #include "gdb-dlfcn.h" #include "gdb_stat.h" #include "exceptions.h" +#include "gdb_bfd.h" static const char *jit_reader_dir = NULL; @@ -132,17 +133,16 @@ mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb) static struct bfd * bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size, char *target) { - const char *filename = xstrdup ("<in-memory>"); struct target_buffer *buffer = xmalloc (sizeof (struct target_buffer)); buffer->base = addr; buffer->size = size; - return bfd_openr_iovec (filename, target, - mem_bfd_iovec_open, - buffer, - mem_bfd_iovec_pread, - mem_bfd_iovec_close, - mem_bfd_iovec_stat); + return gdb_bfd_openr_iovec ("<in-memory>", target, + mem_bfd_iovec_open, + buffer, + mem_bfd_iovec_pread, + mem_bfd_iovec_close, + mem_bfd_iovec_stat); } /* One reader that has been loaded successfully, and can potentially be used to @@ -868,7 +868,7 @@ jit_bfd_try_read_symtab (struct jit_code_entry *code_entry, { printf_unfiltered (_("\ JITed symbol file is not an object file, ignoring it.\n")); - bfd_close (nbfd); + gdb_bfd_unref (nbfd); return; } @@ -896,7 +896,8 @@ JITed symbol file is not an object file, ignoring it.\n")); ++i; } - /* This call takes ownership of NBFD. It does not take ownership of SAI. */ + /* This call does not take ownership of SAI. */ + make_cleanup_bfd_unref (nbfd); objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED, NULL); do_cleanups (old_cleanups); diff --git a/gdb/m32r-rom.c b/gdb/m32r-rom.c index 76e4bf1..9a2f5aa 100644 --- a/gdb/m32r-rom.c +++ b/gdb/m32r-rom.c @@ -40,6 +40,7 @@ #include "inferior.h" #include <ctype.h> #include "regcache.h" +#include "gdb_bfd.h" /* * All this stuff just to get my host computer's IP address! @@ -124,13 +125,15 @@ m32r_load (char *filename, int from_tty) bfd *abfd; unsigned int data_count = 0; struct timeval start_time, end_time; + struct cleanup *cleanup; if (filename == NULL || filename[0] == 0) filename = get_exec_file (1); - abfd = bfd_openr (filename, 0); + abfd = gdb_bfd_openr (filename, 0); if (!abfd) error (_("Unable to open file %s."), filename); + cleanup = make_cleanup_bfd_unref (abfd); if (bfd_check_format (abfd, bfd_object) == 0) error (_("File is not an object file.")); gettimeofday (&start_time, NULL); @@ -188,6 +191,7 @@ m32r_load (char *filename, int from_tty) confused... */ clear_symtab_users (0); + do_cleanups (cleanup); } static void @@ -434,6 +438,7 @@ m32r_upload_command (char *args, int from_tty) char buf[1024]; struct hostent *hostent; struct in_addr inet_addr; + struct cleanup *cleanup; /* First check to see if there's an ethernet port! */ monitor_printf ("ust\r"); @@ -524,7 +529,8 @@ m32r_upload_command (char *args, int from_tty) printf_filtered (" -- Ethernet load complete.\n"); gettimeofday (&end_time, NULL); - abfd = bfd_openr (args, 0); + abfd = gdb_bfd_openr (args, 0); + cleanup = make_cleanup_bfd_unref (abfd); if (abfd != NULL) { /* Download is done -- print section statistics. */ if (bfd_check_format (abfd, bfd_object) == 0) @@ -565,6 +571,7 @@ m32r_upload_command (char *args, int from_tty) confused... */ clear_symtab_users (0); + do_cleanups (cleanup); } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/machoread.c b/gdb/machoread.c index 22530ab..0d7578a 100644 --- a/gdb/machoread.c +++ b/gdb/machoread.c @@ -454,6 +454,7 @@ macho_add_oso_symfile (oso_el *oso, bfd *abfd, asymbol **symp; struct bfd_hash_table table; int nbr_sections; + struct cleanup *cleanup; /* Per section flag to mark which section have been rebased. */ unsigned char *sections_rebased; @@ -466,14 +467,14 @@ macho_add_oso_symfile (oso_el *oso, bfd *abfd, { warning (_("`%s': can't read symbols: %s."), oso->name, bfd_errmsg (bfd_get_error ())); - bfd_close (abfd); + gdb_bfd_unref (abfd); return; } if (abfd->my_archive == NULL && oso->mtime != bfd_get_mtime (abfd)) { warning (_("`%s': file time stamp mismatch."), oso->name); - bfd_close (abfd); + gdb_bfd_unref (abfd); return; } @@ -482,7 +483,7 @@ macho_add_oso_symfile (oso_el *oso, bfd *abfd, oso->nbr_syms)) { warning (_("`%s': can't create hash table"), oso->name); - bfd_close (abfd); + gdb_bfd_unref (abfd); return; } @@ -629,18 +630,15 @@ macho_add_oso_symfile (oso_el *oso, bfd *abfd, bfd_hash_table_free (&table); - /* Make sure that the filename was malloc'ed. The current filename comes - either from an OSO symbol name or from an archive name. Memory for both - is not managed by gdb. */ - abfd->filename = xstrdup (abfd->filename); - /* We need to clear SYMFILE_MAINLINE to avoid interractive question from symfile.c:symbol_file_add_with_addrs_or_offsets. */ + cleanup = make_cleanup_bfd_unref (abfd); symbol_file_add_from_bfd (abfd, symfile_flags & ~(SYMFILE_MAINLINE | SYMFILE_VERBOSE), NULL, main_objfile->flags & (OBJF_REORDERED | OBJF_SHARED | OBJF_READNOW | OBJF_USERLOADED), main_objfile); + do_cleanups (cleanup); } /* Read symbols from the vector of oso files. */ @@ -651,6 +649,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) int ix; VEC (oso_el) *vec; oso_el *oso; + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); vec = oso_vector; oso_vector = NULL; @@ -677,6 +676,8 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) memcpy (archive_name, oso->name, pfx_len); archive_name[pfx_len] = '\0'; + make_cleanup (xfree, archive_name); + /* Compute number of oso for this archive. */ for (last_ix = ix; VEC_iterate (oso_el, vec, last_ix, oso2); last_ix++) @@ -686,7 +687,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) } /* Open the archive and check the format. */ - archive_bfd = bfd_openr (archive_name, gnutarget); + archive_bfd = gdb_bfd_openr (archive_name, gnutarget); if (archive_bfd == NULL) { warning (_("Could not open OSO archive file \"%s\""), @@ -698,17 +699,18 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) { warning (_("OSO archive file \"%s\" not an archive."), archive_name); - bfd_close (archive_bfd); + gdb_bfd_unref (archive_bfd); ix = last_ix; continue; } - member_bfd = bfd_openr_next_archived_file (archive_bfd, NULL); + + member_bfd = gdb_bfd_openr_next_archived_file (archive_bfd, NULL); if (member_bfd == NULL) { warning (_("Could not read archive members out of " "OSO archive \"%s\""), archive_name); - bfd_close (archive_bfd); + gdb_bfd_unref (archive_bfd); ix = last_ix; continue; } @@ -738,12 +740,12 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) } prev = member_bfd; - member_bfd = bfd_openr_next_archived_file - (archive_bfd, member_bfd); + member_bfd = gdb_bfd_openr_next_archived_file (archive_bfd, + member_bfd); /* Free previous member if not referenced by an oso. */ if (ix2 >= last_ix) - bfd_close (prev); + gdb_bfd_unref (prev); } for (ix2 = ix; ix2 < last_ix; ix2++) { @@ -759,7 +761,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) { bfd *abfd; - abfd = bfd_openr (oso->name, gnutarget); + abfd = gdb_bfd_openr (oso->name, gnutarget); if (!abfd) warning (_("`%s': can't open to read symbols: %s."), oso->name, bfd_errmsg (bfd_get_error ())); @@ -771,6 +773,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags) } VEC_free (oso_el, vec); + do_cleanups (cleanup); } /* DSYM (debug symbols) files contain the debug info of an executable. @@ -808,20 +811,17 @@ macho_check_dsym (struct objfile *objfile) warning (_("can't find UUID in %s"), objfile->name); return NULL; } - dsym_filename = xstrdup (dsym_filename); - dsym_bfd = bfd_openr (dsym_filename, gnutarget); + dsym_bfd = gdb_bfd_openr (dsym_filename, gnutarget); if (dsym_bfd == NULL) { warning (_("can't open dsym file %s"), dsym_filename); - xfree (dsym_filename); return NULL; } if (!bfd_check_format (dsym_bfd, bfd_object)) { - bfd_close (dsym_bfd); + gdb_bfd_unref (dsym_bfd); warning (_("bad dsym file format: %s"), bfd_errmsg (bfd_get_error ())); - xfree (dsym_filename); return NULL; } @@ -829,16 +829,14 @@ macho_check_dsym (struct objfile *objfile) BFD_MACH_O_LC_UUID, &dsym_uuid) == 0) { warning (_("can't find UUID in %s"), dsym_filename); - bfd_close (dsym_bfd); - xfree (dsym_filename); + gdb_bfd_unref (dsym_bfd); return NULL; } if (memcmp (dsym_uuid->command.uuid.uuid, main_uuid->command.uuid.uuid, sizeof (main_uuid->command.uuid.uuid))) { warning (_("dsym file UUID doesn't match the one in %s"), objfile->name); - bfd_close (dsym_bfd); - xfree (dsym_filename); + gdb_bfd_unref (dsym_bfd); return NULL; } return dsym_bfd; @@ -902,6 +900,7 @@ macho_symfile_read (struct objfile *objfile, int symfile_flags) int ix; oso_el *oso; struct bfd_section *asect, *dsect; + struct cleanup *cleanup; if (mach_o_debug_level > 0) printf_unfiltered (_("dsym file found\n")); @@ -922,7 +921,9 @@ macho_symfile_read (struct objfile *objfile, int symfile_flags) } /* Add the dsym file as a separate file. */ + cleanup = make_cleanup_bfd_unref (dsym_bfd); symbol_file_add_separate (dsym_bfd, symfile_flags, objfile); + do_cleanups (cleanup); /* Don't try to read dwarf2 from main file or shared libraries. */ return; diff --git a/gdb/main.c b/gdb/main.c index d075694..e4da3f1 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -37,6 +37,7 @@ #include "interps.h" #include "main.h" +#include "python/python.h" #include "source.h" #include "cli/cli-cmds.h" #include "python/python.h" @@ -283,6 +284,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; @@ -471,10 +474,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; @@ -492,6 +499,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; @@ -699,7 +709,31 @@ captured_main (void *data) /* 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 @@ -979,7 +1013,8 @@ captured_main (void *data) /* Read in the old history after all the command files have been read. */ - init_history (); + if (!python_script) + init_history (); if (batch_flag) { @@ -990,13 +1025,25 @@ captured_main (void *data) /* 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. */ } @@ -1028,7 +1075,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 (_("\ @@ -1068,7 +1120,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/objfiles.c b/gdb/objfiles.c index f5e5c75..411618f 100644 --- a/gdb/objfiles.c +++ b/gdb/objfiles.c @@ -53,6 +53,7 @@ #include "complaints.h" #include "psymtab.h" #include "solist.h" +#include "gdb_bfd.h" /* Prototypes for local functions */ @@ -195,7 +196,8 @@ allocate_objfile (bfd *abfd, int flags) that any data that is reference is saved in the per-objfile data region. */ - objfile->obfd = gdb_bfd_ref (abfd); + objfile->obfd = abfd; + gdb_bfd_ref (abfd); if (abfd != NULL) { /* Look up the gdbarch associated with the BFD. */ @@ -1456,75 +1458,6 @@ objfiles_changed (void) get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1; } -/* Close ABFD, and warn if that fails. */ - -int -gdb_bfd_close_or_warn (struct bfd *abfd) -{ - int ret; - char *name = bfd_get_filename (abfd); - - ret = bfd_close (abfd); - - if (!ret) - warning (_("cannot close \"%s\": %s"), - name, bfd_errmsg (bfd_get_error ())); - - return ret; -} - -/* Add reference to ABFD. Returns ABFD. */ -struct bfd * -gdb_bfd_ref (struct bfd *abfd) -{ - int *p_refcount; - - if (abfd == NULL) - return NULL; - - p_refcount = bfd_usrdata (abfd); - - if (p_refcount != NULL) - { - *p_refcount += 1; - return abfd; - } - - p_refcount = xmalloc (sizeof (*p_refcount)); - *p_refcount = 1; - bfd_usrdata (abfd) = p_refcount; - - return abfd; -} - -/* Unreference and possibly close ABFD. */ -void -gdb_bfd_unref (struct bfd *abfd) -{ - int *p_refcount; - char *name; - - if (abfd == NULL) - return; - - p_refcount = bfd_usrdata (abfd); - - /* Valid range for p_refcount: a pointer to int counter, which has a - value of 1 (single owner) or 2 (shared). */ - gdb_assert (*p_refcount == 1 || *p_refcount == 2); - - *p_refcount -= 1; - if (*p_refcount > 0) - return; - - xfree (p_refcount); - bfd_usrdata (abfd) = NULL; /* Paranoia. */ - - name = bfd_get_filename (abfd); - gdb_bfd_close_or_warn (abfd); - xfree (name); -} - /* The default implementation for the "iterate_over_objfiles_in_search_order" gdbarch method. It is equivalent to use the ALL_OBJFILES macro, searching the objfiles in the order they are stored internally, diff --git a/gdb/objfiles.h b/gdb/objfiles.h index 01c3aea..0df5798 100644 --- a/gdb/objfiles.h +++ b/gdb/objfiles.h @@ -522,10 +522,6 @@ extern void set_objfile_data (struct objfile *objfile, extern void *objfile_data (struct objfile *objfile, const struct objfile_data *data); -extern struct bfd *gdb_bfd_ref (struct bfd *abfd); -extern void gdb_bfd_unref (struct bfd *abfd); -extern int gdb_bfd_close_or_warn (struct bfd *abfd); - extern void default_iterate_over_objfiles_in_search_order (struct gdbarch *gdbarch, iterate_over_objfiles_in_search_order_cb_ftype *cb, diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index b8434ed..98a076d 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -39,6 +39,7 @@ #include "cp-abi.h" #include "cp-support.h" #include "exceptions.h" +#include "dwarf2loc.h" /* Decorations for Pascal. */ @@ -74,8 +75,31 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, struct type *char_type; CORE_ADDR addr; int want_space = 0; + struct cleanup *back_to; + struct type *saved_type = type; + CORE_ADDR saved_address = address; + + back_to = make_cleanup (null_cleanup, 0); + address += embedded_offset; + 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; + } + if (address != saved_address + embedded_offset) + { + 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); + embedded_offset = 0; + } + else + address -= embedded_offset; switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: @@ -131,8 +155,8 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, { i = 0; } - val_print_array_elements (type, valaddr, embedded_offset, - address, stream, recurse, + val_print_array_elements (saved_type, valaddr, embedded_offset, + saved_address, stream, recurse, original_value, options, i); fprintf_filtered (stream, "}"); } @@ -170,6 +194,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, { /* Try to print what function it points to. */ print_address_demangle (options, gdbarch, addr, stream, demangle); + do_cleanups (back_to); return; } @@ -271,6 +296,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, } } + do_cleanups (back_to); return; case TYPE_CODE_REF: @@ -421,6 +447,7 @@ pascal_val_print (struct type *type, const gdb_byte *valaddr, TYPE_CODE (type)); } gdb_flush (stream); + do_cleanups (back_to); } void diff --git a/gdb/parse.c b/gdb/parse.c index 529c517..6326a01 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -1708,6 +1708,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) @@ -1749,7 +1750,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; } } @@ -1767,7 +1768,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. */ @@ -1780,24 +1782,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) { @@ -1812,7 +1817,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; @@ -1843,8 +1850,29 @@ 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. */ + +#if 0 +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); } +#endif void _initialize_parse (void) diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index 86f3bdf..f908a61 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -245,6 +245,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); @@ -331,6 +333,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); @@ -369,4 +372,10 @@ 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); + +#if 0 +extern void exp_types_mark_used (struct expression *exp); +#endif + #endif /* PARSER_DEFS_H */ diff --git a/gdb/printcmd.c b/gdb/printcmd.c index d5b5b63..4bc2b5b 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -50,6 +50,7 @@ #include "arch-utils.h" #include "cli/cli-utils.h" #include "format.h" +#include "dwarf2loc.h" #ifdef TUI #include "tui/tui.h" /* For tui_active et al. */ @@ -968,6 +969,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)) { @@ -1056,6 +1062,9 @@ output_command (char *exp, int from_tty) val = evaluate_expression (expr); + if (VALUE_LVAL (val) == lval_memory) + object_address_set (value_raw_address (val)); + annotate_value_begin (value_type (val)); get_formatted_print_options (&opts, format); @@ -1485,6 +1494,24 @@ x_command (char *exp, int from_tty) set_internalvar (lookup_internalvar ("__"), last_examine_value); } } + +#if 0 +/* 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); +} +#endif + /* Add an expression to the auto-display chain. @@ -1982,6 +2009,10 @@ print_variable_and_value (const char *name, struct symbol *var, struct value_print_options opts; val = read_var_value (var, frame); + + make_cleanup_restore_selected_frame (); + select_frame (frame); + get_user_print_options (&opts); opts.deref_ref = 1; common_val_print (val, stream, indent, &opts, current_language); @@ -2626,4 +2657,8 @@ Show printing of source filename and line number with <symbol>."), NULL, add_com ("eval", no_class, eval_command, _("\ Convert \"printf format string\", arg1, arg2, arg3, ..., argn to\n\ a command line, and call it.")); + +#if 0 + observer_attach_mark_used (print_types_mark_used); +#endif } diff --git a/gdb/procfs.c b/gdb/procfs.c index 774df2e..4409e5b 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -3486,7 +3486,7 @@ insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored) long storage_needed; CORE_ADDR sym_addr; - abfd = bfd_fdopenr ("unamed", 0, fd); + abfd = gdb_bfd_fdopenr ("unamed", 0, fd); if (abfd == NULL) { warning (_("Failed to create a bfd: %s."), bfd_errmsg (bfd_get_error ())); @@ -3497,7 +3497,7 @@ insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored) { /* Not the correct format, so we can not possibly find the dbx_link symbol in it. */ - bfd_close (abfd); + gdb_bfd_unref (abfd); return 0; } @@ -3511,14 +3511,14 @@ insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored) if (dbx_link_bpt == NULL) { warning (_("Failed to insert dbx_link breakpoint.")); - bfd_close (abfd); + gdb_bfd_unref (abfd); return 0; } - bfd_close (abfd); + gdb_bfd_unref (abfd); return 1; } - bfd_close (abfd); + gdb_bfd_unref (abfd); return 0; } diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py new file mode 100644 index 0000000..5654546 --- /dev/null +++ b/gdb/python/lib/gdb/FrameIterator.py @@ -0,0 +1,33 @@ +# Iterator over frames. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +class FrameIterator: + """An iterator that iterates over frames.""" + + def __init__ (self, frame): + "Initialize a FrameIterator. FRAME is the starting frame." + self.frame = frame + + def __iter__ (self): + return self + + def next (self): + result = self.frame + if result is None: + raise StopIteration + self.frame = result.older () + return result diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py new file mode 100644 index 0000000..b790a54 --- /dev/null +++ b/gdb/python/lib/gdb/FrameWrapper.py @@ -0,0 +1,112 @@ +# Wrapper API for frames. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb + +# FIXME: arguably all this should be on Frame somehow. +class FrameWrapper: + def __init__ (self, frame): + self.frame = frame; + + def write_symbol (self, stream, sym, block): + if len (sym.linkage_name): + nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) + if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER: + sym = nsym + + stream.write (sym.print_name + "=") + try: + val = self.read_var (sym) + if val != None: + val = str (val) + # FIXME: would be nice to have a more precise exception here. + except RuntimeError, text: + val = text + if val == None: + stream.write ("???") + else: + stream.write (str (val)) + + def print_frame_locals (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if sym.is_argument: + continue; + + self.write_symbol (stream, sym, block) + stream.write ('\n') + + def print_frame_args (self, stream, func): + if not func: + return + + first = True + block = func.value + + for sym in block: + if not sym.is_argument: + continue; + + if not first: + stream.write (", ") + + self.write_symbol (stream, sym, block) + first = False + + # FIXME: this should probably just be a method on gdb.Frame. + # But then we need stream wrappers. + def describe (self, stream, full): + if self.type () == gdb.DUMMY_FRAME: + stream.write (" <function called from gdb>\n") + elif self.type () == gdb.SIGTRAMP_FRAME: + stream.write (" <signal handler called>\n") + else: + sal = self.find_sal () + pc = self.pc () + name = self.name () + if not name: + name = "??" + if pc != sal.pc or not sal.symtab: + stream.write (" 0x%08x in" % pc) + stream.write (" " + name + " (") + + func = self.function () + self.print_frame_args (stream, func) + + stream.write (")") + + if sal.symtab and sal.symtab.filename: + stream.write (" at " + sal.symtab.filename) + stream.write (":" + str (sal.line)) + + if not self.name () or (not sal.symtab or not sal.symtab.filename): + lib = gdb.solib_address (pc) + if lib: + stream.write (" from " + lib) + + stream.write ("\n") + + if full: + self.print_frame_locals (stream, func) + + def __getattr__ (self, name): + return getattr (self.frame, name) diff --git a/gdb/python/lib/gdb/backtrace.py b/gdb/python/lib/gdb/backtrace.py new file mode 100644 index 0000000..6bb4fb1 --- /dev/null +++ b/gdb/python/lib/gdb/backtrace.py @@ -0,0 +1,42 @@ +# Filtering backtrace. + +# Copyright (C) 2008, 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb +import itertools + +# Our only exports. +__all__ = ['push_frame_filter', 'create_frame_filter'] + +frame_filter = None + +def push_frame_filter (constructor): + """Register a new backtrace filter class with the 'backtrace' command. +The filter will be passed an iterator as an argument. The iterator +will return gdb.Frame-like objects. The filter should in turn act as +an iterator returning such objects.""" + global frame_filter + if frame_filter == None: + frame_filter = constructor + else: + frame_filter = lambda iterator, filter = frame_filter: constructor (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/backtrace.py b/gdb/python/lib/gdb/command/backtrace.py new file mode 100644 index 0000000..eeea909 --- /dev/null +++ b/gdb/python/lib/gdb/command/backtrace.py @@ -0,0 +1,106 @@ +# New backtrace command. + +# Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb +import gdb.backtrace +import itertools +from gdb.FrameIterator import FrameIterator +from gdb.FrameWrapper import FrameWrapper +import sys + +class ReverseBacktraceParameter (gdb.Parameter): + """The new-backtrace command can show backtraces in 'reverse' order. +This means that the innermost frame will be printed last. +Note that reverse backtraces are more expensive to compute.""" + + set_doc = "Enable or disable reverse backtraces." + show_doc = "Show whether backtraces will be printed in reverse order." + + def __init__(self): + gdb.Parameter.__init__ (self, "reverse-backtrace", + gdb.COMMAND_STACK, gdb.PARAM_BOOLEAN) + # Default to compatibility with gdb. + self.value = False + +class FilteringBacktrace (gdb.Command): + """Print backtrace of all stack frames, or innermost COUNT frames. +With a negative argument, print outermost -COUNT frames. +Use of the 'full' qualifier also prints the values of the local variables. +Use of the 'raw' qualifier avoids any filtering by loadable modules. +""" + + def __init__ (self): + # FIXME: this is not working quite well enough to replace + # "backtrace" yet. + gdb.Command.__init__ (self, "new-backtrace", gdb.COMMAND_STACK) + self.reverse = ReverseBacktraceParameter() + + def reverse_iter (self, iter): + result = [] + for item in iter: + result.append (item) + result.reverse() + return result + + def final_n (self, iter, x): + result = [] + for item in iter: + result.append (item) + return result[x:] + + def invoke (self, arg, from_tty): + i = 0 + count = 0 + filter = True + full = False + + for word in arg.split (" "): + if word == '': + continue + elif word == 'raw': + filter = False + elif word == 'full': + full = True + else: + count = int (word) + + # FIXME: provide option to start at selected frame + # However, should still number as if starting from newest + newest_frame = gdb.newest_frame() + iter = itertools.imap (FrameWrapper, + FrameIterator (newest_frame)) + if filter: + iter = gdb.backtrace.create_frame_filter (iter) + + # Now wrap in an iterator that numbers the frames. + iter = itertools.izip (itertools.count (0), iter) + + # Reverse if the user wanted that. + if self.reverse.value: + iter = self.reverse_iter (iter) + + # Extract sub-range user wants. + if count < 0: + iter = self.final_n (iter, count) + elif count > 0: + iter = itertools.islice (iter, 0, count) + + for pair in iter: + sys.stdout.write ("#%-2d" % pair[0]) + pair[1].describe (sys.stdout, full) + +FilteringBacktrace() diff --git a/gdb/python/lib/gdb/command/ignore_errors.py b/gdb/python/lib/gdb/command/ignore_errors.py new file mode 100644 index 0000000..6fa48ff --- /dev/null +++ b/gdb/python/lib/gdb/command/ignore_errors.py @@ -0,0 +1,37 @@ +# Ignore errors in user commands. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb + +class IgnoreErrorsCommand (gdb.Command): + """Execute a single command, ignoring all errors. +Only one-line commands are supported. +This is primarily useful in scripts.""" + + def __init__ (self): + super (IgnoreErrorsCommand, self).__init__ ("ignore-errors", + gdb.COMMAND_OBSCURE, + # FIXME... + gdb.COMPLETE_COMMAND) + + def invoke (self, arg, from_tty): + try: + gdb.execute (arg, from_tty) + except: + pass + +IgnoreErrorsCommand () diff --git a/gdb/python/lib/gdb/command/pahole.py b/gdb/python/lib/gdb/command/pahole.py new file mode 100644 index 0000000..21a0bf0 --- /dev/null +++ b/gdb/python/lib/gdb/command/pahole.py @@ -0,0 +1,75 @@ +# pahole command for gdb + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb + +class Pahole (gdb.Command): + """Show the holes in a structure. +This command takes a single argument, a type name. +It prints the type and displays comments showing where holes are.""" + + def __init__ (self): + super (Pahole, self).__init__ ("pahole", gdb.COMMAND_NONE, + gdb.COMPLETE_SYMBOL) + + def pahole (self, type, level, name): + if name is None: + name = '' + tag = type.tag + if tag is None: + tag = '' + print '%sstruct %s {' % (' ' * (2 * level), tag) + bitpos = 0 + for field in type.fields (): + # Skip static fields. + if not hasattr (field, ('bitpos')): + continue + + ftype = field.type.strip_typedefs() + + if bitpos != field.bitpos: + hole = field.bitpos - bitpos + print ' /* XXX %d bit hole, try to pack */' % hole + bitpos = field.bitpos + if field.bitsize > 0: + fieldsize = field.bitsize + else: + # TARGET_CHAR_BIT here... + fieldsize = 8 * ftype.sizeof + + # TARGET_CHAR_BIT + print ' /* %3d %3d */' % (int (bitpos / 8), int (fieldsize / 8)), + bitpos = bitpos + fieldsize + + if ftype.code == gdb.TYPE_CODE_STRUCT: + self.pahole (ftype, level + 1, field.name) + else: + print ' ' * (2 + 2 * level), + print '%s %s' % (str (ftype), field.name) + + print ' ' * (14 + 2 * level), + print '} %s' % name + + def invoke (self, arg, from_tty): + type = gdb.lookup_type (arg) + type = type.strip_typedefs () + if type.code != gdb.TYPE_CODE_STRUCT: + raise TypeError, '%s is not a struct type' % arg + print ' ' * 14, + self.pahole (type, 0, '') + +Pahole() diff --git a/gdb/python/lib/gdb/command/require.py b/gdb/python/lib/gdb/command/require.py new file mode 100644 index 0000000..1fbc1e8 --- /dev/null +++ b/gdb/python/lib/gdb/command/require.py @@ -0,0 +1,57 @@ +# Demand-loading commands. + +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb +import os + +class RequireCommand (gdb.Command): + """Prefix command for requiring features.""" + + def __init__ (self): + super (RequireCommand, self).__init__ ("require", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE, + True) + +class RequireSubcommand (gdb.Command): + """Demand-load a command by name.""" + + def __init__ (self, name): + self.__doc__ = "Demand-load a %s by name." % name + super (RequireSubcommand, self).__init__ ("require %s" % name, + gdb.COMMAND_SUPPORT) + self.name = name + + def invoke (self, arg, from_tty): + for cmd in arg.split(): + exec ('import gdb.' + self.name + '.' + cmd, globals ()) + + def complete (self, text, word): + dir = gdb.pythondir + '/gdb/' + self.name + result = [] + for file in os.listdir(dir): + if not file.startswith (word) or not file.endswith ('.py'): + continue + feature = file[0:-3] + if feature == 'require' or feature == '__init__': + continue + result.append (feature) + return result + +RequireCommand() +RequireSubcommand("command") +RequireSubcommand("function") diff --git a/gdb/python/lib/gdb/command/upto.py b/gdb/python/lib/gdb/command/upto.py new file mode 100644 index 0000000..faf54ed --- /dev/null +++ b/gdb/python/lib/gdb/command/upto.py @@ -0,0 +1,129 @@ +# upto command. + +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb +import re +from gdb.FrameIterator import FrameIterator +from gdb.FrameWrapper import FrameWrapper + +class UptoPrefix (gdb.Command): + def __init__ (self): + super (UptoPrefix, self).__init__ ("upto", gdb.COMMAND_STACK, + prefix = True) + +class UptoImplementation (gdb.Command): + def __init__ (self, subcommand): + super (UptoImplementation, self).__init__ ("upto " + subcommand, + gdb.COMMAND_STACK) + + def search (self): + saved = gdb.selected_frame () + iter = FrameIterator (saved) + found = False + try: + for frame in iter: + frame.select () + try: + if self.filter (frame): + wrapper = FrameWrapper (frame) + wrapper.describe (sys.stdout, False) + return + except: + pass + except: + pass + saved.select () + raise RuntimeError, 'Could not find a matching frame' + + def invoke (self, arg, from_tty): + self.rx = re.compile (arg) + self.search () + +class UptoSymbolCommand (UptoImplementation): + """Select and print some calling stack frame, based on symbol. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose symbol matches the regular +expression.""" + + def __init__ (self): + super (UptoSymbolCommand, self).__init__ ("symbol") + + def filter (self, frame): + name = frame.name () + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoSourceCommand (UptoImplementation): + """Select and print some calling stack frame, based on source file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose source file name matches the +regular expression.""" + + def __init__ (self): + super (UptoSourceCommand, self).__init__ ("source") + + def filter (self, frame): + name = frame.find_sal ().symtab.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoObjectCommand (UptoImplementation): + """Select and print some calling stack frame, based on object file. +The argument is a regular expression. This command moves up the +stack, stopping at the first frame whose object file name matches the +regular expression.""" + + def __init__ (self): + super (UptoObjectCommand, self).__init__ ("object") + + def filter (self, frame): + name = frame.find_sal ().symtab.objfile.filename + if name is not None: + if self.rx.search (name) is not None: + return True + return False + +class UptoWhereCommand (UptoImplementation): + """Select and print some calling stack frame, based on expression. +The argument is an expression. This command moves up the stack, +parsing and evaluating the expression in each frame. This stops when +the expression evaluates to a non-zero (true) value.""" + + def __init__ (self): + super (UptoWhereCommand, self).__init__ ("where") + + def filter (self, frame): + try: + if gdb.parse_and_eval (self.expression): + return True + except: + pass + return False + + def invoke (self, arg, from_tty): + self.expression = arg + self.search () + +UptoPrefix () +UptoSymbolCommand () +UptoSourceCommand () +UptoObjectCommand () +UptoWhereCommand () diff --git a/gdb/python/lib/gdb/function/__init__.py b/gdb/python/lib/gdb/function/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/gdb/python/lib/gdb/function/__init__.py @@ -0,0 +1 @@ + diff --git a/gdb/python/lib/gdb/function/caller_is.py b/gdb/python/lib/gdb/function/caller_is.py new file mode 100644 index 0000000..2b9c5c7 --- /dev/null +++ b/gdb/python/lib/gdb/function/caller_is.py @@ -0,0 +1,58 @@ +# Caller-is functions. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb +import re + +class CallerIs (gdb.Function): + """Return True if the calling function's name is equal to a string. +This function takes one or two arguments. +The first argument is the name of a function; if the calling function's +name is equal to this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerIs, self).__init__ ("caller_is") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return frame.name () == name.string () + +class CallerMatches (gdb.Function): + """Return True if the calling function's name matches a string. +This function takes one or two arguments. +The first argument is a regular expression; if the calling function's +name is matched by this argument, this function returns True. +The optional second argument tells this function how many stack frames +to traverse to find the calling function. The default is 1.""" + + def __init__ (self): + super (CallerMatches, self).__init__ ("caller_matches") + + def invoke (self, name, nframes = 1): + frame = gdb.selected_frame () + while nframes > 0: + frame = frame.older () + nframes = nframes - 1 + return re.match (name.string (), frame.name ()) is not None + +CallerIs() +CallerMatches() diff --git a/gdb/python/lib/gdb/function/in_scope.py b/gdb/python/lib/gdb/function/in_scope.py new file mode 100644 index 0000000..debb3bb --- /dev/null +++ b/gdb/python/lib/gdb/function/in_scope.py @@ -0,0 +1,47 @@ +# In-scope function. + +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb + +class InScope (gdb.Function): + """Return True if all the given variables or macros are in scope. +Takes one argument for each variable name to be checked.""" + + def __init__ (self): + super (InScope, self).__init__ ("in_scope") + + def invoke (self, *vars): + if len (vars) == 0: + raise TypeError, "in_scope takes at least one argument" + + # gdb.Value isn't hashable so it can't be put in a map. + # Convert to string first. + wanted = set (map (lambda x: x.string (), vars)) + found = set () + block = gdb.selected_frame ().block () + while block: + for sym in block: + if (sym.is_argument or sym.is_constant + or sym.is_function or sym.is_variable): + if sym.name in wanted: + found.add (sym.name) + + block = block.superblock + + return wanted == found + +InScope () diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c index 98030a6..9870eec 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -30,6 +30,8 @@ #include "vec.h" #include "bcache.h" #include "dwarf2loc.h" +#include "observer.h" +#include "gdb_assert.h" typedef struct pyty_type_object { @@ -38,11 +40,19 @@ 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; +#if 0 +/* First element of a doubly-linked list of TYPE_DISCARDABLE Types. */ +static type_object *pyty_objects_discardable; +#endif + static PyTypeObject type_object_type; /* A Field object. */ @@ -1166,8 +1176,63 @@ typy_richcompare (PyObject *self, PyObject *other, int op) +/* 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); + } +#if 0 + 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; + } +#endif + 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); + } +#if 0 + else if (pyty_objects_discardable == type_obj) + pyty_objects_discardable = type_obj->next; +#endif + + if (type_obj->next) + type_obj->next->prev = type_obj->prev; +} + static void save_objfile_types (struct objfile *objfile, void *datum) { @@ -1185,12 +1250,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; } @@ -1201,43 +1267,28 @@ 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); } +#if 0 +/* 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); } +#endif /* Return number of fields ("length" of the field dictionary). */ @@ -1457,7 +1508,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; } @@ -1537,6 +1591,10 @@ gdbpy_initialize_types (void) Py_INCREF (&field_object_type); PyModule_AddObject (gdb_module, "Field", (PyObject *) &field_object_type); + +#if 0 + observer_attach_mark_used (typy_types_mark_used); +#endif } diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c index 6f67bdb..5ddd6bc 100644 --- a/gdb/python/py-value.c +++ b/gdb/python/py-value.c @@ -29,6 +29,7 @@ #include "expression.h" #include "cp-abi.h" #include "python.h" +#include "observer.h" #ifdef HAVE_PYTHON @@ -1378,6 +1379,19 @@ gdbpy_is_value_object (PyObject *obj) return PyObject_TypeCheck (obj, &value_object_type); } +#if 0 +/* 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)); +} +#endif + void gdbpy_initialize_values (void) { @@ -1388,6 +1402,10 @@ gdbpy_initialize_values (void) PyModule_AddObject (gdb_module, "Value", (PyObject *) &value_object_type); values_in_python = NULL; + +#if 0 + observer_attach_mark_used (python_types_mark_used); +#endif } diff --git a/gdb/python/python.c b/gdb/python/python.c index c66efe4..0211fcb 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -66,10 +66,13 @@ static const char *gdbpy_should_print_stack = python_excp_message; #include "linespec.h" #include "source.h" #include "version.h" +#include "inferior.h" +#include "gdbthread.h" #include "target.h" #include "gdbthread.h" #include "observer.h" #include "interps.h" +#include "event-top.h" static PyMethodDef GdbMethods[]; @@ -979,6 +982,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) @@ -1420,6 +1470,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" }, diff --git a/gdb/python/python.h b/gdb/python/python.h index dd7066f..f0f6e90 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -30,6 +30,8 @@ void eval_python_from_control_command (struct command_line *); void source_python_script (FILE *file, const char *filename); +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/record.c b/gdb/record.c index bb0fe52..ec42aac 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -32,6 +32,7 @@ #include "gcore.h" #include "event-loop.h" #include "inf-loop.h" +#include "gdb_bfd.h" #include <signal.h> @@ -2638,7 +2639,7 @@ record_save_cleanups (void *data) bfd *obfd = data; char *pathname = xstrdup (bfd_get_filename (obfd)); - bfd_close (obfd); + gdb_bfd_unref (obfd); unlink (pathname); xfree (pathname); } @@ -2854,7 +2855,7 @@ cmd_record_save (char *args, int from_tty) } do_cleanups (set_cleanups); - bfd_close (obfd); + gdb_bfd_unref (obfd); discard_cleanups (old_cleanups); /* Succeeded. */ diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c index 47f4405..85268b6 100644 --- a/gdb/remote-m32r-sdi.c +++ b/gdb/remote-m32r-sdi.c @@ -39,6 +39,7 @@ #include <sys/time.h> #include <signal.h> #include <time.h> +#include "gdb_bfd.h" #include "serial.h" @@ -1257,13 +1258,13 @@ m32r_load (char *args, int from_tty) if (!filename) filename = get_exec_file (1); - pbfd = bfd_openr (filename, gnutarget); + pbfd = gdb_bfd_openr (filename, gnutarget); if (pbfd == NULL) { perror_with_name (filename); return; } - old_chain = make_cleanup_bfd_close (pbfd); + old_chain = make_cleanup_bfd_unref (pbfd); if (!bfd_check_format (pbfd, bfd_object)) error (_("\"%s\" is not an object file: %s"), filename, diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c index babbf19..db4381b 100644 --- a/gdb/remote-mips.c +++ b/gdb/remote-mips.c @@ -36,6 +36,7 @@ #include <ctype.h> #include "mips-tdep.h" #include "gdbthread.h" +#include "gdb_bfd.h" /* Breakpoint types. Values 0, 1, and 2 must agree with the watch @@ -2783,20 +2784,23 @@ mips_load_srec (char *args) unsigned int i; unsigned int srec_frame = 200; int reclen; + struct cleanup *cleanup; static int hashmark = 1; buffer = alloca (srec_frame * 2 + 256); - abfd = bfd_openr (args, 0); + abfd = gdb_bfd_openr (args, 0); if (!abfd) { printf_filtered ("Unable to open file %s\n", args); return; } + cleanup = make_cleanup_bfd_unref (abfd); if (bfd_check_format (abfd, bfd_object) == 0) { printf_filtered ("File is not an object file\n"); + do_cleanups (cleanup); return; } @@ -2850,6 +2854,7 @@ mips_load_srec (char *args) send_srec (srec, reclen, abfd->start_address); serial_flush_input (mips_desc); + do_cleanups (cleanup); } /* @@ -3366,20 +3371,23 @@ pmon_load_fast (char *file) int bintotal = 0; int final = 0; int finished = 0; + struct cleanup *cleanup; buffer = (char *) xmalloc (MAXRECSIZE + 1); binbuf = (unsigned char *) xmalloc (BINCHUNK); - abfd = bfd_openr (file, 0); + abfd = gdb_bfd_openr (file, 0); if (!abfd) { printf_filtered ("Unable to open file %s\n", file); return; } + cleanup = make_cleanup_bfd_unref (abfd); if (bfd_check_format (abfd, bfd_object) == 0) { printf_filtered ("File is not an object file\n"); + do_cleanups (cleanup); return; } @@ -3503,6 +3511,7 @@ pmon_load_fast (char *file) pmon_end_download (final, bintotal); } + do_cleanups (cleanup); return; } diff --git a/gdb/remote.c b/gdb/remote.c index 1c9367d..f2b5e7b 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -42,6 +42,7 @@ #include "cli/cli-decode.h" #include "cli/cli-setshow.h" #include "target-descriptions.h" +#include "gdb_bfd.h" #include <ctype.h> #include <sys/time.h> @@ -9823,11 +9824,13 @@ remote_filename_p (const char *filename) bfd * remote_bfd_open (const char *remote_file, const char *target) { - return bfd_openr_iovec (remote_file, target, - remote_bfd_iovec_open, NULL, - remote_bfd_iovec_pread, - remote_bfd_iovec_close, - remote_bfd_iovec_stat); + bfd *abfd = gdb_bfd_openr_iovec (remote_file, target, + remote_bfd_iovec_open, NULL, + remote_bfd_iovec_pread, + remote_bfd_iovec_close, + remote_bfd_iovec_stat); + + return abfd; } void diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c index 0a2000a..9b8efd3 100644 --- a/gdb/rs6000-nat.c +++ b/gdb/rs6000-nat.c @@ -730,7 +730,7 @@ static struct vmap * add_vmap (LdInfo *ldi) { bfd *abfd, *last; - char *mem, *objname, *filename; + char *mem, *filename; struct objfile *obj; struct vmap *vp; int fd; @@ -743,19 +743,18 @@ add_vmap (LdInfo *ldi) filename = LDI_FILENAME (ldi, arch64); mem = filename + strlen (filename) + 1; mem = xstrdup (mem); - objname = xstrdup (filename); fd = LDI_FD (ldi, arch64); if (fd < 0) /* Note that this opens it once for every member; a possible enhancement would be to only open it once for every object. */ - abfd = bfd_openr (objname, gnutarget); + abfd = gdb_bfd_openr (filename, gnutarget); else - abfd = bfd_fdopenr (objname, gnutarget, fd); + abfd = gdb_bfd_fdopenr (filename, gnutarget, fd); if (!abfd) { warning (_("Could not open `%s' as an executable file: %s"), - objname, bfd_errmsg (bfd_get_error ())); + filename, bfd_errmsg (bfd_get_error ())); return NULL; } @@ -766,35 +765,44 @@ add_vmap (LdInfo *ldi) else if (bfd_check_format (abfd, bfd_archive)) { - last = 0; - /* FIXME??? am I tossing BFDs? bfd? */ - while ((last = bfd_openr_next_archived_file (abfd, last))) - if (strcmp (mem, last->filename) == 0) - break; + last = gdb_bfd_openr_next_archived_file (abfd, NULL); + while (last != NULL) + { + bfd *next; + + if (strcmp (mem, last->filename) == 0) + break; + + next = gdb_bfd_openr_next_archived_file (abfd, last); + gdb_bfd_unref (last); + } if (!last) { - warning (_("\"%s\": member \"%s\" missing."), objname, mem); - bfd_close (abfd); + warning (_("\"%s\": member \"%s\" missing."), filename, mem); + gdb_bfd_unref (abfd); return NULL; } if (!bfd_check_format (last, bfd_object)) { warning (_("\"%s\": member \"%s\" not in executable format: %s."), - objname, mem, bfd_errmsg (bfd_get_error ())); - bfd_close (last); - bfd_close (abfd); + filename, mem, bfd_errmsg (bfd_get_error ())); + gdb_bfd_unref (last); + gdb_bfd_unref (abfd); return NULL; } vp = map_vmap (last, abfd); + /* map_vmap acquired a reference to LAST, so we can release + ours. */ + gdb_bfd_unref (last); } else { warning (_("\"%s\": not in executable format: %s."), - objname, bfd_errmsg (bfd_get_error ())); - bfd_close (abfd); + filename, bfd_errmsg (bfd_get_error ())); + gdb_bfd_unref (abfd); return NULL; } obj = allocate_objfile (vp->bfd, 0); @@ -803,6 +811,11 @@ add_vmap (LdInfo *ldi) /* Always add symbols for the main objfile. */ if (vp == vmap || auto_solib_add) vmap_add_symbols (vp); + + /* Anything needing a reference to ABFD has already acquired it, so + release our local reference. */ + gdb_bfd_unref (abfd); + return vp; } diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c index d52fb46..db8f187 100644 --- a/gdb/solib-darwin.c +++ b/gdb/solib-darwin.c @@ -28,6 +28,7 @@ #include "inferior.h" #include "regcache.h" #include "gdbthread.h" +#include "gdb_bfd.h" #include "gdb_assert.h" @@ -356,6 +357,7 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) gdb_byte *interp_name; CORE_ADDR load_addr = 0; bfd *dyld_bfd = NULL; + struct cleanup *cleanup; /* This method doesn't work with an attached process. */ if (current_inferior ()->attach_flag) @@ -366,24 +368,31 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) if (!interp_name) return; + cleanup = make_cleanup (null_cleanup, NULL); + /* Create a bfd for the interpreter. */ - dyld_bfd = bfd_openr (interp_name, gnutarget); + dyld_bfd = gdb_bfd_openr (interp_name, gnutarget); if (dyld_bfd) { bfd *sub; + make_cleanup_bfd_unref (dyld_bfd); sub = bfd_mach_o_fat_extract (dyld_bfd, bfd_object, gdbarch_bfd_arch_info (target_gdbarch)); if (sub) - dyld_bfd = sub; - else { - bfd_close (dyld_bfd); - dyld_bfd = NULL; + dyld_bfd = sub; + gdb_bfd_ref (sub); + make_cleanup_bfd_unref (sub); } + else + dyld_bfd = NULL; } if (!dyld_bfd) - return; + { + do_cleanups (cleanup); + return; + } /* We find the dynamic linker's base address by examining the current pc (which should point at the entry point for the @@ -395,7 +404,7 @@ darwin_solib_get_all_image_info_addr_at_init (struct darwin_info *info) info->all_image_addr = lookup_symbol_from_bfd (dyld_bfd, "_dyld_all_image_infos"); - bfd_close (dyld_bfd); + do_cleanups (cleanup); if (info->all_image_addr == 0) return; @@ -509,17 +518,10 @@ darwin_bfd_open (char *pathname) gdbarch_bfd_arch_info (target_gdbarch)); if (!res) { - bfd_close (abfd); - make_cleanup (xfree, found_pathname); + make_cleanup_bfd_unref (abfd); error (_("`%s': not a shared-library: %s"), - found_pathname, bfd_errmsg (bfd_get_error ())); + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); } - - /* Make sure that the filename is malloc'ed. The current filename - for fat-binaries BFDs is a name that was generated by BFD, usually - a static string containing the name of the architecture. */ - res->filename = xstrdup (pathname); - return res; } diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c index 2500c1f..fcc01a8 100644 --- a/gdb/solib-dsbt.c +++ b/gdb/solib-dsbt.c @@ -30,6 +30,7 @@ #include "gdbcmd.h" #include "elf-bfd.h" #include "exceptions.h" +#include "gdb_bfd.h" #define GOT_MODULE_OFFSET 4 @@ -899,7 +900,7 @@ enable_break2 (void) { warning (_("Could not find symbol _dl_debug_addr in dynamic linker")); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } @@ -948,13 +949,13 @@ enable_break2 (void) "(at address %s) from dynamic linker"), hex_string_custom (addr + 8, 8)); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order); /* We're done with the temporary bfd. */ - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); /* We're also done with the loadmap. */ xfree (ldm); diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c index 2f2c8b0..0f59535 100644 --- a/gdb/solib-frv.c +++ b/gdb/solib-frv.c @@ -31,6 +31,7 @@ #include "gdbcmd.h" #include "elf/frv.h" #include "exceptions.h" +#include "gdb_bfd.h" /* Flag which indicates whether internal debug messages should be printed. */ static int solib_frv_debug; @@ -574,7 +575,7 @@ enable_break2 (void) { warning (_("Unable to determine dynamic linker loadmap address.")); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } @@ -589,7 +590,7 @@ enable_break2 (void) warning (_("Unable to load dynamic linker loadmap at address %s."), hex_string_custom (interp_loadmap_addr, 8)); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } @@ -623,7 +624,7 @@ enable_break2 (void) warning (_("Could not find symbol _dl_debug_addr " "in dynamic linker")); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } @@ -674,7 +675,7 @@ enable_break2 (void) "(at address %s) from dynamic linker"), hex_string_custom (addr + 8, 8)); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order); @@ -686,13 +687,13 @@ enable_break2 (void) "(at address %s) from dynamic linker"), hex_string_custom (addr, 8)); enable_break_failure_warning (); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return 0; } addr = extract_unsigned_integer (addr_buf, sizeof addr_buf, byte_order); /* We're done with the temporary bfd. */ - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); /* We're also done with the loadmap. */ xfree (ldm); diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c index 2b8d061..00ed8a5 100644 --- a/gdb/solib-pa64.c +++ b/gdb/solib-pa64.c @@ -362,7 +362,7 @@ manpage for methods to privately map shared library text.")); to find any magic formula to find it for Solaris (appears to be trivial on GNU/Linux). Therefore, we have to try an alternate mechanism to find the dynamic linker's base address. */ - tmp_bfd = bfd_openr (buf, gnutarget); + tmp_bfd = gdb_bfd_openr (buf, gnutarget); if (tmp_bfd == NULL) return; @@ -371,7 +371,7 @@ manpage for methods to privately map shared library text.")); { warning (_("Unable to grok dynamic linker %s as an object file"), buf); - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); return; } @@ -401,7 +401,7 @@ manpage for methods to privately map shared library text.")); } /* We're done with the temporary bfd. */ - bfd_close (tmp_bfd); + gdb_bfd_unref (tmp_bfd); } } diff --git a/gdb/solib-spu.c b/gdb/solib-spu.c index b5454e7..f62d96c 100644 --- a/gdb/solib-spu.c +++ b/gdb/solib-spu.c @@ -36,6 +36,7 @@ #include "breakpoint.h" #include "gdbthread.h" #include "exceptions.h" +#include "gdb_bfd.h" #include "spu-tdep.h" @@ -325,16 +326,16 @@ spu_bfd_fopen (char *name, CORE_ADDR addr) CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR)); *open_closure = addr; - nbfd = bfd_openr_iovec (xstrdup (name), "elf32-spu", - spu_bfd_iovec_open, open_closure, - spu_bfd_iovec_pread, spu_bfd_iovec_close, - spu_bfd_iovec_stat); + nbfd = gdb_bfd_openr_iovec (name, "elf32-spu", + spu_bfd_iovec_open, open_closure, + spu_bfd_iovec_pread, spu_bfd_iovec_close, + spu_bfd_iovec_stat); if (!nbfd) return NULL; if (!bfd_check_format (nbfd, bfd_object)) { - bfd_close (nbfd); + gdb_bfd_unref (nbfd); return NULL; } diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 307e483..76bd872 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -46,6 +46,7 @@ #include "exec.h" #include "auxv.h" #include "exceptions.h" +#include "gdb_bfd.h" static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); @@ -1558,9 +1559,11 @@ enable_break (struct svr4_info *info, int from_tty) goto bkpt_at_symbol; /* Now convert the TMP_BFD into a target. That way target, as - well as BFD operations can be used. Note that closing the - target will also close the underlying bfd. */ + well as BFD operations can be used. */ tmp_bfd_target = target_bfd_reopen (tmp_bfd); + /* target_bfd_reopen acquired its own reference, so we can + release ours now. */ + gdb_bfd_unref (tmp_bfd); /* On a running target, we can get the dynamic linker's base address from the shared library table. */ @@ -1670,8 +1673,9 @@ enable_break (struct svr4_info *info, int from_tty) sym_addr, tmp_bfd_target); - /* We're done with both the temporary bfd and target. Remember, - closing the target closes the underlying bfd. */ + /* We're done with both the temporary bfd and target. Closing + the target closes the underlying bfd, because it holds the + only remaining reference. */ target_close (tmp_bfd_target, 0); if (sym_addr != 0) diff --git a/gdb/solib.c b/gdb/solib.c index 90439ba..73773f1 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -46,6 +46,7 @@ #include "solib.h" #include "interps.h" #include "filesystem.h" +#include "gdb_bfd.h" /* Architecture-specific operations. */ @@ -360,9 +361,9 @@ solib_find (char *in_pathname, int *fd) it is used as file handle to open the file. Throws an error if the file could not be opened. Handles both local and remote file access. - PATHNAME must be malloc'ed by the caller. If successful, the new BFD's - name will point to it. If unsuccessful, PATHNAME will be freed and the - FD will be closed (unless FD was -1). */ + PATHNAME must be malloc'ed by the caller. It will be freed by this + function. If unsuccessful, the FD will be closed (unless FD was + -1). */ bfd * solib_bfd_fopen (char *pathname, int fd) @@ -376,7 +377,7 @@ solib_bfd_fopen (char *pathname, int fd) } else { - abfd = bfd_fopen (pathname, gnutarget, FOPEN_RB, fd); + abfd = gdb_bfd_fopen (pathname, gnutarget, FOPEN_RB, fd); if (abfd) bfd_set_cacheable (abfd, 1); @@ -389,6 +390,8 @@ solib_bfd_fopen (char *pathname, int fd) pathname, bfd_errmsg (bfd_get_error ())); } + xfree (pathname); + return abfd; } @@ -420,17 +423,16 @@ solib_bfd_open (char *pathname) /* Check bfd format. */ if (!bfd_check_format (abfd, bfd_object)) { - bfd_close (abfd); - make_cleanup (xfree, found_pathname); + make_cleanup_bfd_unref (abfd); error (_("`%s': not in executable format: %s"), - found_pathname, bfd_errmsg (bfd_get_error ())); + bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); } /* Check bfd arch. */ b = gdbarch_bfd_arch_info (target_gdbarch); if (!b->compatible (b, bfd_get_arch_info (abfd))) warning (_("`%s': Shared library architecture %s is not compatible " - "with target architecture %s."), found_pathname, + "with target architecture %s."), bfd_get_filename (abfd), bfd_get_arch_info (abfd)->printable_name, b->printable_name); return abfd; @@ -466,7 +468,7 @@ solib_map_sections (struct so_list *so) return 0; /* Leave bfd open, core_xfer_memory and "info files" need it. */ - so->abfd = gdb_bfd_ref (abfd); + so->abfd = abfd; /* copy full path name into so_name, so that later symbol_file_add can find it. */ @@ -1233,7 +1235,7 @@ reload_shared_libraries_1 (int from_tty) { found_pathname = xstrdup (bfd_get_filename (abfd)); make_cleanup (xfree, found_pathname); - gdb_bfd_close_or_warn (abfd); + gdb_bfd_unref (abfd); } /* If this shared library is no longer associated with its previous diff --git a/gdb/spu-linux-nat.c b/gdb/spu-linux-nat.c index 2dfec8c..999f1ab 100644 --- a/gdb/spu-linux-nat.c +++ b/gdb/spu-linux-nat.c @@ -315,16 +315,16 @@ spu_bfd_open (ULONGEST addr) ULONGEST *open_closure = xmalloc (sizeof (ULONGEST)); *open_closure = addr; - nbfd = bfd_openr_iovec (xstrdup ("<in-memory>"), "elf32-spu", - spu_bfd_iovec_open, open_closure, - spu_bfd_iovec_pread, spu_bfd_iovec_close, - spu_bfd_iovec_stat); + nbfd = gdb_bfd_openr_iovec ("<in-memory>", "elf32-spu", + spu_bfd_iovec_open, open_closure, + spu_bfd_iovec_pread, spu_bfd_iovec_close, + spu_bfd_iovec_stat); if (!nbfd) return NULL; if (!bfd_check_format (nbfd, bfd_object)) { - bfd_close (nbfd); + gdb_bfd_unref (nbfd); return NULL; } @@ -374,8 +374,13 @@ spu_symbol_file_add_from_memory (int inferior_fd) /* Open BFD representing SPE executable and read its symbols. */ nbfd = spu_bfd_open (addr); if (nbfd) - symbol_file_add_from_bfd (nbfd, SYMFILE_VERBOSE | SYMFILE_MAINLINE, - NULL, 0, NULL); + { + struct cleanup *cleanup = make_cleanup_bfd_unref (nbfd); + + symbol_file_add_from_bfd (nbfd, SYMFILE_VERBOSE | SYMFILE_MAINLINE, + NULL, 0, NULL); + do_cleanups (cleanup); + } } diff --git a/gdb/stack.c b/gdb/stack.c index 35d379d..04aab5e 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -509,6 +509,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame, stb = mem_fileopen (); old_chain = make_cleanup_ui_file_delete (stb); + /* Frame may be needed for check_typedef of TYPE_DYNAMIC. */ + make_cleanup_restore_selected_frame (); + select_frame (frame); + if (func) { struct block *b = SYMBOL_BLOCK_VALUE (func); diff --git a/gdb/symfile-mem.c b/gdb/symfile-mem.c index e80fd25..2e53be0 100644 --- a/gdb/symfile-mem.c +++ b/gdb/symfile-mem.c @@ -54,6 +54,7 @@ #include "observer.h" #include "auxv.h" #include "elf/common.h" +#include "gdb_bfd.h" /* Verify parameters of target_read_memory_bfd and target_read_memory are compatible. */ @@ -100,23 +101,24 @@ symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr, char *name, if (nbfd == NULL) error (_("Failed to read a valid object file image from memory.")); + gdb_bfd_ref (nbfd); if (name == NULL) - nbfd->filename = xstrdup ("shared object read from target memory"); + nbfd->filename = "shared object read from target memory"; else - nbfd->filename = name; - - if (!bfd_check_format (nbfd, bfd_object)) { - /* FIXME: should be checking for errors from bfd_close (for one thing, - on error it does not free all the storage associated with the - bfd). */ - bfd_close (nbfd); - error (_("Got object file from memory but can't read symbols: %s."), - bfd_errmsg (bfd_get_error ())); + nbfd->filename = name; + gdb_bfd_stash_filename (nbfd); + xfree (name); } + cleanup = make_cleanup_bfd_unref (nbfd); + + if (!bfd_check_format (nbfd, bfd_object)) + error (_("Got object file from memory but can't read symbols: %s."), + bfd_errmsg (bfd_get_error ())); + sai = alloc_section_addr_info (bfd_count_sections (nbfd)); - cleanup = make_cleanup (xfree, sai); + make_cleanup (xfree, sai); i = 0; for (sec = nbfd->sections; sec != NULL; sec = sec->next) if ((bfd_get_section_flags (nbfd, sec) & (SEC_ALLOC|SEC_LOAD)) != 0) diff --git a/gdb/symfile.c b/gdb/symfile.c index 01252e2..95ed480 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -55,6 +55,7 @@ #include "solib.h" #include "remote.h" #include "stack.h" +#include "gdb_bfd.h" #include <sys/types.h> #include <fcntl.h> @@ -1036,7 +1037,7 @@ new_symfile_objfile (struct objfile *objfile, int add_flags) loaded file. ABFD is a BFD already open on the file, as from symfile_bfd_open. - This BFD will be closed on error, and is always consumed by this function. + A new reference is acquired by this function. ADD_FLAGS encodes verbosity, whether this is main symbol file or extra, such as dynamically loaded code, and what to do with breakpoins. @@ -1060,7 +1061,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int flags, struct objfile *parent) { struct objfile *objfile; - struct cleanup *my_cleanups; const char *name = bfd_get_filename (abfd); const int from_tty = add_flags & SYMFILE_VERBOSE; const int mainline = add_flags & SYMFILE_MAINLINE; @@ -1074,8 +1074,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, add_flags &= ~SYMFILE_NO_READ; } - my_cleanups = make_cleanup_bfd_close (abfd); - /* Give user a chance to burp if we'd be interactively wiping out any existing symbols. */ @@ -1086,7 +1084,6 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, error (_("Not confirmed.")); objfile = allocate_objfile (abfd, flags | (mainline ? OBJF_MAINLINE : 0)); - discard_cleanups (my_cleanups); if (parent) add_separate_debug_objfile (objfile, parent); @@ -1207,8 +1204,13 @@ struct objfile * symbol_file_add (char *name, int add_flags, struct section_addr_info *addrs, int flags) { - return symbol_file_add_from_bfd (symfile_bfd_open (name), add_flags, addrs, - flags, NULL); + bfd *bfd = symfile_bfd_open (name); + struct cleanup *cleanup = make_cleanup_bfd_unref (bfd); + struct objfile *objf; + + objf = symbol_file_add_from_bfd (bfd, add_flags, addrs, flags, NULL); + do_cleanups (cleanup); + return objf; } @@ -1350,7 +1352,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, if (filename_cmp (name, parent_objfile->name) == 0) return 0; - abfd = bfd_open_maybe_remote (name); + abfd = gdb_bfd_open_maybe_remote (name); if (!abfd) return 0; @@ -1372,7 +1374,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, if (abfd_stat.st_dev == parent_stat.st_dev && abfd_stat.st_ino == parent_stat.st_ino) { - bfd_close (abfd); + gdb_bfd_unref (abfd); return 0; } verified_as_different = 1; @@ -1382,7 +1384,7 @@ separate_debug_file_exists (const char *name, unsigned long crc, file_crc_p = get_file_crc (abfd, &file_crc); - bfd_close (abfd); + gdb_bfd_unref (abfd); if (!file_crc_p) return 0; @@ -1690,15 +1692,20 @@ set_initial_language (void) } /* If NAME is a remote name open the file using remote protocol, otherwise - open it normally. */ + open it normally. Returns a new reference to the BFD. On error, + returns NULL with the BFD error set. */ bfd * -bfd_open_maybe_remote (const char *name) +gdb_bfd_open_maybe_remote (const char *name) { + bfd *result; + if (remote_filename_p (name)) - return remote_bfd_open (name, gnutarget); + result = remote_bfd_open (name, gnutarget); else - return bfd_openr (name, gnutarget); + result = gdb_bfd_openr (name, gnutarget); + + return result; } @@ -1716,19 +1723,14 @@ symfile_bfd_open (char *name) if (remote_filename_p (name)) { - name = xstrdup (name); sym_bfd = remote_bfd_open (name, gnutarget); if (!sym_bfd) - { - make_cleanup (xfree, name); - error (_("`%s': can't open to read symbols: %s."), name, - bfd_errmsg (bfd_get_error ())); - } + error (_("`%s': can't open to read symbols: %s."), name, + bfd_errmsg (bfd_get_error ())); if (!bfd_check_format (sym_bfd, bfd_object)) { - bfd_close (sym_bfd); - make_cleanup (xfree, name); + make_cleanup_bfd_unref (sym_bfd); error (_("`%s': can't read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); } @@ -1757,12 +1759,11 @@ symfile_bfd_open (char *name) perror_with_name (name); } - /* Free 1st new malloc'd copy, but keep the 2nd malloc'd copy in - bfd. It'll be freed in free_objfile(). */ xfree (name); name = absolute_name; + make_cleanup (xfree, name); - sym_bfd = bfd_fopen (name, gnutarget, FOPEN_RB, desc); + sym_bfd = gdb_bfd_fopen (name, gnutarget, FOPEN_RB, desc); if (!sym_bfd) { make_cleanup (xfree, name); @@ -1773,18 +1774,11 @@ symfile_bfd_open (char *name) if (!bfd_check_format (sym_bfd, bfd_object)) { - /* FIXME: should be checking for errors from bfd_close (for one - thing, on error it does not free all the storage associated - with the bfd). */ - bfd_close (sym_bfd); /* This also closes desc. */ - make_cleanup (xfree, name); + make_cleanup_bfd_unref (sym_bfd); error (_("`%s': can't read symbols: %s."), name, bfd_errmsg (bfd_get_error ())); } - /* bfd_usrdata exists for applications and libbfd must not touch it. */ - gdb_assert (bfd_usrdata (sym_bfd) == NULL); - return sym_bfd; } @@ -2109,17 +2103,14 @@ generic_load (char *args, int from_tty) } /* Open the file for loading. */ - loadfile_bfd = bfd_openr (filename, gnutarget); + loadfile_bfd = gdb_bfd_openr (filename, gnutarget); if (loadfile_bfd == NULL) { perror_with_name (filename); return; } - /* FIXME: should be checking for errors from bfd_close (for one thing, - on error it does not free all the storage associated with the - bfd). */ - make_cleanup_bfd_close (loadfile_bfd); + make_cleanup_bfd_unref (loadfile_bfd); if (!bfd_check_format (loadfile_bfd, bfd_object)) { @@ -2518,15 +2509,18 @@ reread_symbols (void) /* Clean up any state BFD has sitting around. We don't need to close the descriptor but BFD lacks a way of closing the BFD without closing the descriptor. */ - obfd_filename = bfd_get_filename (objfile->obfd); - if (!bfd_close (objfile->obfd)) - error (_("Can't close BFD for %s: %s"), objfile->name, - bfd_errmsg (bfd_get_error ())); - objfile->obfd = bfd_open_maybe_remote (obfd_filename); + { + struct bfd *obfd = objfile->obfd; + + obfd_filename = bfd_get_filename (objfile->obfd); + /* Open the new BFD before freeing the old one, so that + the filename remains live. */ + objfile->obfd = gdb_bfd_open_maybe_remote (obfd_filename); + gdb_bfd_unref (obfd); + } + if (objfile->obfd == NULL) error (_("Can't open %s to read symbols."), objfile->name); - else - objfile->obfd = gdb_bfd_ref (objfile->obfd); /* bfd_openr sets cacheable to true, which is what we want. */ if (!bfd_check_format (objfile->obfd, bfd_object)) error (_("Can't read symbols from %s: %s."), objfile->name, diff --git a/gdb/symfile.h b/gdb/symfile.h index aca7359..184a83e 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -553,7 +553,7 @@ extern void find_lowest_section (bfd *, asection *, void *); extern bfd *symfile_bfd_open (char *); -extern bfd *bfd_open_maybe_remote (const char *); +extern bfd *gdb_bfd_open_maybe_remote (const char *); extern int get_section_index (struct objfile *, char *); diff --git a/gdb/testsuite/gdb.ada/packed_array.exp b/gdb/testsuite/gdb.ada/packed_array.exp index 678639c..47a2202 100644 --- a/gdb/testsuite/gdb.ada/packed_array.exp +++ b/gdb/testsuite/gdb.ada/packed_array.exp @@ -60,5 +60,11 @@ gdb_test_multiple "$test" "$test" { # are. Observed with (FSF GNU Ada 4.5.3 20110124). xfail $test } + -re "= \\(\\)\[\r\n\]+$gdb_prompt $" { + # archer-jankratochvil-vla resolves it as a dynamic type resolved as an + # empty array [0..-1]. + # DW_AT_upper_bound : (DW_OP_fbreg: -48; DW_OP_deref) + xfail $test + } } diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S new file mode 100644 index 0000000..83faaf6 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer-foo.S @@ -0,0 +1,457 @@ + .file "x86_64-vla-pointer.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl foo + .type foo, @function +foo: +.LFB2: + .file 1 "x86_64-vla-pointer.c" + .loc 1 22 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $64, %rsp +.LCFI2: + movl %edi, -36(%rbp) + .loc 1 22 0 + movq %rsp, %rax + movq %rax, -48(%rbp) + .loc 1 23 0 + movl -36(%rbp), %edx + movslq %edx,%rax + subq $1, %rax + movq %rax, -24(%rbp) + .loc 1 24 0 + movslq %edx,%rax + addq $15, %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + subq %rax, %rsp + movq %rsp, -56(%rbp) + movq -56(%rbp), %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + movq %rax, -56(%rbp) + movq -56(%rbp), %rax + movq %rax, -16(%rbp) + .loc 1 27 0 + movl $0, -4(%rbp) + jmp .L2 +.L3: + .loc 1 28 0 + movl -4(%rbp), %esi + movl -4(%rbp), %eax + movl %eax, %ecx + movq -16(%rbp), %rdx + movslq %esi,%rax + movb %cl, (%rdx,%rax) + .loc 1 27 0 + addl $1, -4(%rbp) +.L2: + movl -4(%rbp), %eax + cmpl -36(%rbp), %eax + jl .L3 + .loc 1 30 0 + .globl break_here +break_here: + movq -16(%rbp), %rax + movb $0, (%rax) + movq -48(%rbp), %rsp + .loc 1 31 0 + leave + ret +.LFE2: + .size foo, .-foo + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE0: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .text +.Letext0: + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB2-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad 0x0 + .quad 0x0 + .section .debug_info +.Ldebug_relative: + .long .Ldebug_end - .Ldebug_start +.Ldebug_start: + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .string "foo" + .byte 0x1 + .byte 0x16 + .byte 0x1 + .quad .LFB2 + .quad .LFE2 + .long .LLST0 + .long .Ltype_int - .Ldebug_relative + .uleb128 0x3 + .long .LASF5 + .byte 0x1 + .byte 0x15 + .long .Ltype_int - .Ldebug_relative + .byte 0x2 + .byte 0x91 + .sleb128 -52 +.Ltag_pointer: + .uleb128 0x4 + .byte 0x8 /* DW_AT_byte_size */ + .long .Ltag_array_type - .debug_info /* DW_AT_type */ + .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ + .long .LASF0 + .byte 0x1 + .byte 0x18 +#if 1 + .long .Ltag_pointer - .debug_info +#else + /* Debugging only: Skip the typedef indirection. */ + .long .Ltag_array_type - .debug_info +#endif + /* DW_AT_location: DW_FORM_block1: start */ + .byte 0x3 + .byte 0x91 + .sleb128 -32 +#if 0 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif + /* DW_AT_location: DW_FORM_block1: end */ + .uleb128 0x6 + .string "i" + .byte 0x1 + .byte 0x19 + .long .Ltype_int - .Ldebug_relative + .byte 0x2 + .byte 0x91 + .sleb128 -20 + .byte 0x0 +.Ltype_int: + .uleb128 0x7 + .byte 0x4 + .byte 0x5 + .string "int" +.Ltag_array_type: + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .long .Ltype_char - .Ldebug_relative + .long .Ltype_ulong - .Ldebug_relative /* DW_AT_sibling: DW_FORM_ref4 */ +1: /* DW_AT_data_location: DW_FORM_block1: start */ + .byte 2f - 3f /* length */ +3: + .byte 0x97 /* DW_OP_push_object_address */ +#if 1 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif +2: /* DW_AT_data_location: DW_FORM_block1: end */ + .uleb128 0x9 + .long .Ltype_char - .Ldebug_relative /* DW_AT_type: DW_FORM_ref4 */ + .byte 0x3 + .byte 0x91 + .sleb128 -40 + .byte 0x6 + .byte 0x0 +.Ltype_ulong: + .uleb128 0xa + .byte 0x8 + .byte 0x7 +.Ltype_char: + .uleb128 0xb + .byte 0x1 + .byte 0x6 + .long .LASF1 + .byte 0x0 +.Ldebug_end: + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 /* .Ltag_pointer abbrev */ + .uleb128 0x0f /* DW_TAG_pointer_type */ + .byte 0x0 + .uleb128 0x0b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x6 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .uleb128 0x1 + .byte 0x1 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x1 /* DW_AT_sibling */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x50 /* DW_AT_data_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 + .byte 0x0 + .uleb128 0x9 + .uleb128 0x21 + .byte 0x0 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2f + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0xa + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0xb + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .long 0x16 + .value 0x2 + .long .Ldebug_info0 + .long 0xa8 + .long 0x2d + .string "foo" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0x0 + .value 0x0 + .value 0x0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0x0 + .quad 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "array" +.LASF5: + .string "size" +.LASF3: + .string "x86_64-vla-pointer.c" +.LASF6: + .string "array_t" +.LASF1: + .string "char" +.LASF4: + .string "gdb.arch" +.LASF2: + .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" + .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c new file mode 100644 index 0000000..fe2c8f7 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#if 0 + +void +foo (int size) +{ + typedef char array_t[size]; + array_t array; + int i; + + for (i = 0; i < size; i++) + array[i] = i; + + array[0] = 0; /* break-here */ +} + +#else + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp new file mode 100644 index 0000000..d243cf1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-pointer.exp @@ -0,0 +1,66 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if ![istarget "x86_64-*-*"] then { + verbose "Skipping over gdb.arch/x86_64-vla-pointer.exp test made only for x86_64." + return +} + +set testfile x86_64-vla-pointer +set srcasmfile ${testfile}-foo.S +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set binobjfile ${objdir}/${subdir}/${testfile}-foo.o +if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { + untested "Couldn't compile test program" + return -1 +} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested x86_64-vla-pointer + return -1 +} + +gdb_breakpoint "break_here" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "first: whatis array" +gdb_test "ptype array" "type = char \\(\\*\\)\\\[26\\\]" "first: ptype array" + +gdb_test "whatis *array" "type = char \\\[26\\\]" "first: whatis *array" +gdb_test "ptype *array" "type = char \\\[26\\\]" "first: ptype *array" + +gdb_test "p (*array)\[1\]" "\\$\[0-9\] = 1 '\\\\001'" +gdb_test "p (*array)\[2\]" "\\$\[0-9\] = 2 '\\\\002'" +gdb_test "p (*array)\[3\]" "\\$\[0-9\] = 3 '\\\\003'" +gdb_test "p (*array)\[4\]" "\\$\[0-9\] = 4 '\\\\004'" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = char \\(\\*\\)\\\[variable\\\]" "second: whatis array" +gdb_test "ptype array" "type = char \\(\\*\\)\\\[78\\\]" "second: ptype array" + +gdb_test "whatis *array" "type = char \\\[78\\\]" "second: whatis *array" +gdb_test "ptype *array" "type = char \\\[78\\\]" "second: ptype *array" diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S new file mode 100644 index 0000000..66f7a39 --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef-foo.S @@ -0,0 +1,455 @@ + .file "x86_64-vla-typedef.c" + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: +.globl foo + .type foo, @function +foo: +.LFB2: + .file 1 "x86_64-vla-typedef.c" + .loc 1 22 0 + pushq %rbp +.LCFI0: + movq %rsp, %rbp +.LCFI1: + subq $64, %rsp +.LCFI2: + movl %edi, -36(%rbp) + .loc 1 22 0 + movq %rsp, %rax + movq %rax, -48(%rbp) + .loc 1 23 0 + movl -36(%rbp), %edx + movslq %edx,%rax + subq $1, %rax + movq %rax, -24(%rbp) + .loc 1 24 0 + movslq %edx,%rax + addq $15, %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + subq %rax, %rsp + movq %rsp, -56(%rbp) + movq -56(%rbp), %rax + addq $15, %rax + shrq $4, %rax + salq $4, %rax + movq %rax, -56(%rbp) + movq -56(%rbp), %rax + movq %rax, -16(%rbp) + .loc 1 27 0 + movl $0, -4(%rbp) + jmp .L2 +.L3: + .loc 1 28 0 + movl -4(%rbp), %esi + movl -4(%rbp), %eax + movl %eax, %ecx + movq -16(%rbp), %rdx + movslq %esi,%rax + movb %cl, (%rdx,%rax) + .loc 1 27 0 + addl $1, -4(%rbp) +.L2: + movl -4(%rbp), %eax + cmpl -36(%rbp), %eax + jl .L3 + .loc 1 30 0 + .globl break_here +break_here: + movq -16(%rbp), %rax + movb $0, (%rax) + movq -48(%rbp), %rsp + .loc 1 31 0 + leave + ret +.LFE2: + .size foo, .-foo + .section .debug_frame,"",@progbits +.Lframe0: + .long .LECIE0-.LSCIE0 +.LSCIE0: + .long 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE0: +.LSFDE0: + .long .LEFDE0-.LASFDE0 +.LASFDE0: + .long .Lframe0 + .quad .LFB2 + .quad .LFE2-.LFB2 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE0: + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 +.LSCIE1: + .long 0x0 + .byte 0x1 + .string "zR" + .uleb128 0x1 + .sleb128 -8 + .byte 0x10 + .uleb128 0x1 + .byte 0x3 + .byte 0xc + .uleb128 0x7 + .uleb128 0x8 + .byte 0x90 + .uleb128 0x1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 +.LASFDE1: + .long .LASFDE1-.Lframe1 + .long .LFB2 + .long .LFE2-.LFB2 + .uleb128 0x0 + .byte 0x4 + .long .LCFI0-.LFB2 + .byte 0xe + .uleb128 0x10 + .byte 0x86 + .uleb128 0x2 + .byte 0x4 + .long .LCFI1-.LCFI0 + .byte 0xd + .uleb128 0x6 + .align 8 +.LEFDE1: + .text +.Letext0: + .section .debug_loc,"",@progbits +.Ldebug_loc0: +.LLST0: + .quad .LFB2-.Ltext0 + .quad .LCFI0-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 8 + .quad .LCFI0-.Ltext0 + .quad .LCFI1-.Ltext0 + .value 0x2 + .byte 0x77 + .sleb128 16 + .quad .LCFI1-.Ltext0 + .quad .LFE2-.Ltext0 + .value 0x2 + .byte 0x76 + .sleb128 16 + .quad 0x0 + .quad 0x0 + .section .debug_info + .long .Ldebug_end - .Ldebug_start +.Ldebug_start: + .value 0x2 + .long .Ldebug_abbrev0 + .byte 0x8 + .uleb128 0x1 + .long .LASF2 + .byte 0x1 + .long .LASF3 + .long .LASF4 + .quad .Ltext0 + .quad .Letext0 + .long .Ldebug_line0 + .uleb128 0x2 + .byte 0x1 + .string "foo" + .byte 0x1 + .byte 0x16 + .byte 0x1 + .quad .LFB2 + .quad .LFE2 + .long .LLST0 + .long 0x83 + .uleb128 0x3 + .long .LASF5 + .byte 0x1 + .byte 0x15 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -52 +.Ltag_typedef: + .uleb128 0x4 + .long .LASF6 + .byte 0x1 + .byte 0x17 + .long .Ltag_array_type - .debug_info + .uleb128 0x5 /* Abbrev Number: 5 (DW_TAG_variable) */ + .long .LASF0 + .byte 0x1 + .byte 0x18 +#if 1 + .long .Ltag_typedef - .debug_info +#else + /* Debugging only: Skip the typedef indirection. */ + .long .Ltag_array_type - .debug_info +#endif + /* DW_AT_location: DW_FORM_block1: start */ + .byte 0x3 + .byte 0x91 + .sleb128 -32 +#if 0 + .byte 0x6 /* DW_OP_deref */ +#else + .byte 0x96 /* DW_OP_nop */ +#endif + /* DW_AT_location: DW_FORM_block1: end */ + .uleb128 0x6 + .string "i" + .byte 0x1 + .byte 0x19 + .long 0x83 + .byte 0x2 + .byte 0x91 + .sleb128 -20 + .byte 0x0 + .uleb128 0x7 + .byte 0x4 + .byte 0x5 + .string "int" +.Ltag_array_type: + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .long 0xa0 + (2f - 1f) /* DW_AT_type: DW_FORM_ref4 */ + .long 0x9d + (2f - 1f) /* DW_AT_sibling: DW_FORM_ref4 */ +1: /* DW_AT_data_location: DW_FORM_block1: start */ + .byte 2f - 3f /* length */ +3: + .byte 0x97 /* DW_OP_push_object_address */ + .byte 0x6 /* DW_OP_deref */ +2: /* DW_AT_data_location: DW_FORM_block1: end */ + .uleb128 0x9 + .long 0x9d + (2b - 1b) /* DW_AT_type: DW_FORM_ref4 */ + .byte 0x3 + .byte 0x91 + .sleb128 -40 + .byte 0x6 + .byte 0x0 + .uleb128 0xa + .byte 0x8 + .byte 0x7 + .uleb128 0xb + .byte 0x1 + .byte 0x6 + .long .LASF1 + .byte 0x0 +.Ldebug_end: + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x25 + .uleb128 0xe + .uleb128 0x13 + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x1b + .uleb128 0xe + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x10 + .uleb128 0x6 + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0x6 + .uleb128 0x1 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 + .uleb128 0x16 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .byte 0x0 + .byte 0x0 + .uleb128 0x5 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0xe + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x6 + .uleb128 0x34 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x7 + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0x8 + .byte 0x0 + .byte 0x0 + .uleb128 0x8 /* Abbrev Number: 8 (DW_TAG_array_type) */ + .uleb128 0x1 + .byte 0x1 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x1 /* DW_AT_sibling */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x50 /* DW_AT_data_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 + .byte 0x0 + .uleb128 0x9 + .uleb128 0x21 + .byte 0x0 + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x2f + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0xa + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0xb + .uleb128 0x24 + .byte 0x0 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .uleb128 0x3 + .uleb128 0xe + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .long 0x16 + .value 0x2 + .long .Ldebug_info0 + .long 0xa8 + .long 0x2d + .string "foo" + .long 0x0 + .section .debug_aranges,"",@progbits + .long 0x2c + .value 0x2 + .long .Ldebug_info0 + .byte 0x8 + .byte 0x0 + .value 0x0 + .value 0x0 + .quad .Ltext0 + .quad .Letext0-.Ltext0 + .quad 0x0 + .quad 0x0 + .section .debug_str,"MS",@progbits,1 +.LASF0: + .string "array" +.LASF5: + .string "size" +.LASF3: + .string "x86_64-vla-typedef.c" +.LASF6: + .string "array_t" +.LASF1: + .string "char" +.LASF4: + .string "gdb.arch" +.LASF2: + .string "GNU C 4.3.2 20081105 (Red Hat 4.3.2-7)" + .ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)" + .section .note.GNU-stack,"",@progbits diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c new file mode 100644 index 0000000..b809c4e --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#if 0 + +void +foo (int size) +{ + typedef char array_t[size]; + array_t array; + int i; + + for (i = 0; i < size; i++) + array[i] = i; + + array[0] = 0; /* break-here */ +} + +#else + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} + +#endif diff --git a/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp new file mode 100644 index 0000000..b05411e --- /dev/null +++ b/gdb/testsuite/gdb.arch/x86_64-vla-typedef.exp @@ -0,0 +1,64 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test DW_AT_data_location accessed through DW_TAG_typedef intermediate. + +if ![istarget "x86_64-*-*"] then { + verbose "Skipping over gdb.arch/x86_64-vla-typedef.exp test made only for x86_64." + return +} + +set testfile x86_64-vla-typedef +set srcasmfile ${testfile}-foo.S +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set binobjfile ${objdir}/${subdir}/${testfile}-foo.o +if { [gdb_compile "${srcdir}/${subdir}/${srcasmfile}" "${binobjfile}" object {}] != "" } { + untested "Couldn't compile test program" + return -1 +} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${binobjfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested x86_64-vla-typedef + return -1 +} + +gdb_breakpoint "break_here" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = array_t" "first: whatis array" + +gdb_test "ptype array" "type = char \\\[26\\\]" "first: ptype array" + +gdb_test "p array\[1\]" "\\$\[0-9\] = 1 '\\\\001'" +gdb_test "p array\[2\]" "\\$\[0-9\] = 2 '\\\\002'" +gdb_test "p array\[3\]" "\\$\[0-9\] = 3 '\\\\003'" +gdb_test "p array\[4\]" "\\$\[0-9\] = 4 '\\\\004'" + +gdb_continue_to_breakpoint "break_here" + +gdb_test "whatis array" "type = array_t" "second: whatis array" + +gdb_test "ptype array" "type = char \\\[78\\\]" "second: ptype array" diff --git a/gdb/testsuite/gdb.base/arrayidx.c b/gdb/testsuite/gdb.base/arrayidx.c index a99137e..c3dc2d9 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 cba0024..0dc0e46 100644 --- a/gdb/testsuite/gdb.base/arrayidx.exp +++ b/gdb/testsuite/gdb.base/arrayidx.exp @@ -53,4 +53,12 @@ gdb_test "print array" \ "\\{\\\[0\\\] = 1, \\\[1\\\] = 2, \\\[2\\\] = 3, \\\[3\\\] = 4\\}" \ "Print array with array-indexes on" - +set test "p unbound.a == &unbound.a\[0\]" +gdb_test_multiple $test $test { + -re " = 1\r\n$gdb_prompt $" { + pass $test + } + -re "No symbol \"unbound\" in current context.\r\n$gdb_prompt $" { + unsupported "$test (no GCC)" + } +} diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.c b/gdb/testsuite/gdb.base/internal-var-field-address.c new file mode 100644 index 0000000..eeb7b85 --- /dev/null +++ b/gdb/testsuite/gdb.base/internal-var-field-address.c @@ -0,0 +1,20 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +struct { + int field; +} staticstruct = { 1 }; diff --git a/gdb/testsuite/gdb.base/internal-var-field-address.exp b/gdb/testsuite/gdb.base/internal-var-field-address.exp new file mode 100644 index 0000000..6d82e73 --- /dev/null +++ b/gdb/testsuite/gdb.base/internal-var-field-address.exp @@ -0,0 +1,26 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set test internal-var-field-address +set binfile ${test}.x +if { [gdb_compile "${srcdir}/${subdir}/${test}.c" "${objdir}/${subdir}/${binfile}" object {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +clean_restart $binfile + +gdb_test {set $varstruct = staticstruct} +gdb_test {p $varstruct.field} " = 1" diff --git a/gdb/testsuite/gdb.base/vla-frame.c b/gdb/testsuite/gdb.base/vla-frame.c new file mode 100644 index 0000000..5750f68 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-frame.c @@ -0,0 +1,31 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +int +main (int argc, char **argv) +{ + char s[2 + argc]; + void (*f) (char *) = 0; + + memset (s, 0, sizeof (s)); + s[0] = 'X'; + + f (s); + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla-frame.exp b/gdb/testsuite/gdb.base/vla-frame.exp new file mode 100644 index 0000000..47736c7 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-frame.exp @@ -0,0 +1,38 @@ +# Copyright 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set testfile vla-frame +set executable ${testfile} + +if { [prepare_for_testing ${testfile}.exp ${executable}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +set test "continue" +gdb_test_multiple $test $test { + -re "Continuing\\.\r\n\r\nProgram received signal SIGSEGV, Segmentation fault\\.\r\n0x0+ in \\?\\? \\(\\)\r\n$gdb_prompt $" { + pass $test + } + -re "\r\n$gdb_prompt $" { + untested ${testfile}.exp + return + } +} + +gdb_test "bt full" "\r\n +s = \"X\\\\000\"\r\n.*" diff --git a/gdb/testsuite/gdb.base/vla-overflow.c b/gdb/testsuite/gdb.base/vla-overflow.c new file mode 100644 index 0000000..c5d5ee0 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla-overflow.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +int +main (int argc, char **argv) +{ + int array[argc]; + + array[0] = array[0]; + + abort (); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla-overflow.exp b/gdb/testsuite/gdb.base/vla-overflow.exp new file mode 100644 index 0000000..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 <http://www.gnu.org/licenses/>. + +# We could crash in: +# #0 block_linkage_function (bl=0x0) at ../../gdb/block.c:69 +# #1 in dwarf_block_get_frame_base (...) at ../../gdb/dwarf2block.c:97 +# 97 framefunc = block_linkage_function (get_frame_block (frame, NULL)); +# #2 in execute_stack_op (...) at ../../gdb/dwarf2expr.c:496 +# #3 in dwarf_block_exec_core () at ../../gdb/dwarf2block.c:156 +# #4 dwarf_block_exec (...) at ../../gdb/dwarf2block.c:206 +# #5 in range_type_count_bound_internal (...) at ../../gdb/gdbtypes.c:1430 +# #6 in create_array_type (...) at ../../gdb/gdbtypes.c:840 +# ... +# #21 in psymtab_to_symtab (...) at ../../gdb/symfile.c:292 +# ... +# #29 in backtrace_command_1 () at ../../gdb/stack.c:1273 + +set testfile vla-overflow +set shfile ${objdir}/${subdir}/${testfile}-gdb.sh +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +set f [open "|getconf PAGESIZE" "r"] +gets $f pagesize +close $f + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set pid_of_gdb [exp_pid -i [board_info host fileid]] + +if { [runto_main] < 0 } { + untested vla-overflow + return -1 +} + +# Get the GDB memory size when we stay at main. + +proc memory_v_pages_get {} { + global pid_of_gdb pagesize + set fd [open "/proc/$pid_of_gdb/statm"] + gets $fd line + close $fd + # number of pages of virtual memory + scan $line "%d" drs + return $drs +} + +set pages_found [memory_v_pages_get] + +# 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 <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +void +marker (void) +{ +} + +void +bar (char *a, char *b, char *c, int size) +{ + memset (a, '1', size); + memset (b, '2', size); + memset (c, '3', 48); +} + +void +foo (int size) +{ + char temp1[size]; + char temp3[48]; + + temp1[size - 1] = '\0'; + { + char temp2[size]; + + bar (temp1, temp2, temp3, size); + + marker (); /* break-here */ + } +} + +int +main (void) +{ + foo (26); + foo (78); + return 0; +} diff --git a/gdb/testsuite/gdb.base/vla.exp b/gdb/testsuite/gdb.base/vla.exp new file mode 100644 index 0000000..5da7378 --- /dev/null +++ b/gdb/testsuite/gdb.base/vla.exp @@ -0,0 +1,62 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set testfile vla +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto_main] { + untested vla + return -1 +} + +gdb_breakpoint [gdb_get_line_number "break-here"] + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "first: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "first: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "first: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[26\\\]" "first: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[26\\\]" "first: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "first: ptype temp3" + +gdb_test "p temp1" " = '1' <repeats 26 times>" "first: print temp1" +gdb_test "p temp2" " = '2' <repeats 26 times>" "first: print temp2" +gdb_test "p temp3" " = '3' <repeats 48 times>" "first: print temp3" + +gdb_continue_to_breakpoint "break-here" + +gdb_test "whatis temp1" "type = char \\\[variable\\\]" "second: whatis temp1" +gdb_test "whatis temp2" "type = char \\\[variable\\\]" "second: whatis temp2" +gdb_test "whatis temp3" "type = char \\\[48\\\]" "second: whatis temp3" + +gdb_test "ptype temp1" "type = char \\\[78\\\]" "second: ptype temp1" +gdb_test "ptype temp2" "type = char \\\[78\\\]" "second: ptype temp2" +gdb_test "ptype temp3" "type = char \\\[48\\\]" "second: ptype temp3" + +gdb_test "p temp1" " = '1' <repeats 78 times>" "second: print temp1" +gdb_test "p temp2" " = '2' <repeats 78 times>" "second: print temp2" +gdb_test "p temp3" " = '3' <repeats 48 times>" "second: print temp3" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S new file mode 100644 index 0000000..aac3baa --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.S @@ -0,0 +1,246 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +/* 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 */ + + /* DW_AT_upper_bound is referencing register. */ +.Larrayreg_type: + .uleb128 2 /* Abbrev: DW_TAG_array_type */ + .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */ + + .uleb128 8 /* Abbrev: DW_TAG_subrange_type with block */ + .4byte .Luint_type-.Lcu1_begin /* DW_AT_type */ + .byte 0 /* DW_AT_lower_bound */ + .byte 2f - 1f /* DW_AT_upper_bound */ +1: .byte 0x50 /* DW_OP_reg0 */ +2: + .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 /* <addr> */ +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 /* <addr> */ +2: + + /* DW_AT_upper_bound is referencing register. */ + .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */ + .string "reg_string" /* DW_AT_name */ + .4byte .Larrayreg_type-.Lcu1_begin /* DW_AT_type */ + .byte 2f - 1f /* DW_AT_location */ +1: .byte 3 /* DW_OP_addr */ + .4byte vardata /* <addr> */ +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 */ + + .uleb128 8 /* Abbrev code */ + .uleb128 0x21 /* DW_TAG_subrange_type with block */ + .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 0xa /* DW_FORM_block1 */ + .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..815ed93 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-bound-loclist.exp @@ -0,0 +1,54 @@ +# 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 <http://www.gnu.org/licenses/>. + +# 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 \[\]} + +# The register contains unpredictable value - the array size. +gdb_test "ptype reg_string" {type = char \[-?[0-9]+\]} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.c b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c new file mode 100644 index 0000000..1f02d90 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.c @@ -0,0 +1,42 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + +/* The function `func1' traced into must have debug info on offset > 0; + (DW_UNSND (attr)). This is the reason of `func0' existence. */ + +void +func0(int a, int b) +{ +} + +/* `func1' being traced into must have some arguments to dump. */ + +void +func1(int a, int b) +{ + func0 (a,b); +} + +int +main(void) +{ + func1 (1, 2); + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp new file mode 100644 index 0000000..1c6e84a --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-stripped.exp @@ -0,0 +1,79 @@ +# Copyright 2006 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Minimal DWARF-2 unit test + +# This test can only be run on targets which support DWARF-2. +# For now pick a sampling of likely targets. +if {![istarget *-*-linux*] + && ![istarget *-*-gnu*] + && ![istarget *-*-elf*] + && ![istarget *-*-openbsd*] + && ![istarget arm-*-eabi*] + && ![istarget powerpc-*-eabi*]} { + return 0 +} + +set testfile "dw2-stripped" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile}.x + +remote_exec build "rm -f ${binfile}" + +# get the value of gcc_compiled +if [get_compiler_info ${binfile}] { + return -1 +} + +# This test can only be run on gcc as we use additional_flags=FIXME +if {$gcc_compiled == 0} { + return 0 +} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-ggdb3}] != "" } { + return -1 +} + +remote_exec build "objcopy -R .debug_loc ${binfile}" +set strip_output [remote_exec build "objdump -h ${binfile}"] + +set test "stripping test file preservation" +if [ regexp ".debug_info " $strip_output] { + pass "$test (.debug_info preserved)" +} else { + fail "$test (.debug_info got also stripped)" +} + +set test "stripping test file functionality" +if [ regexp ".debug_loc " $strip_output] { + fail "$test (.debug_loc still present)" +} else { + pass "$test (.debug_loc stripped)" +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# For C programs, "start" should stop in main(). + +gdb_test "start" \ + ".*main \\(\\) at .*" \ + "start" +gdb_test "step" \ + "func.* \\(.*\\) at .*" \ + "step" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S new file mode 100644 index 0000000..5fcdd84 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.S @@ -0,0 +1,83 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Debug information */ + + .section .debug_info +.Lcu1_begin: + /* CU header */ + .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */ +.Lcu1_start: + .2byte 2 /* DWARF Version */ + .4byte .Labbrev1_begin /* Offset into abbrev section */ + .byte 4 /* Pointer size */ + + /* CU die */ + .uleb128 1 /* Abbrev: DW_TAG_compile_unit */ + .ascii "dw2-struct-member-data-location.c\0" /* DW_AT_name */ + .ascii "GNU C 4.3.2\0" /* DW_AT_producer */ + .byte 1 /* DW_AT_language (C) */ + +.Ltype_uchar: + .uleb128 2 /* Abbrev: DW_TAG_structure_type */ + .ascii "some_struct\0" /* DW_AT_name */ + + .uleb128 3 /* Abbrev: DW_TAG_member */ + .ascii "field\0" /* DW_AT_name */ + .byte 0 /* DW_AT_data_member_location */ + + .byte 0 /* End of children of some_struct */ + + .byte 0 /* End of children of CU */ + +.Lcu1_end: + +/* Abbrev table */ + .section .debug_abbrev +.Labbrev1_begin: + .uleb128 1 /* Abbrev code */ + .uleb128 0x11 /* DW_TAG_compile_unit */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x25 /* DW_AT_producer */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x13 /* DW_AT_language */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 2 /* Abbrev code */ + .uleb128 0x13 /* DW_TAG_structure_type */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 3 /* Abbrev code */ + .uleb128 0x0d /* DW_TAG_member */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x38 /* DW_AT_data_member_location */ + .uleb128 0x0b /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp new file mode 100644 index 0000000..c41151c --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-struct-member-data-location.exp @@ -0,0 +1,37 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This test can only be run on targets which support DWARF-2 and use gas. +# For now pick a sampling of likely targets. +if {![istarget *-*-linux*] + && ![istarget *-*-gnu*] + && ![istarget *-*-elf*] + && ![istarget *-*-openbsd*] + && ![istarget arm-*-eabi*] + && ![istarget powerpc-*-eabi*]} { + return 0 +} + +set testfile "dw2-struct-member-data-location" +set srcfile ${testfile}.S +set binfile ${testfile}.x + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${objdir}/${subdir}/${binfile}" object {nodebug}] != "" } { + return -1 +} + +clean_restart $binfile + +gdb_test "ptype struct some_struct" "type = struct some_struct {\[\r\n \t\]*void field;\[\r\n \t\]*}" diff --git a/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.S b/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.S new file mode 100644 index 0000000..9dbbf3c --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.S @@ -0,0 +1,121 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Debug information */ + + .section .data +vardata: + .rept 129 + .ascii "x" + .endr + .ascii "UNSEEN\0" + + .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 */ + .ascii "GNU C 3.3.3\0" /* DW_AT_producer */ + .byte 2 /* DW_AT_language (C) - */ + +.Larray_type: + .uleb128 2 /* Abbrev: DW_TAG_array_type */ + .4byte .Lchar_type-.Lcu1_begin /* DW_AT_type */ + + .uleb128 8 /* Abbrev: DW_TAG_subrange_type without DW_AT_type */ + .byte 0 /* DW_AT_lower_bound */ + .byte 128 /* DW_AT_upper_bound */ + + .byte 0 /* End of children of die */ + +.Lchar_type: + .uleb128 4 /* Abbrev: DW_TAG_base_type */ + .ascii "char\0" /* DW_AT_name */ + .byte 1 /* DW_AT_byte_size */ + .byte 6 /* DW_AT_encoding */ + + .uleb128 6 /* Abbrev: DW_TAG_variable DW_FORM_string */ + .ascii "notype_string\0" /* 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 /* <addr> */ +2: + + .byte 0 /* End of children of CU */ +.Lcu1_end: + + .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 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 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 4 /* Abbrev code */ + .uleb128 0x24 /* DW_TAG_base_type */ + .byte 0x0 /* no_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0xb /* DW_AT_byte_size */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x3e /* DW_AT_encoding */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 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 8 /* Abbrev code */ + .uleb128 0x21 /* DW_TAG_subrange_type without DW_AT_type */ + .byte 0x0 /* no children */ + .uleb128 0x22 /* DW_AT_lower_bound */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x2f /* DW_AT_upper_bound */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .byte 0x0 /* Terminator */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.exp b/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.exp new file mode 100644 index 0000000..a13e346 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-subrange-no-type.exp @@ -0,0 +1,39 @@ +# Copyright 2012 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +load_lib dwarf.exp + +# https://bugzilla.redhat.com/show_bug.cgi?id=806920 +# read_subrange_type <TYPE_CODE (base_type) == TYPE_CODE_VOID> reinitialization +# of BASE_TYPE was done too late, it affects DW_TAG_subrange_type without +# specified DW_AT_type, present only in XLF produced code. + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +set testfile dw2-subrange-no-type +set srcfile ${testfile}.S +set executable ${testfile}.x +set binfile ${objdir}/${subdir}/${executable} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" object {}] != "" } { + return -1 +} + +clean_restart $executable + +gdb_test "ptype notype_string" {type = char \[129\]} +gdb_test "p notype_string" " = 'x' <repeats 129 times>" diff --git a/gdb/testsuite/gdb.fortran/dwarf-stride.exp b/gdb/testsuite/gdb.fortran/dwarf-stride.exp new file mode 100644 index 0000000..d7b8bea --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dwarf-stride.exp @@ -0,0 +1,42 @@ +# Copyright 2009 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>. + +# This file is part of the gdb testsuite. Array element stride must not be +# specified in the number of elements but in a number of bytes instead. +# Original problem: +# (gdb) p c40pt(1) +# $1 = '0-hello', ' ' <repeats 33 times> +# (gdb) p c40pt(2) +# warning: Fortran array stride not divisible by the element size + +set testfile dwarf-stride +set srcfile ${testfile}.f90 + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f90}] } { + 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-other-frame-stub.f90 b/gdb/testsuite/gdb.fortran/dynamic-other-frame-stub.f90 new file mode 100644 index 0000000..261ce17 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame-stub.f90 @@ -0,0 +1,24 @@ +! 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 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek <jakub@redhat.com>. +! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>. + +subroutine bar + real :: dummy + dummy = 1 +end subroutine bar diff --git a/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp b/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp new file mode 100644 index 0000000..fa41b80 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame.exp @@ -0,0 +1,37 @@ +# 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 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. + +set testfile "dynamic-other-frame" +set srcfile1 ${testfile}.f90 +set srcfile2 ${testfile}-stub.f90 +set objfile2 ${objdir}/${subdir}/${testfile}-stub.o +set executable ${testfile} +set binfile ${objdir}/${subdir}/${executable} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${objfile2}" object {f90}] != "" + || [gdb_compile "${srcdir}/${subdir}/${srcfile1} ${objfile2}" "${binfile}" executable {debug f90}] != "" } { + untested "Couldn't compile ${srcfile1} or ${srcfile2}" + return -1 +} + +clean_restart ${executable} + +if ![runto bar_] then { + perror "couldn't run to bar_" + continue +} + +gdb_test "bt" {foo \(string='hello'.*} diff --git a/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90 b/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90 new file mode 100644 index 0000000..2bc637d --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic-other-frame.f90 @@ -0,0 +1,36 @@ +! 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 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek <jakub@redhat.com>. +! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>. + +subroutine foo (string) + interface + subroutine bar + end subroutine + end interface + character string*(*) + call bar ! stop-here +end subroutine foo +program test + interface + subroutine foo (string) + character string*(*) + end subroutine + end interface + call foo ('hello') +end diff --git a/gdb/testsuite/gdb.fortran/dynamic.exp b/gdb/testsuite/gdb.fortran/dynamic.exp new file mode 100644 index 0000000..e79e94a --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.exp @@ -0,0 +1,152 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>. + +# This file is part of the gdb testsuite. It contains tests for dynamically +# allocated Fortran arrays. +# It depends on the GCC dynamic Fortran arrays DWARF support: +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22244 + +set testfile "dynamic" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f90 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" + +set test "output varx" +gdb_test_multiple $test $test { + -re "^output varx\r\n\[() ,6789.\]*$gdb_prompt $" { + pass $test + } +} + +gdb_breakpoint [gdb_get_line_number "varv-associated"] +gdb_continue_to_breakpoint "varv-associated" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 6" "p varx(3, 7, 19) with varv associated" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 6" "p varv(3, 7, 19) associated" +# Intel Fortran Compiler 10.1.008 uses -1 there, GCC uses 1. +gdb_test "p l" "\\$\[0-9\]* = (\\.TRUE\\.|4294967295)" "p l if varv associated" +gdb_test "ptype varx" "type = real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)" "ptype varx with varv associated" +# Intel Fortran Compiler 10.1.008 uses the pointer type. +gdb_test "ptype varv" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(6,5:15,17:28\\)\\)?" "ptype varv associated" + +gdb_breakpoint [gdb_get_line_number "varv-filled"] +gdb_continue_to_breakpoint "varv-filled" +gdb_test "p varx(3, 7, 19)" "\\$\[0-9\]* = 10" "p varx(3, 7, 19) with varv filled" +gdb_test "p varv(3, 7, 19)" "\\$\[0-9\]* = 10" "p varv(3, 7, 19) filled" + +gdb_breakpoint [gdb_get_line_number "varv-deassociated"] +gdb_continue_to_breakpoint "varv-deassociated" +# The latter one is for the Intel Fortran Compiler 10.1.008 pointer type. +gdb_test "p varv" "\\$\[0-9\]* = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "p varv deassociated" +gdb_test "ptype varv" "type = (<(object|the array) is not associated>|.*(Cannot access it|Unable to access the object) because the object is not associated.)" "ptype varv deassociated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varv deassociated" +gdb_test "p varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." +gdb_test "ptype varv(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not associated\\." + +gdb_breakpoint [gdb_get_line_number "varx-deallocated"] +gdb_continue_to_breakpoint "varx-deallocated" +gdb_test "p varx" "\\$\[0-9\]* = <(object|the array) is not allocated>" "p varx deallocated" +gdb_test "ptype varx" "type = <(object|the array) is not allocated>" "ptype varx deallocated" +gdb_test "p l" "\\$\[0-9\]* = \\.FALSE\\." "p l if varx deallocated" +gdb_test "p varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "p varx(1,5,17) deallocated" +gdb_test "ptype varx(1,5,17)" "(Cannot access it|Unable to access the object) because the (object|array) is not allocated\\." "ptype varx(1,5,17) deallocated" + +gdb_breakpoint [gdb_get_line_number "vary-passed"] +gdb_continue_to_breakpoint "vary-passed" +# $1 = (( ( 1, 1, 1, 1, 1, 1) ( 1, 1, 1, 1, 1, 1) --- , 1) ) ( ( 1, 1, ...) ...) ...) +gdb_test "p vary" "\\$\[0-9\]* = \\(\[()1, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "vary-filled"] +gdb_continue_to_breakpoint "vary-filled" +gdb_test "ptype vary" "type = real(\\(kind=4\\)|\\*4) \\(10,10\\)" +gdb_test "p vary(1, 1)" "\\$\[0-9\]* = 8" +gdb_test "p vary(2, 2)" "\\$\[0-9\]* = 9" +gdb_test "p vary(1, 3)" "\\$\[0-9\]* = 10" +# $1 = (( ( 3, 3, 3, 3, 3, 3) ( 3, 3, 3, 3, 3, 3) --- , 3) ) ( ( 3, 3, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\(\[()3, .\]*\\)" + +gdb_breakpoint [gdb_get_line_number "varw-almostfilled"] +gdb_continue_to_breakpoint "varw-almostfilled" +gdb_test "ptype varw" "type = real(\\(kind=4\\)|\\*4) \\(5,4,3\\)" +gdb_test "p varw(3,1,1)=1" "\\$\[0-9\]* = 1" +# $1 = (( ( 6, 5, 1, 5, 5, 5) ( 5, 5, 5, 5, 5, 5) --- , 5) ) ( ( 5, 5, ...) ...) ...) +gdb_test "p varw" "\\$\[0-9\]* = \\( *\\( *\\( *6, *5, *1,\[()5, .\]*\\)" "p varw filled" +# "up" works with GCC but other Fortran compilers may copy the values into the +# outer function only on the exit of the inner function. +# We need both variants as depending on the arch we optionally may still be +# executing the caller line or not after `finish'. +gdb_test "finish" ".*(call bar \\(y, x\\)|call foo \\(x, z\\(2:6, 4:7, 6:8\\)\\))" +gdb_test "p z(2,4,5)" "\\$\[0-9\]* = 3" +gdb_test "p z(2,4,6)" "\\$\[0-9\]* = 6" +gdb_test "p z(2,4,7)" "\\$\[0-9\]* = 5" +gdb_test "p z(4,4,6)" "\\$\[0-9\]* = 1" + +gdb_breakpoint [gdb_get_line_number "varz-almostfilled"] +gdb_continue_to_breakpoint "varz-almostfilled" +# GCC uses the pointer type here, Intel Fortran Compiler 10.1.008 does not. +gdb_test "ptype varz" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(\\*\\)\\)?" +# Intel Fortran Compiler 10.1.008 has a bug here - (2:11,7:7) +# as it produces DW_AT_lower_bound == DW_AT_upper_bound == 7. +gdb_test "ptype vart" "type = (PTR TO -> \\( )?real(\\(kind=4\\)|\\*4) \\(2:11,7:\\*\\)\\)?" +gdb_test "p varz" "\\$\[0-9\]* = \\(\\)" +gdb_test "p vart" "\\$\[0-9\]* = \\(\\)" +gdb_test "p varz(3)" "\\$\[0-9\]* = 4" +# maps to foo::vary(1,1) +gdb_test "p vart(2,7)" "\\$\[0-9\]* = 8" +# maps to foo::vary(2,2) +gdb_test "p vart(3,8)" "\\$\[0-9\]* = 9" +# maps to foo::vary(1,3) +gdb_test "p vart(2,9)" "\\$\[0-9\]* = 10" diff --git a/gdb/testsuite/gdb.fortran/dynamic.f90 b/gdb/testsuite/gdb.fortran/dynamic.f90 new file mode 100644 index 0000000..0f43564 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/dynamic.f90 @@ -0,0 +1,98 @@ +! Copyright 2007 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek <jakub@redhat.com>. +! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>. + +subroutine baz + real, target, allocatable :: varx (:, :, :) + real, pointer :: varv (:, :, :) + real, target :: varu (1, 2, 3) + logical :: l + allocate (varx (1:6, 5:15, 17:28)) ! varx-init + l = allocated (varx) + varx(:, :, :) = 6 ! varx-allocated + varx(1, 5, 17) = 7 + varx(2, 6, 18) = 8 + varx(6, 15, 28) = 9 + varv => varx ! varx-filled + l = associated (varv) + varv(3, 7, 19) = 10 ! varv-associated + varv => null () ! varv-filled + l = associated (varv) + deallocate (varx) ! varv-deassociated + l = allocated (varx) + varu(:, :, :) = 10 ! varx-deallocated + allocate (varv (1:6, 5:15, 17:28)) + l = associated (varv) + varv(:, :, :) = 6 + varv(1, 5, 17) = 7 + varv(2, 6, 18) = 8 + varv(6, 15, 28) = 9 + deallocate (varv) + l = associated (varv) + varv => varu + varv(1, 1, 1) = 6 + varv(1, 2, 3) = 7 + l = associated (varv) +end subroutine baz +subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + vary(:, :) = 4 ! vary-passed + vary(1, 1) = 8 + vary(2, 2) = 9 + vary(1, 3) = 10 + varw(:, :, :) = 5 ! vary-filled + varw(1, 1, 1) = 6 + varw(2, 2, 2) = 7 ! varw-almostfilled +end subroutine foo +subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + varz(1:3) = 4 + varz(2) = 5 ! varz-almostfilled + vart(2,7) = vart(2,7) +end subroutine bar +program test + interface + subroutine foo (vary, varw) + real :: vary (:, :) + real :: varw (:, :, :) + end subroutine + end interface + interface + subroutine bar (varz, vart) + real :: varz (*) + real :: vart (2:11, 7:*) + end subroutine + end interface + real :: x (10, 10), y (5), z(8, 8, 8) + x(:,:) = 1 + y(:) = 2 + z(:,:,:) = 3 + call baz + call foo (x, z(2:6, 4:7, 6:8)) + call bar (y, x) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (1, 3) .ne. 10) call abort + if (z (2, 4, 6) .ne. 6 .or. z (3, 5, 7) .ne. 7 .or. z (2, 4, 7) .ne. 5) call abort + if (any (y .ne. (/4, 5, 4, 2, 2/))) call abort + call foo (transpose (x), z) + if (x (1, 1) .ne. 8 .or. x (2, 2) .ne. 9 .or. x (1, 2) .ne. 4) call abort + if (x (3, 1) .ne. 10) call abort +end diff --git a/gdb/testsuite/gdb.fortran/string.exp b/gdb/testsuite/gdb.fortran/string.exp new file mode 100644 index 0000000..39de2c4 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.exp @@ -0,0 +1,59 @@ +# Copyright 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Jan Kratochvil <jan.kratochvil@redhat.com>. + +# This file is part of the gdb testsuite. It contains tests for Fortran +# strings with dynamic length. + +set testfile "string" +set srcfile ${testfile}.f90 +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f90 quiet}] != "" } { + untested "Couldn't compile ${srcfile}" + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto MAIN__] then { + perror "couldn't run to breakpoint MAIN__" + continue +} + +gdb_breakpoint [gdb_get_line_number "var-init"] +gdb_continue_to_breakpoint "var-init" +gdb_test "ptype c" "type = character(\\(kind=1\\)|\\*1)" +gdb_test "ptype d" "type = character(\\(kind=8\\)|\\*8)" +gdb_test "ptype e" "type = character(\\(kind=4\\)|\\*4)" +gdb_test "ptype f" "type = character(\\(kind=4\\)|\\*4) \\(7,8:10\\)" +gdb_test "ptype *e" "Attempt to take contents of a non-pointer value." +gdb_test "ptype *f" "type = character(\\(kind=4\\)|\\*4) \\(7\\)" +gdb_test "p c" "\\$\[0-9\]* = 'c'" +gdb_test "p d" "\\$\[0-9\]* = 'd '" +gdb_test "p e" "\\$\[0-9\]* = 'g '" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\( 'h ', 'h ', 'h ', 'h ', 'h ', 'h ', 'h '\\) \\)" +gdb_test "p *e" "Attempt to take contents of a non-pointer value." +gdb_test "p *f" "Attempt to take contents of a non-pointer value." + +gdb_breakpoint [gdb_get_line_number "var-finish"] +gdb_continue_to_breakpoint "var-finish" +gdb_test "p e" "\\$\[0-9\]* = 'e '" "p e re-set" +gdb_test "p f" "\\$\[0-9\]* = \\(\\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f2 ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\( 'f ', 'f ', 'f ', 'f ', 'f ', 'f ', 'f '\\) \\)" "p *f re-set" diff --git a/gdb/testsuite/gdb.fortran/string.f90 b/gdb/testsuite/gdb.fortran/string.f90 new file mode 100644 index 0000000..226dc5d --- /dev/null +++ b/gdb/testsuite/gdb.fortran/string.f90 @@ -0,0 +1,37 @@ +! Copyright 2008 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 2 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program; if not, write to the Free Software +! Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +! +! Ihis file is the Fortran source file for dynamic.exp. +! Original file written by Jakub Jelinek <jakub@redhat.com>. +! Modified for the GDB testcase by Jan Kratochvil <jan.kratochvil@redhat.com>. + +subroutine foo (e, f) + character (len=1) :: c + character (len=8) :: d + character (len=*) :: e + character (len=*) :: f (1:7, 8:10) + c = 'c' + d = 'd' + e = 'e' ! var-init + f = 'f' + f(1,9) = 'f2' + c = 'c' ! var-finish +end subroutine foo + character (len=4) :: g, h (1:7, 8:10) + g = 'g' + h = 'h' + call foo (g, h) +end diff --git a/gdb/testsuite/gdb.fortran/subrange.exp b/gdb/testsuite/gdb.fortran/subrange.exp new file mode 100644 index 0000000..c819e23 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/subrange.exp @@ -0,0 +1,60 @@ +# Copyright 2011 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if { [skip_fortran_tests] } { return -1 } + +set testfile "subrange" +set srcfile ${testfile}.f90 +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug f90}] } { + return -1 +} + +if ![runto MAIN__] { + perror "Couldn't run to MAIN__" + continue +} + +# Depending on the compiler version being used, the name of the 4-byte integer +# and real types can be printed differently. For instance, gfortran-4.1 uses +# "int4" whereas gfortran-4.3 uses "int(kind=4)". +set int4 "(int4|integer\\(kind=4\\))" + +gdb_breakpoint [gdb_get_line_number "break-static"] +gdb_continue_to_breakpoint "break-static" ".*break-static.*" + +foreach var {a alloc ptr} { + global pf_prefix + set old_prefix $pf_prefix + lappend pf_prefix "$var:" + + gdb_test "p $var (2, 2:3)" { = \(22, 32\)} + gdb_test "p $var (2:3, 3)" { = \(32, 33\)} + gdb_test "p $var (1, 2:)" { = \(21, 31\)} + gdb_test "p $var (2, :2)" { = \(12, 22\)} + gdb_test "p $var (3, 2:2)" { = \(23\)} + gdb_test "ptype $var (3, 2:2)" " = $int4 \\(2:2\\)" + gdb_test "p $var (4, :)" { = \(14, 24, 34\)} + gdb_test "p $var (:, :)" { = \(\( *11, 12, 13, 14\) \( *21, 22, 23, 24\) \( *31, 32, 33, 34\) *\)} + gdb_test "ptype $var (:, :)" " = $int4 \\(4,3\\)" + gdb_test "p $var (:)" "Wrong number of subscripts" + gdb_test "p $var (:, :, :)" "Wrong number of subscripts" + + set pf_prefix $old_prefix +} + +gdb_test_no_output {set $a=a} +delete_breakpoints +gdb_unload +gdb_test {p $a (3, 2:2)} { = \(23\)} diff --git a/gdb/testsuite/gdb.fortran/subrange.f90 b/gdb/testsuite/gdb.fortran/subrange.f90 new file mode 100644 index 0000000..4747ea9 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/subrange.f90 @@ -0,0 +1,28 @@ +! Copyright 2011 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program. If not, see <http://www.gnu.org/licenses/>. + +program test + integer, target :: a (4, 3) + integer, allocatable :: alloc (:, :) + integer, pointer :: ptr (:, :) + do 1 i = 1, 4 + do 1 j = 1, 3 + a (i, j) = j * 10 + i +1 continue + allocate (alloc (4, 3)) + alloc = a + ptr => a + write (*,*) a ! break-static +end diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp index 7645caf..f4f9c1f 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 cmdarg_vec 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.mi/mi2-var-stale-type.c b/gdb/testsuite/gdb.mi/mi2-var-stale-type.c new file mode 100644 index 0000000..ebced3c --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi2-var-stale-type.c @@ -0,0 +1,26 @@ +/* Copyright 2011 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int +main (int argc, char **argv) +{ + char vla[argc]; + + vla[0] = 0; /* break-here */ + + return 0; +} diff --git a/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp b/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp new file mode 100644 index 0000000..74a104e --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi2-var-stale-type.exp @@ -0,0 +1,57 @@ +# Copyright 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +load_lib mi-support.exp +set MIFLAGS "-i=mi2" + +gdb_exit +if [mi_gdb_start] { + continue +} + +set testfile "mi2-var-stale-type" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if {[build_executable ${testfile}.exp $testfile $srcfile] == -1} { + return -1 +} + +mi_delete_breakpoints +mi_gdb_reinitialize_dir $srcdir/$subdir +mi_gdb_load ${binfile} + +mi_gdb_test {-interpreter-exec console "maintenance set internal-error quit yes"} \ + {\^done} \ + "maintenance set internal-error quit yes" + +mi_gdb_test {-interpreter-exec console "maintenance set internal-error corefile yes"} \ + {\^done} \ + "maintenance set internal-error corefile yes" + +set line [gdb_get_line_number "break-here"] +set func "main" + +mi_gdb_test "-break-insert -t $srcfile:$line" \ + "\\^done,bkpt=\{number=\"\[0-9\]+\",type=\"breakpoint\",disp=\"del\",enabled=\"y\",addr=\"$hex\",func=\"$func\(\\\(.*\\\)\)?\",file=\".*\",line=\"$line\",times=\"0\",original-location=\".*\"\}" \ + "breakpoint at $func" + +if { [mi_run_cmd] < 0 } { + return -1 +} +mi_expect_stop "breakpoint-hit" $func ".*" ".*" "\[0-9\]+" { "" "disp=\"del\"" } "stop after initializing vla" + +mi_create_varobj "vla" "vla" "create local variable vla" + +mi_gdb_test "-var-update *" "\\^done,changelist=.*" "-var-update *" diff --git a/gdb/testsuite/gdb.opt/array-from-register-func.c b/gdb/testsuite/gdb.opt/array-from-register-func.c new file mode 100644 index 0000000..729f457 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register-func.c @@ -0,0 +1,22 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int +func (int *arr) +{ + return arr[0]; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.c b/gdb/testsuite/gdb.opt/array-from-register.c new file mode 100644 index 0000000..3090e7e --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.c @@ -0,0 +1,28 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +extern int func (int *arr); + +int +main (void) +{ + int arr[] = { 42 }; + + func (arr); + + return 0; +} diff --git a/gdb/testsuite/gdb.opt/array-from-register.exp b/gdb/testsuite/gdb.opt/array-from-register.exp new file mode 100644 index 0000000..f2de718 --- /dev/null +++ b/gdb/testsuite/gdb.opt/array-from-register.exp @@ -0,0 +1,33 @@ +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# This file is part of the gdb testsuite. + +if { [prepare_for_testing array-from-register.exp "array-from-register" \ + {array-from-register.c array-from-register-func.c} \ + {debug optimize=-O2}] } { + return -1 +} + +if ![runto func] then { + return -1 +} + +gdb_test "p arr" "\\$\[0-9\]+ = \\(int \\*\\) *0x\[0-9a-f\]+" + +# Seen regression: +# Address requested for identifier "arr" which is in register $rdi +gdb_test "p arr\[0\]" "\\$\[0-9\]+ = 42" diff --git a/gdb/testsuite/gdb.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 <http://www.gnu.org/licenses/>. + +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 <http://www.gnu.org/licenses/>. +} + +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-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp index 993e774..52dbd17 100644 --- a/gdb/testsuite/gdb.python/py-frame.exp +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -74,8 +74,6 @@ gdb_test "python print bframe == gdb.newest_frame()" True \ 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" @@ -90,3 +88,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 ()" "<gdb.Block object at 0x\[\[:xdigit:\]\]+>" "test Frame.block" diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index acfd89b..c77d9c2 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -358,6 +358,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. @@ -494,6 +503,7 @@ test_value_in_inferior test_inferior_function_call test_lazy_strings test_value_after_death +test_cast_regression # Test either C or C++ values. test_subscript_regression "${binfile}" "c" diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 4f2b7c9..0daef25 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -142,6 +142,11 @@ proc gdb_unload {} { send_gdb "y\n" exp_continue } + -re "A program is being debugged already..*Are you sure you want to change the file.*y or n. $"\ + { send_gdb "y\n" + verbose "\t\tUnloading symbols for program being debugged" + exp_continue + } -re "Discard symbol table from .*y or n.*$" { send_gdb "y\n" exp_continue diff --git a/gdb/testsuite/lib/pascal.exp b/gdb/testsuite/lib/pascal.exp index dd18d37..f973485 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/top.c b/gdb/top.c index 061ad48..d615cfc 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -352,6 +352,9 @@ prepare_execute_command (void) mark = value_mark (); cleanup = make_cleanup_value_free_to_mark (mark); +#if 0 + free_all_types (); +#endif /* With multiple threads running while the one we're examining is stopped, the dcache can get stale without us being able to detect diff --git a/gdb/typeprint.c b/gdb/typeprint.c index c25e705..498958a 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -35,6 +35,7 @@ #include "gdb_string.h" #include "exceptions.h" #include "valprint.h" +#include "dwarf2loc.h" #include <errno.h> extern void _initialize_typeprint (void); @@ -76,6 +77,9 @@ void type_print (struct type *type, const char *varstring, struct ui_file *stream, int show) { + if (show >= 0 && current_language->la_language != language_ada) + type = check_typedef (type); + LA_PRINT_TYPE (type, varstring, stream, show, 0); } @@ -114,7 +118,8 @@ whatis_exp (char *exp, int show) { struct expression *expr; struct value *val; - struct cleanup *old_chain = NULL; + /* Required at least for the object_address_set call. */ + struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); struct type *real_type = NULL; struct type *type; int full = 0; @@ -125,12 +130,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); @@ -158,8 +164,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/utils.c b/gdb/utils.c index 5566149..6e1aa34 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -27,6 +27,7 @@ #include "exceptions.h" #include "gdbthread.h" #include "fnmatch.h" +#include "gdb_bfd.h" #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> #endif /* HAVE_SYS_RESOURCE_H */ @@ -198,11 +199,11 @@ make_cleanup_dyn_string_delete (dyn_string_t arg) static void do_bfd_close_cleanup (void *arg) { - bfd_close (arg); + gdb_bfd_unref (arg); } struct cleanup * -make_cleanup_bfd_close (bfd *abfd) +make_cleanup_bfd_unref (bfd *abfd) { return make_cleanup (do_bfd_close_cleanup, abfd); } @@ -1738,6 +1739,36 @@ set_batch_flag_and_make_cleanup_restore_page_info (void) return back_to; } +/* Helper for make_cleanup_restore_page_info. */ + +static void +do_restore_selected_frame_cleanup (void *arg) +{ + struct frame_id *frame_idp = arg; + + select_frame (frame_find_by_id (*frame_idp)); + + xfree (frame_idp); +} + +/* Provide cleanup for restoring currently selected frame. Use frame_id for + the case the current frame becomes stale in the meantime. */ + +struct cleanup * +make_cleanup_restore_selected_frame (void) +{ + struct frame_id *frame_idp; + + /* get_selected_frame->get_current_frame would error otherwise. */ + if (!has_stack_frames ()) + return make_cleanup (null_cleanup, NULL); + + frame_idp = xmalloc (sizeof (*frame_idp)); + *frame_idp = get_frame_id (get_selected_frame (NULL)); + + return make_cleanup (do_restore_selected_frame_cleanup, frame_idp); +} + /* Set the screen size based on LINES_PER_PAGE and CHARS_PER_LINE. */ static void diff --git a/gdb/valarith.c b/gdb/valarith.c index 96d5411..37bd464 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -197,7 +197,10 @@ value_subscripted_rvalue (struct value *array, LONGEST index, int lowerbound) 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); + unsigned int elt_stride + = (TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (array_type)) == 0 + ? elt_size : TYPE_BYTE_STRIDE (TYPE_INDEX_TYPE (array_type))); + unsigned int elt_offs = elt_stride * longest_to_int (index - lowerbound); struct value *v; if (index < lowerbound || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type) @@ -297,6 +300,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 97d889b..6ae77b8 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -45,6 +45,7 @@ #include "objfiles.h" #include "symtab.h" #include "exceptions.h" +#include "dwarf2loc.h" extern int overload_debug; /* Local functions. */ @@ -919,6 +920,65 @@ value_one (struct type *type) 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 * @@ -981,7 +1041,8 @@ int value_fetch_lazy (struct value *val) { gdb_assert (value_lazy (val)); - allocate_value_contents (val); + if (VALUE_LVAL (val) != lval_memory) + allocate_value_contents (val); if (value_bitsize (val)) { /* To read a lazy bitfield, read the entire enclosing value. This @@ -1015,12 +1076,24 @@ 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) - read_value_memory (val, 0, value_stack (val), - addr, value_contents_all_raw (val), length); + if (object_address_get_data (value_type (val), &addr)) + { + struct type *type = value_enclosing_type (val); + int length = TYPE_LENGTH (check_typedef (type)); + + if (length) + { + /* Delay it after object_address_get_data above. */ + allocate_value_contents (val); + addr += value_offset (val); + read_value_memory (val, 0, value_stack (val), + addr, value_contents_all_raw (val), length); + } + } + /* Just to be sure it has been called. */ + allocate_value_contents (val); } else if (VALUE_LVAL (val) == lval_register) { @@ -1530,7 +1603,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); } @@ -1637,6 +1721,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 @@ -1646,8 +1731,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 @@ -3769,6 +3858,8 @@ value_slice (struct value *array, int lowbound, int length) TYPE_TARGET_TYPE (range_type), lowbound, lowbound + length - 1); + TYPE_BYTE_STRIDE (slice_range_type) = TYPE_BYTE_STRIDE (range_type); + if (TYPE_CODE (array_type) == TYPE_CODE_BITSTRING) { int i; diff --git a/gdb/valprint.c b/gdb/valprint.c index fc5942d..8333eb4 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -37,6 +37,7 @@ #include "gdb_obstack.h" #include "charset.h" #include <ctype.h> +#include "dwarf2loc.h" #include <errno.h> @@ -251,7 +252,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: @@ -1570,6 +1570,7 @@ val_print_array_elements (struct type *type, { 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 @@ -1578,9 +1579,33 @@ val_print_array_elements (struct type *type, /* Number of repetitions we have detected so far. */ unsigned int reps; LONGEST low_bound, high_bound; + 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); if (get_array_bounds (type, &low_bound, &high_bound)) @@ -1667,6 +1692,8 @@ val_print_array_elements (struct type *type, { 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 a6bb718..7b08d1f 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -42,6 +42,7 @@ #include <ctype.h> #include "tracepoint.h" #include "cp-abi.h" +#include "observer.h" /* Prototypes for exported functions. */ @@ -1437,12 +1438,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) { const struct lval_funcs *funcs = whole->location.computed.funcs; @@ -1450,6 +1454,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); } @@ -1583,6 +1593,31 @@ 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 (); +#if 0 + free_all_types (); +#endif +} /* Internal variables. These are variables within the debugger that hold values assigned by debugger commands. @@ -2118,6 +2153,38 @@ call_internal_function (struct gdbarch *gdbarch, return (*ifn->handler) (gdbarch, language, ifn->cookie, argc, argv); } +#if 0 +/* 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; + } + + 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])); + } +} +#endif + /* 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 @@ -2165,11 +2232,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); } @@ -2184,7 +2250,7 @@ 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_VALUE: @@ -3276,10 +3342,27 @@ readjust_indirect_value_type (struct value *value, struct type *enc_type, struct value * coerce_ref (struct value *arg) { - struct type *value_type_arg_tmp = check_typedef (value_type (arg)); + struct type *value_type_arg_tmp; struct value *retval; struct type *enc_type; + 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)); + retval = coerce_ref_if_computed (arg); if (retval) return retval; @@ -3386,4 +3469,10 @@ 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); + +#if 0 + observer_attach_mark_used (value_types_mark_used); +#endif } diff --git a/gdb/value.h b/gdb/value.h index d8b157f..f49e827 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -533,6 +533,10 @@ extern struct value *value_from_decfloat (struct type *type, const gdb_byte *decbytes); extern struct value *value_from_history_ref (char *, char **); +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); diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index f16588a..afef615 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -752,7 +752,7 @@ windows_make_so (const char *name, LPVOID load_addr) asection *text = NULL; CORE_ADDR text_vma; - abfd = bfd_openr (so->so_name, "pei-i386"); + abfd = gdb_bfd_openr (so->so_name, "pei-i386"); if (!abfd) return so; @@ -762,7 +762,7 @@ windows_make_so (const char *name, LPVOID load_addr) if (!text) { - bfd_close (abfd); + gdb_bfd_unref (abfd); return so; } @@ -773,7 +773,7 @@ windows_make_so (const char *name, LPVOID load_addr) load_addr + 0x1000); cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text); - bfd_close (abfd); + gdb_bfd_unref (abfd); } #endif
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor